1. 使用哈希
适用场景:需要处理的数据中,相同的数据可以分配到同样的机器/文件进行处理。
技巧总结:相同的数会哈希到同一个位置上
这类题目一般面试官给的描述都不是很清晰,需要自己去问条件、然后给出方案。
回答思路是:问给我多少机器、需要的时效怎么样?然后用哈希的方式拆解海量数据到多台机器上,单台机器的性能还不够的话,单台机器上再拆成小文件进行处理。
例题1. 有100亿个url,统计其中重复出现的url出现的次数
对url进行哈希,会让相同url分到同一台机器上,然后用该机器上的一个哈希表来统计这台机器上分配到的url的词频。如果这台机器内存不够,就把分过来的url继续哈希,存到本地多个文件里。
例题2. 40亿个int数1G内存,求词频最高的是哪个
哈希到40个文件里,每个文件里有1亿个数,用1G内存建立哈希表统计每个文件里词频最大的数,最后计算40个最大的词频得出总的结果。
2. 使用堆
适用场景:需要统计top N,一般用小根堆或大根堆。
技巧总结:小根堆/大根堆能时刻保持top N个。单台机器用堆做top N,多台机器上继续用堆做机器之间的top N,变长2维、多维堆。
例题3. 有100亿个url,统计其中词频top100
技巧总结:二维大根堆
在例题1.思路的基础上,对每个小文件进行top100的统计,然后合并多个小文件选出他们之间的top100。也可以在每个小文件上维护一个100大小的大根堆,在每台机器上维护一个以小文件大根堆堆顶元素为元素的大根堆,这就相当于做了个二维大根堆,继续往上垒出一个全局大根堆,这种算法比前面那个要快。
例题4. 一个存满int数的10T文件,用1G内存排序后输出到另一10T文件中
技巧总结:小根堆、门槛变量
轮询原始10T的文件,用一个小根堆(小根堆的大小n跟1G内存相关)存放轮询到的前n大的数及其词频,小根堆堆顶存放的是前n大的数中最小的那个,相当于一个“门槛”,小于该门槛的数都进入不了小根堆,这样,小根堆里存的就是整个文件前n大的数了。轮询完一遍文件后,小根堆输出到目标文件中,此时按堆的方式出堆,就是排好序的。
小根堆腾空后,用一个变量记录这次的最小值,下一轮遍历所有大于等于这个最小值的都不要进入堆,这样下一轮统计到小根堆里的就是前n~2n大的数了,继续输出到目标文件。重复以上过程,直到进入小根堆的数小于n。
3.使用布隆过滤器
适用场景:黑名单过滤器,允许有一定的误判率。
技巧总结:布隆过滤器要结合bitmap来使用,可以有效减少内存占用
布隆过滤器的误判是指:不在过滤器中的一定是不在的,在过滤器中的不一定不在。它会多杀,但不会漏杀。
这类题目,要问面试官是否允许有误判率,如果可以,就用布隆过滤器,否则不能使用。
布隆过滤器的大小m(m个bit位)、误判率p、哈希函数个数k(必须是相互独立的哈希哈数)、面相要过滤的数量n,这几个量之间是有计算公式的:
例题5. 有个网页爬虫工具,要爬大概100亿个url,如何确保不重复爬取url
爬过的url加入到布隆过滤器里,可以确保爬过的一定不会被再爬,但未爬过的个别url可能会漏爬。