Mass data processing - (top K problem)

CSDN-mass data processing blog

 

Find the largest 10,000 numbers among 1 billion numbers (top K problem)

Another workaround:

Distributed processing mapreduce

Basic principles and key points:

 

Hand over data to different machines for processing, data division, and result reduction

 

First build a heap with 10,000 numbers, and then add the remaining elements at a time. If it is greater than the number at the top of the heap (the smallest of 10,000), replace this number with the top of the heap, and adjust the structure to make it still a minimum heap. In this way, after traversing , the number of 10000 in the heap is the maximum 10000 required. The time complexity of heap building is O(mlogm), and the time complexity of the algorithm is O(nmlogm) (n is 1 billion, m is 10000).

        Optimized method: All 1 billion data can be stored in groups, for example, in 1000 files. In this way, you can find the largest 10,000 numbers in the 10^6 data of each file, and combine them together to find the final result.

        The above is simply the content mentioned in the interview, and the following is a summary of the questions in this area:

 

top K problem

        In large-scale data processing, a class of problems often encountered: finding the top k numbers with the best frequency in massive data, or finding the largest top k numbers from massive data, such problems are usually It is called the top K problem . For example, in a search engine, the 10 most popular search terms are counted; the top 10 most downloaded songs are counted in the song library, and so on.

        For top K problems, a better solution is usually divide and conquer + Trie tree/hash + small top heap (that is, the minimum heap mentioned above), that is, first decompose the data set into multiple small data sets according to the Hash method, and then use Trie tree and Hash count the query word frequency in each small data set, and then use the small top heap to find the top K with the highest frequency in each data set, and finally find the final top K in all top K.

eg: There are 100 million floating-point numbers, if you find the largest 10,000 in the period?

        The easiest way to think of is to sort all the data , and then search in the sorted set. The time complexity of the fastest sorting algorithm is generally O(nlogn), such as quicksort. However, on a 32-bit machine, each float type occupies 4 bytes, and 100 million floating-point numbers will occupy 400MB of storage space. For some computers with less than 400M of available memory, it is obviously impossible to store all data at one time. Read into memory for sorting. In fact, even if the memory can meet the requirements (my machine memory is 8GB), this method is not efficient, because the purpose of the problem is to find the largest 10,000 numbers, but sorting is to sort all the elements, do A lot of useless work .

 

        The second method is the partial elimination method , which is similar to the sorting method. A container is used to store the first 10,000 numbers, and then all the remaining numbers are compared with the smallest number in the container, if all subsequent elements are smaller than the container. The number of 10,000 in the container is still small, so the number of 10,000 in the container is the maximum number of 10,000. If a subsequent element is larger than the minimum number in the container, delete the minimum element in the container, insert the element into the container, and finally traverse the 100 million numbers , and the number stored in the result container is the final result. The time complexity at this time is O(n+m^2), where m is the size of the container, which is 10000.

 

        第三种方法是分治法将1亿个数据分成100份,每份100万个数据,找到每份数据中最大的10000个,最后在剩下的100*10000个数据里面找出最大的10000个。如果100万数据选择足够理想,那么可以过滤掉1亿数据里面99%的数据。100万个数据里面查找最大的10000个数据的方法如下:用快速排序的方法,将数据分为2堆,如果大的那堆个数N大于10000个,继续对大堆快速排序一次分成2堆,如果大的那堆个数N大于10000个,继续对大堆快速排序一次分成2堆,如果大堆个数N小于10000个,就在小的那堆里面快速排序一次,找第10000-n大的数字;递归以上过程,就可以找到第1w大的数。参考上面的找出第1w大数字,就可以类似的方法找到前10000大数字了。此种方法需要每次的内存空间为10^6*4=4MB,一共需要101次这样的比较。

 

        第四种方法是Hash法如果这1亿个书里面有很多重复的数,先通过Hash法,把这1亿个数字去重复,这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间,然后通过分治法或最小堆法查找最大的10000个数。

 

        第五种方法采用最小堆。首先读入前10000个数来创建大小为10000的最小堆,建堆的时间复杂度为O(mlogm)(m为数组的大小即为10000),然后遍历后续的数字,并于堆顶(最小)数字进行比较。如果比最小的数小,则继续读取后续数字;如果比堆顶数字大,则替换堆顶元素并重新调整堆为最小堆。整个过程直至1亿个数全部遍历完为止。然后按照中序遍历的方式输出当前堆中的所有10000个数字。该算法的时间复杂度为O(nmlogm),空间复杂度是10000(常数)。

 

实际运行:

        实际上,最优的解决方案应该是最符合实际设计需求的方案,在时间应用中,可能有足够大的内存,那么直接将数据扔到内存中一次性处理即可,也可能机器有多个核,这样可以采用多线程处理整个数据集。

       下面针对不容的应用场景,分析了适合相应应用场景的解决方案。

