前言
本文需要有下面4种算法和数据结构的基础:map+reduce哈希分流、Bitmap、Bloom过滤器、桶排序。本文对该4种数据结构只是综合简单的概述,主要是讲解面试场中出现的情况,如若想深入学习该4种数据结构,还需自行深究。
备用知识
海量数据处理,对于内存使用的预估是不可避免的:
(1)10亿个int需要多少G?
10亿整数=40亿Byte=4G
(2)10亿bit需要多少G?
10亿bit=1G/8=0.125G=125MB
可见:同样10亿个int和bit,采用bit进行存储,消耗的内存减小了8倍!
方法论
在面试场和实际的应用开发中,对于海量数据处理,主要有下面3种情况:
方法 | 适用场景 | 案例 |
---|---|---|
map+reduce哈希分流 | 内存限制:2G(以G为单位)、和排序相关 | 词频统计、TopK问题 |
Bitmap | 内存限制是M(对于内存要求严格)、有范围的数据 | 有范围的数据[max-min+1]:IP地址,电话号码,32位无符号整数、"无重复&&有范围"的数排序 |
Bloom过滤器 | 存在误差、无范围的数据 | URL、网页黑名单 |
桶排序 |
map哈希分流+reduce
(1)先介绍哈希函数的4个特性
1. 具有无限的input域
2. input值相同,output值一定相同
3. input值不同,output值有可能相同,也有可能不同
4. 最重要的性质:很多不同的输入,均匀的分布在S域上 (评价哈希函数的优劣)
(2)介绍map-reduce过程
{
map阶段:(哈希函数分流到计算节点)将大任务划分成小任务——>如何划分?假设有海量数据,每个数据都有id,有M台机器或计算节点,则将每个数据 (id) 经过一个哈希函数,计算出key,再key%M,得到的值必然分配到每个机器或计算节点上。
说明:经过优秀的哈希函数后,数据在每个机器或计算节点上是均匀分布的
reduce阶段:子任务在多个机器上并发处理,处理完之后,合并结果
}
经典案例1:海量数据的词频统计
map阶段:哈希函数将单词分流到多个计算节点上,形成多个子任务(相同单词的必然会分配到同一台机器上)
reduce阶段:多个计算节点进行词频统计,在进行合并
经典案例2:20亿个全是32位整数的大文件,找出现次数最多的数,但是内存限制只有2G
分析:由于是词频统计,由于BitMap和Bloom不能进行统计,因此只能使用Map+Reduce解决
解法1:哈希表
key/value分别占4Byte,加起来占8Byte,20亿个数占用20亿*8Byte=16G>2G
解法2:哈希分流
map阶段:哈希函数分流
reduce阶段:统计次数,并合并
经典案例3:某个公司每天搜索词汇是海量的(百亿),求搜索最热100词(要求:说出排序方法)
答案:map+reduce+小根堆
map:数据哈希分流到不同的机器
词频统计:每台机器使用"小根堆"寻找Top100
reduce:不同机器的Top100中寻找最终的Top100,使用小根堆或外排序
其他案例:
1、现有海量日志数据,要提取出某日访问百度次数最多的那个IP(内存限制512MB)
2、在包含20亿个全是32位整数的大文件中,找出出现次数最多的数(内存限制只有2G)
hash分流+堆排序
1. 对一个整数用hash函数获得一个hash值,再进行100取模,保存到某一个文件中,然后再对单个小文件进行处理
2. 使用大根堆的方式保存单个小文件的所有整数,所以单个小文件,就形成了大根堆的top是最大的数据
3. 然后再用整合大根堆对这个100个小文件进行整合。
4. 每个小文件的大根堆的堆顶元素,放进整合大根堆(100个小文件就放进了100个元素)
5. 然后对整合大根堆,弹出堆顶元素,则这个元素则是最多出现的次数。
6. 弹出的堆顶元素知道他是属于那个小文件的,再将这个小文件的大根堆堆顶再放到整合大根堆中。
7. 依次类推6,7步骤。直到整合大根堆弹出100个元素就知道TOP100。
Bitmap位图
原理:
1、Bitmap是用一个bit位,它的值只能是0和1,表示存在和不存在
2、一个bit位置可以存放任意大小的数据:Bitmap的整体大小由max-min决定
{
优点:
bitmap的大小与数据大小无关;1bit就可以表示某个元素存在或不存在
与bloom相比,bitmap可以用于排序
缺点:
Bitmap的大小与max-min成正比:即使数据量很小,但是数据域大,也需要开辟过多的bit位置
只能对不重复的数据进行排序;不能记录一个数据出现了多少次
}
经典案例1:请对10亿个IPV4的ip地址进行排序,每个ip只会出现一次 牢记(IPV4的ip数量≈42亿)
解题思路:
将ip通过简单的规则转换成无符号整数
将无符号整数排序
排序后,再转回ip地址即可
内存分析:
解法1:10亿个ip—>10亿个无符号整数—>40亿Byte === 4G内存
解法2:
10亿个ip—>bitmap—>10亿bit—>1G/8=0.125G=125M
经典案例2:(腾讯)32位无符号整数的范围是0~4294967295,现在有一个正好包含40亿个无符号整数的文件,如何快速判断这个数是否在那40亿个数当中?
要求:最多使用10M的内存,只要找到一个每出现的数即可,该如何找?
分析:由于是"必然",就是一定的意思,要求无差错
解法1:哈希表
解法2:BitMap——10亿bit占125M–>40亿bit占500M > 10M
因此可以先将数据0~4294967295按照区间分成64块
遍历64次——>
每次遍历只将某个区间[a,b]内的数放入,用Bitmap记录出现的数
其他案例:
1-请对10亿个IPV4的ip地址进行排序,每个ip只会出现一次
2-如何快速判断某个数是否在0~4294967295中
3-电话号码和IP地址排序问题(特点:不重复,内存限制)
4-在2.5亿个整数中找出不重复的整数,(内存不足以容纳这2.5亿个整数)
=====================================
Bloom过滤器
允许失误率
空间要求严格
工作原理:input—>K个哈希函数—>S域涂黑—>检查data
[1]input怎么进入Bloom过滤器:先将所有的input集合中的数,都映射到S域
(1)准备K个相互独立的哈希函数,S域(1~M)
(2)将所有的input都经过K个哈希函数,计算出哈希码之后,都mod M,就会在S域上有对应的落脚点,将其描黑(即设为1)
[2]怎么查询data是否在Bloom中:查询某个数data是否在input集合中?
如果data经过步骤[1]过程后,data对应的S域中的数
(1)有一个没有被涂黑,那么data一定不在input集合中
(2)全部被涂黑,那么data可能在input集合中,极小可能不在input集合中
其他案例:
1、判断某个URL是否在海量的URL中
2、网页黑名单 垃圾邮件过滤 爬虫地址判重
桶排序
经典案例:将10亿个年龄,按照年龄顺序排序
解题思路:
由于每个人具有的年龄是可以重复的,因此不能用BitMap对每个人按照年龄排序!
答案:
桶排序