https://www.jianshu.com/p/3dcebd818e49

试题

海量日志数据,提取出某日访问百度次数最多的那个IP。

IP是32位的,所以IP数目是有限的,最多2个,可以直接考虑使用hash将ip存入内存,然后进行统计。

  • 将这一天的访问百度的IP地址提取出来,逐个写入到一个大文件
  • 采用映射方法,比如mod 1000,分成1000个小文件
  • 找出每个小文件中频率最大的IP
  • 在这1000个频率最大的ip中,找到频率最大的那个

搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。

假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

典型的Top K算法
给出的最终算法是:第一步、先对这批海量数据预处理,在O(N)的时间内用Hash表完成排序;然后,第二步、借助这个数据结构,找出Top K,时间复杂度为N‘logK。 即,借助堆结构,我们可以在log量级的时间内查找和调整/移动。因此,维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比所以,我们最终的时间复杂度是:O(N) + N’*O(logK),(N为1000万,N’为300万)。

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

  • 顺序读文件,对于每个词,取hash%5000分别存放到5000个小文件中,这样每个文件大概200k左右;如果有某些文件还是超过1M,继续往下分解,直到所有的文件都小于1M
  • 对于每个小文件,统计每个文件中出现的词以及相应的频率,取出最大的100个词(可以用含100个结点的最小堆),并将其存入一个文件,于是得到5000个这样的文件
  • 把这5000个文件进行归并

有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。

  • TOPK
  • 顺序读取十个文件,按照hash%10来写入到另外是个文件中,如果hash是随机的,那么每个新文件可能也是1G左右大小
  • 读取每个新文件,使用hashmap来统计query的频率,使用堆按照频率进行排序,输出到10个排好序的文件中。
  • 对着10个文件进行归并排序

给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?

方案一:

  • 遍历文件A,hash%1000成1000个文件
  • 遍历文件B,hash%1000成1000个文件
  • A和B对应的url,一定是a1-b1;a2-b2中,如果a和b中有一个相同的url,则其位于a的第几个小文件一定位于b的第几个小文件
  • 依次比较每对两两对应的小文件
    • 将ai文件的内容放入set中,然后读取bi的内容,如果bi中的内容已经在堆中,则是重复文件

方案二:
布隆过滤器。
4G内存大概可以表示340亿bit。
将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。

在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。

  • 采用两比特的位图
    • 2-Bitmap,每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义
    • 然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。


  • 或者划分小文件,重复的数字一定会分到一个文件中,只要在小文件中找出不重复的数,合并起来就是所有不重复的数。

腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

  • 方法1:申请512M的内存,一个bit位代表一个unsigned int值。读入40亿个数,设置相应的bit位,读入要查询的数,查看相应bit位是否为1,为1表示存在,为0表示不存在。
  • 方法2:
    • 把40亿个数中的每一个用32位的二进制来表示假设这40亿个数开始放在一个文件中。
    • 然后将这40亿个数分成两类:
      • 最高位为0
      • 最高位为1
      • 并将这两类分别写入到两个文件中,其中一个文件中数的个数<=20亿,而另一个>=20亿(这相当于折半了);与要查找的数的最高位比较并接着进入相应的文件再查找
    • 再然后把这个文件为又分成两类: 1.次最高位为0 2.次最高位为1
      •  并将这两类分别写入到两个文件中,其中一个文件中数的个数<=10亿,而另一个>=10亿(这相当于折半了); 与要查找的数的次最高位比较并接着进入相应的文件再查找。 ……. 以此类推,就可以找到了,而且时间复杂度为O(logn),方案2完。

怎么在海量数据中找出重复次数最多的一个?

先做hash,然后求模映射为小文件,求出每个小文件中重复次数最多的一个,并记录重复次数。然后找出上一步求出的数据中重复次数最多的一个就是所求(具体参考前面的题)。

上千万或上亿数据(有重复),统计其中出现次数最多的前N个数据。

上千万或上亿的数据,现在的机器的内存应该能存下。所以考虑采用hash_map/搜索二叉树/红黑树等来进行统计次数。然后就是取出前N个出现次数最多的数据了,可以用第2题提到的堆机制完成。

一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。

这题是考虑时间效率。用trie树统计每个词出现的次数,时间复杂度是O(n×le)(le表示单词的平准长度)。然后是找出出现最频繁的前10个词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n×lg10)。所以总的时间复杂度,是O(n×le)与O(n×lg10)中较大的哪一个。

十个海量数据处理方法大总结

布隆过滤器

适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集
原理:位数组+k个独立的hash函数
将hash函数对应的值的位数组置1,查找时如果发现所有hash函数对应位都是1说明存在,很明显这个过程并不保证查找的结果是100%正确的。同时也不支持删除一个已经插入的关键字,因为该关键字对应的位会牵动到其他的关键字。
一个简单的改进就是 counting Bloom filter,用一个counter数组代替位数组,就可以支持删除了。

  • Counting Bloom Filter 的出现,解决了上述问题,它将标准 Bloom Filter 位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的 k (k 为哈希函数个数)个 Counter 的值分别加 1,删除元素时给对应的 k 个 Counter 的值分别减 1。Counting Bloom Filter 通过多占用几倍的存储空间的代价, 给 Bloom Filter 增加了删除操作。


hashing

适用范围:快速查找,删除的基本数据结构,通常需要总数据量可以放入内存
原理:hash函数选择,针对字符串,整数,排列,具体相应的hash方法。
碰撞处理,一种是open hashing,也称为拉链法;另一种就是closed hashing,也称开地址法,opened addressing。

bit-map

适用范围:可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下

适用范围:海量数据前n大,并且n比较小,堆可以放入内存
  基本原理及要点:最大堆求前n小,最小堆求前n大。方法,比如求前n小,我们比较当前元素与最大堆里的最大元素,如果它小于最大元素,则应该替换那个最大元素。这样最后得到的n个元素就是最小的n个。适合大数据量,求前n小,n的大小比较小的情况,这样可以扫描一遍即可得到所有的前n元素,效率很高。
  扩展:双堆,一个最大堆与一个最小堆结合,可以用来维护中位数。