海量数据top K问题

  在很多的大规模数据处理中,经常会遇到的一类问题就是在海量数据中找出出现频率最高的前K个数,或者从海量数据中找出最大的前K个数,这种问题被称为top K问题,例如在搜索引擎中,统计搜索搜索最热门的10个查询词或者统计下载率中下载最多的东西。
  对于top K类 问题一般有两种方法:
  1.分治+Trie树
  2.hash+小顶堆
  举例说明:有1亿个浮点数,如何找出其中最大的10000个?
  第一种方法是将数据全部排序,然后在排序后的集合中进行查找,最快的排序算法时间复杂度为O(nlogn),例如快速排序。而在32位机器上,每个float类型占4B,1亿个浮点数就要占用400M的存储空间。而且我们只找出最大的1万个数并不是全部排序所以我们会做很多无用功。
  第二种方法局部淘汰法,该方法与排序方法类似,用一个容器保存前1万个树,然后将剩余的所有数字一一和容器内最小的数字比较,如果后续元素比容器内的最小元素大就删掉容器内的最小元素,并将该元素插入容器,最后遍历玩这1亿个数,得到最终结果。
  第三种分治法:将1亿个数据分成100份,每份100万个数据,找出每份数据中最大的1万个,最后在剩下的100 X 10000个数据。也就是100万个数据里面找前1万。在这里使用快速排序,将数据分成两堆如果大的那堆个数N大于10000个,继续对大堆快速排序依次。意思就是在100万个数据中找出倒数第1万个就行了。
  第四种hash法:如果1一个数中有很多重复的数,先通过hash法,把这1亿个数字去重复,这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间,然后通过分治法或最小堆法找到10000个数。
  第五种最小堆:先读入前10000个数来创建大小为10000的小顶堆,建堆的时间复杂度为O(mlogm),然后遍历后续数字,并与堆顶数字(最小)进行比较,如果比堆顶的数字大,替换堆顶元素调整堆为小顶堆。这个过程直到1亿个数全部遍历完。然后按照中序遍历的方式输出当前堆中的所有1万个数字。该算法的时间复杂度为O(nmlogm),空间复杂度是常数。
  

对于这五种设计适应于不同的情景。

1。单机+单核+足够大内存
例如如果需要查找10亿个查询词中出现频率最高的10个,考虑查询词占8byte,则10亿个查询词所需内存大约是10^9 X 8Byte=8GB内存对于这种可以用HashMap找每个词的出现频率。
2。单机+多核+足够大内存
由于这里是多核我们可以利用多线程的优势,利用hash方法把数据划分成N个partition,每个partition交给一个线程处理,在每个线程中使用HashMap找,但是会出现数据倾斜,每个线程的速度不同,最终处理速度取决于慢得线程。所以我们可以把数据划分成c x n个partition,每个线程处理完当前partition后主动取下一个partition。
3,单机+单核+受限内存。
对于这里我们可以把文件切割成一个一个小文件,如采用hash的取余法切割成M个小文件如果小文件扔大于内存大小,继续采用hash方法。
4。多机+受限内存
可以使用数据分发

你可能感兴趣的:(海量数据)