海量数据处理的解决方案

116 阅读6分钟

定义

所谓海量数据处理,就是基于海量数据的存储,处理,操作

海量就是数据量太大,所以导致要么是无法在短时间内迅速解决,要么是无法一次性装入内存

解决办法:

  1. 针对时间,可以采用巧妙的算法搭配合适的数据结构。
    1. Hash
    2. bitmap
    3. 数据库
    4. 倒排索引
    5. tire树
  1. 针对空间,化整为零:分而治之/hash映射,把规模大的化为规模小的,各个击破

共有六种方法模式

  1. 分而治之/hash映射+hash统计+堆/快速/归并排序
  2. 双层桶划分
  3. 布隆过滤器/bitmap
  4. tire树/数据库/倒排索引
  5. 外排序
  6. 分布式 MapReduce

分而治之

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

  1. 分而治之/hash映射:针对数据太大,内存受限,只能是:把大文件化成(取模映射)小文件,即16字方针:大而化小,各个击破,缩小规模,逐个解决
  2. hash统计:当大文件转化了小文件,那么我们便可以采用常规的hash_map(ip,value)来进行频率统计。
  3. 堆/快速排序:统计完了之后,便进行排序(可采取堆排序),得到次数最多的IP。

2、寻找热门查询,300万个字符串中寻找最热门的10个查询

可以一次性加载进内存,然后使用堆排序(优先队列)

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

  1. 分而治之/hash映射,分为5000个小文件,如果有的超过1M了,继续分
  2. 使用hash统计+堆排序,找出100个热门的词
  3. 然后将这个100个词写进源文件,或者保存在别的地方,然后使用归并排序
    1. 每次读几个文件,找出排名前100的,然后继续重复

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

方案1:

  1. 遍历文件,对10取模,得到新的10个文件(这样就保证了每个query都在一个文件中)
  2. 使用2G内存的机器对这几个文件进行统计,得到 (query,count)
  3. 使用归并排序

最后为什么能直接归并:是因为每个文件里面都是不同的query,所以可以进行排序

简而言之:每次都读取10个文件的一行,然后进行排序就行。

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

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

双层桶划分

双层桶划分—-其实本质上还是分而治之的思想,重在“分”的技巧上! 适用范围:第k大,中位数,不重复或重复的数字 基本原理及要点:因为元素范围很大,不能利用直接寻址表,所以通过多次划分,逐步确定范围,然后最后在一个可以接受的范围内进行。可以通过多次缩小,双层只是一个例子。

12、5亿个int找它们的中位数。

  1. 思路一:这个例子比上面那个更明显。首先我们将int划分为2^16个区域,然后读取数据统计落到各个区域里的数的个数,之后我们根据统计结果就可以判断中位数落到那个区域,同时知道这个区域中的第几大数刚好是中位数。然后第二次扫描我们只统计落在这个区域中的那些数就可以了。 实际上,如果不是int是int64,我们可以经过3次这样的划分即可降低到可以接受的程度。即可以先将int64分成2^24个区域,然后确定区域的第几大数,在将该区域分成2^20个子区域,然后确定是子区域的第几大数,然后子区域里的数的个数只有2^20,就可以直接利用direct addr table进行统计了。
  2. 思路二@绿色夹克衫:同样需要做两遍统计,如果数据存在硬盘上,就需要读取2次。 方法同基数排序有些像,开一个大小为65536的Int数组,第一遍读取,统计Int32的高16位的情况,也就是0-65535,都算作0,65536 – 131071都算作1。就相当于用该数除以65536。Int32 除以 65536的结果不会超过65536种情况,因此开一个长度为65536的数组计数就可以。每读取一个数,数组中对应的计数+1,考虑有负数的情况,需要将结果加32768后,记录在相应的数组内。 第一遍统计之后,遍历数组,逐个累加统计,看中位数处于哪个区间,比如处于区间k,那么0- k-1的区间里数字的数量sum应该<n/2(2.5亿)。而k+1 – 65535的计数和也<n/2,第二遍统计同上面的方法类似,但这次只统计处于区间k的情况,也就是说(x / 65536) + 32768 = k。统计只统计低16位的情况。并且利用刚才统计的sum,比如sum = 2.49亿,那么现在就是要在低16位里面找100万个数(2.5亿-2.49亿)。这次计数之后,再统计一下,看中位数所处的区间,最后将高位和低位组合一下就是结果了。

bitmap

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

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

Trie树/数据库/倒排索引