(1)单机+单核+足够大内存

        如果需要查找10亿个查询次(每个占8B)中出现频率最高的10个,考虑到每个查询词占8B,则10亿个查询次所需的内存大约是10^9 * 8B=8GB内存。如果有这么大内存,直接在内存中对查询次进行排序,顺序遍历找出10个出现频率最大的即可。这种方法简单快速,使用。然后,也可以先用HashMap求出每个词出现的频率,然后求出频率最大的10个词。

(2)单机+多核+足够大内存

        这时可以直接在内存总使用Hash方法将数据划分成n个partition,每个partition交给一个线程处理,线程的处理逻辑同(1)类似,最后一个线程将结果归并。

        该方法存在一个瓶颈会明显影响效率,即数据倾斜。每个线程的处理速度可能不同,快的线程需要等待慢的线程,最终的处理速度取决于慢的线程。而针对此问题,解决的方法是,将数据划分成c×n个partition(c>1),每个线程处理完当前partition后主动取下一个partition继续处理,知道所有数据处理完毕,最后由一个线程进行归并。

(3)单机+单核+受限内存

        这种情况下,需要将原数据文件切割成一个一个小文件,如次啊用hash(x)%M,将原文件中的数据切割成M小文件,如果小文件仍大于内存大小,继续采用Hash的方法对数据文件进行分割,知道每个小文件小于内存大小,这样每个文件可放到内存中处理。采用(1)的方法依次处理每个小文件。

(4)多机+受限内存

        这种情况,为了合理利用多台机器的资源,可将数据分发到多台机器上,每台机器采用(3)中的策略解决本地的数据。可采用hash+socket方法进行数据分发。

 

        从实际应用的角度考虑,(1)(2)(3)(4)方案并不可行,因为在大规模数据处理环境下,作业效率并不是首要考虑的问题,算法的扩展性和容错性才是首要考虑的。算法应该具有良好的扩展性,以便数据量进一步加大(随着业务的发展,数据量加大是必然的)时,在不修改算法框架的前提下,可达到近似的线性比;算法应该具有容错性,即当前某个文件处理失败后,能自动将其交给另外一个线程继续处理,而不是从头开始处理。

        top K问题很适合采用MapReduce框架解决,用户只需编写一个Map函数和两个Reduce 函数,然后提交到Hadoop(采用Mapchain和Reducechain)上即可解决该问题。具体而言,就是首先根据数据值或者把数据hash(MD5)后的值按照范围划分到不同的机器上,最好可以让数据划分后一次读入内存,这样不同的机器负责处理不同的数值范围,实际上就是Map。得到结果后,各个机器只需拿出各自出现次数最多的前N个数据,然后汇总,选出所有的数据中出现次数最多的前N个数据,这实际上就是Reduce过程。对于Map函数,采用Hash算法,将Hash值相同的数据交给同一个Reduce task;对于第一个Reduce函数,采用HashMap统计出每个词出现的频率,对于第二个Reduce 函数,统计所有Reduce task,输出数据中的top K即可。

        直接将数据均分到不同的机器上进行处理是无法得到正确的结果的。因为一个数据可能被均分到不同的机器上,而另一个则可能完全聚集到一个机器上,同时还可能存在具有相同数目的数据。

 

以下是一些经常被提及的该类问题。

(1)有10000000个记录,这些查询串的重复度比较高,如果除去重复后,不超过3000000个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。请统计最热门的10个查询串,要求使用的内存不能超过1GB。

(2)有10个文件,每个文件1GB,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。按照query的频度排序。

(3)有一个1GB大小的文件,里面的每一行是一个词,词的大小不超过16个字节,内存限制大小是1MB。返回频数最高的100个词。

(4)提取某日访问网站次数最多的那个IP。

(5)10亿个整数找出重复次数最多的100个整数。

(6)搜索的输入信息是一个字符串,统计300万条输入信息中最热门的前10条,每次输入的一个字符串为不超过255B,内存使用只有1GB。

(7)有1000万个身份证号以及他们对应的数据,身份证号可能重复,找出出现次数最多的身份证号。

 

重复问题

        在海量数据中查找出重复出现的元素或者去除重复出现的元素也是常考的问题。针对此类问题,一般可以通过位图法实现。例如,已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

        本题最好的解决方法是通过使用位图法来实现。8位整数可以表示的最大十进制数值为99999999。如果每个数字对应于位图中一个bit位,那么存储8位整数大约需要99MB。因为1B=8bit,所以99Mbit折合成内存为99/8=12.375MB的内存,即可以只用12.375MB的内存表示所有的8位数电话号码的内容。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326088687&siteId=291194637