海量数据处理问题
常见的方法有Hash法,位图法,Bloom-filter法、数据库优化法、倒排索引法、外排序法、Trie树、堆、双层桶法以及MapReduce法。
分而治之/hash映射+hash统计+堆/快速/归并排序(先映射,然后统计,最后排序)
双层桶排序(求第K大,中位数,不重复或重复的数字):通过多次划分,逐步确定范围,最后在一个可以接受的范围内进行
Bloom filter(集合求交集、数据判重)/BitMap
Trie树/数据库/倒排索引
外排序
分布式处理之Hadoop/MapReduce
TopK问题(先映射,然后统计,最后排序)
题目1:假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),请你统计最热门的10个查询串,要求使用的内存不能超过1G。
解法:
3百万*255B=0.75G <1G 可以将所有串放在内存中进行
Hashmap统计:先对数据预处理,维护一个key为query串,value为该query串出现次数的hashmap,若该query串在map中,那么将该query串的计数加一即可,若该query串不在map中,那么加入该query串,并将value设为1
堆排序:维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比。
题目2:有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
解法:
(1G/16B):(1M/16B)=2000 可取5000
分而治之/hash映射:顺序读文件中,对于每个词x,取hash(x)%5000,然后按照该值存到5000个小文件(记为x0,x1,...x4999)中。这样每个文件大概是200k左右。如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M。
Hashmap统计:对每个小文件,采用trie树/hash_map等统计每个文件中出现的词以及相应的频率。
堆排序/归并排序:取出出现频率最大的100个词(可以用含100个结点的最小堆)后,再把100个词及相应的频率存入文件,这样又得到了5000个文件。最后就是把这5000个文件进行归并(类似于归并排序)的过程了。
题目3:提取某日访问网站次数最多的那个IP
解法:
分而治之/hash映射:首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有个2^32个IP。同样可以采用映射的方法,比如%1000,把整个大文件映射为1000个小文件
Hashmap统计:采用hash_map对那1000个文件中的所有IP进行频率统计
堆/快速排序:进行排序(可采取堆排序),得到次数最多的IP。
题目4:海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。
解法:
如果每个数据元素只出现一次,而且只出现在某一台机器中,那么可以采取以下步骤统计出现次数TOP10的数据元素:
堆排序::在每台电脑上求出TOP10,可以采用包含10个元素的堆完成,求出每台电脑上的TOP10后,然后把这100台电脑上的TOP10组合起来,共1000个数据,再利用上面类似的方法求出TOP10就可以了。
如果同一个元素重复出现在不同的电脑中:遍历一遍所有数据,重新hash取摸,如此使得同一个元素只出现在单独的一台电脑中,然后采用上面所说的方法,统计每台电脑中各个元素的出现次数找出TOP10,继而组合100台电脑上的TOP10,找出最终的TOP10
排序问题
映射之后排序
题目1:有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。
解法:
hash映射:顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件(记为a0,a1,..a9)中。这样新生成的文件每个的大小大约也1G(假设hash函数是随机的)。
hash_map统计:找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数。
堆/快速/归并排序:利用快速/堆/归并排序按照出现次数进行排序,将排序好的query和对应的query_cout输出到文件中,这样得到了10个排好序的文件(记为b0,b1,...b10)。最后,对这10个文件进行归并排序(内排序与外排序相结合)。
外排序
题目1:如何给10^7个数据量的磁盘文件排序
解法:
(1) 内存排序
由于要求的可用内存为1MB,那么每次可以在内存中对250K的数据进行排序,然后将有序的数写入硬盘。
那么10M的数据需要循环40次,最终产生40个有序的文件。
(2) 归并排序
将每个文件最开始的数读入(由于有序,所以为该文件最小数),存放在一个大小为40的first_data数组中;
选择first_data数组中最小的数min_data,及其对应的文件索引index;
将first_data数组中最小的数写入文件result,然后更新数组first_data(根据index读取该文件下一个数代替min_data);
判断是否所有数据都读取完毕,否则返回 (2)。