周末,深圳,又是大雨。今天来聊海量数据。
海量数据,是BAT笔试面试中的常客,TMD也纷纷效仿,其余公司也紧随其后。在实际工作中,也确实会涉及到类似问题。
海量数据,从时间上讲,难以快速处理。从空间上讲,难以一次加载到内存。针对海量数据,我们需要对时间和空间进行预估,而不是一根筋蛮力处理。
海量数据处理的常见思路如下:
1. 哈希分治,重新分类
2. hash map, O(1)查找
3. hash map, 统计计数
4. bitmap, 节省空间
5. bloom filter, 节省空间
6. trie树,节省时间
7. 文件桶,化大为小
8. 堆,求出top K
9. 快速排序,局部求解
10. 外排序,多路归并
在很多场景下,要综合使用上述多种方法和工具。也可能会用到其它的一些奇技淫巧,比如异或,比如纯数学。
接下来,我们直接看海量数据相关的问题。
问题1
问题:有100亿个uint32元素,判断其中是否有相同元素。内存限制:1K
如果不够敏感,则会在这个问题上陷入死局。任何一个程序员都应该在3秒内知道一些常识,比如:
a. 一天有8万多秒
b. uint32的最大值接近43亿
所以,根据抽屉原理可知,100亿个uint32元素中,必然存在相同的元素。
问题2
问题:有40亿个uint32元素,判断其中是否有相同元素。内存限制:1.2G
40亿个uint32元素,无法直接加载到内存中,可以考虑使用2个bitmap, 总占用内存为1G. bitmap的知识请参考:
具体来说,就是创建两个bitmap,即bm1和bm2, 用它们对元素x进行标记,可以记录x的四种可能情况:
bm1[x] | bm2[x] | 含义 |
0 | 0 | x出现0次 |
0 | 1 | x出现1次 |
1 | 0 | x出现2次 |
1 | 1 | x出现多次 |
问题3
问题:有40亿个uint32元素,判断其中是否有相同元素。内存限制:0.6G
显然,2个bitmap需要内存是1G, 不符合要求。怎么办呢?可以使用一个bitmap. bitmap的知识请参考:
具体来说,就是把40亿个元素读到bitmap中做标记,并统计bitmap中的元素个数count,然后用count跟40亿进行比较,便可以判断是否存在相同元素。
问题4
问题:有40亿个uint32元素,试去重。内存限制0.6G
显然,直接读到bitmap中即可,直接实现去重,内存消耗512M. 关于bitmap的知识请参考:
问题5
问题:有40亿个不重复的uint32元素,试排序。内存限制0.6G
由于元素不重复,故可直接读到bitmap中,然后直接遍历,就实现了排序,内存消耗512M, bitmap的知识请参考:
问题6
问题:有40亿个uint32元素,试排序。内存限制0.6G
元素可能有重复值,故不适合用bitmap. 此时,可以考虑使用桶排序,桶是海量数据处理的天然利器,参考:
当然,如果对多路归并排序有所了解,也可以考虑多路归并排序。多路归并其实也用到了桶的思想,但每个桶之间,需要通过归并实现排序。显然,多路归并排序不如直接使用上述桶排序。
问题7
问题:有40亿个不重复的uint32元素,求top K. 内存限制0.6G
由于元素不重复,故可直接读到bitmap中,实际上就实现了排序,那么获取top K就易如反掌了。bitmap的知识请参考:
问题8
问题:有40亿个uint32元素,求top K. 内存限制0.6G
元素可能重复,故不适合直接使用bitmap来做。堆是非常适合这种情况的,参考如下:
问题9
问题:有40亿个不重复的uint32元素,求中位数。内存限制0.6G
由于元素不重复,故可以直接读到bitmap中,实际上就实现了排序,然后找中位数就易如反掌了,内存消耗512M, bitmap的知识请参考:
问题10
问题:有40亿个uint32元素,求中位数。内存限制0.6G
元素可能重复,故不适合直接使用bitmap, 此时可以考虑用桶,参考如下:
问题11
问题:有40亿个uint32元素,判断n是否存在于这40亿个元素中。内存限制0.6G
直接bitmap搞起,把40亿个元素读到bitmap中,然后判断bitmap[n]的值是否为1即可,内存消耗512M, bitmap的知识请参考:
问题12
问题:A文件有40亿个url, 判定给定url是否在其中,允许有一定的误判率。内存限制0.6G
Bloom Filter就是为这种场景而生的,直接参考:
问题13
问题:A文件有40亿个uint32元素, B文件有4万个uint32整数,求交集。内存限制0.6G
这个问题,直接用bitmap,直接参考:
问题14
问题:A文件有40亿个uint32元素, B文件有4万个uint32整数,求交集。内存限制10M
由于可用内存很小,故无法使用bitmap. 可以考虑哈希分治的思想,化大为小,直接看如下第15题的思路即可。
问题15
问题:A文件有40亿个url, B文件有4万个url,求交集。内存限制100M
显然,需要化大为小,可采用哈希分治的思想,直接参考:
问题16
问题:某文件有黑客攻击的海量来源IP, 求次数最多的IP.
这个问题,首先要计算出每个IP的次数,然后对次数求top K, 具体如下:
Step1: 通过哈希分治, 把相同的IP划分到相同的小文件桶中。
Step2: 使用hash map统计每个小文件桶中IP出现的次数,求出每个小文件桶中次数最多的IP.
Step3: 遍历每个小文件桶, 求出全局出现次数最多的IP.
问题17
问题:在某台服务器的100个文件中,记录着黑客访问的来源IP, 求次数最多的10个IP.
首先要使用哈希分治,将100个文件中的相同IP分配到相同的文件中,然后采用如上第16题类似的方法,求出访问次数的top 10.
问题18
问题:文件总共有1万行,每行一个单词,统计出现次数最多的10个单词。
总共才1万行,内存完全能容纳下所有数据,故可直接在内存中处理,用hash map来统计频次就行,然后对频次进行排序。
另外,可以用trie树来做,直接参考:
注意,trie树除了用于计数,还能用来查找、前缀匹配、去重和排序,用途大大的。