厦门大学数据库实验室-蔡珉星-Partition类和布隆过滤器

Download Report

Transcript 厦门大学数据库实验室-蔡珉星-Partition类和布隆过滤器

Partition类与布隆过滤器
报告人:蔡珉星
厦大数据库实验室
2014-08-02
目录
遇到的问题
Partitioner类
Semi-Join中的布隆过滤器
Part 1
Pa r t i t i o n 类
Partition类
 MapReduce中的Partition类:
在Map端输出时,需要对key进行分区,来决定输出数据传输到哪个reducer
上进行处理。
在提交MapReduce作业时,可以通过指定Partition类来实现分区。
默认的partitioner是HashPartitioner,通过哈希操作来决定分配到哪个reducer。
Partition类
 HashPartitioner:结果返回reducer的编号[0, 1, ... NumreducerTasks-1]
 为何要 key.hashCode() & Integer.MAX_VALUE:
若key为Text,其hashCode是通过Horner法则(对多项式求值的高效方法)计
算得出的一个int值,若Text太大,则可能int会溢出从而得到一个负值。
所以对hashCode和MAX_VALUE(0111111111111111)与运算,保证其值
为正数。
Partition类
 优化重分区算法:注意Map输出的key为组合键
Partition类
 优化重分区算法:
Partition是根据组合键中的Join key来分区的,而默认的hash partition是对整个键进行
分区的,所以需要自定义一个Partition类。
二次排序将会用整个组合键来进行排序。组合键包括一个标识源数据集(较大或较小)
的整数值,因此可以根据这个整数值来保证较小源数据集的值先于较大源数据的值被reducer
接收。
Partition类
 优化重分区算法:
 与Partition相关的还有次排序(上图蓝色圈起来的部分)
• setOutputKeyComparatorClass是key值的第二次比较,决定key的排序;
• setOutputValueGroupingComparator是指定group的划分。
PS: 0.20.0版本后API有变动: setSortComparatorClass、setGroupingComparatorClass
Partition类
 一般比较函数的实现:
• 一般具体排序算法无需用户实现,用户需实现比较函数来决定数据的大小序关系;
• 返回1, 0, -1来决定大小序关系;
• 再如PHP中的usort()用于实现用户的自定义排序函数:
usort($data, 'sortByLen') -> 使用函数sortByLen(a, b)来排序,返回1, 0, -1。
Part 2
Semi-Join中的布隆过滤器
背景知识 - 位图算法
 问题描述:给40亿个不重复的unsigned int的整数,没有排过序,然后再给一个
数,如果快速判断这个数是否在那40亿个数当中?
 分析: 如果将数据全部存入内存,再遍历判断,需要大约15G内存才能实现
(unsigned int为4字节)。
 位图算法: 利用2进制位表示是否存在。0表示不存在,1表示存在。
例如: 有{3,5,7,8,2},可以利用一个8位的二进制来表示该集合 11010110
因此,通过申请40亿位长的空间(不到512M)就可以表示这40亿的整数了。
 位图算法的实现:
Java、C++有BitSe类型,就可以直接定义一个bit数组来实现。
如果没有Bit类型,可以使用int数组,一个int可以表示32个数,通过位操作来
实现。
背景知识 - 位图算法
 位图算法更多应用:
• 给40亿个unsigned int的整数,如何判断这40亿个数中哪些数重复?
同理,可以申请512M的内存空间,然后读取40亿个整数,并且将相应的bit
位置1。如果是第一次读取某个数据,则在将该bit位置1之前,此bit位必定是0;
如果是第二次读取该数据,则可根据相应的bit位是否为1判断该数据是否重复。
• 给40亿个unsigned int的整数排序?
全部存到内存中可能放不下,可使用外部排序(归并排序)来实现,但实现复
杂、效率不高。更有效的方法--位图算法: 用位数组表示所有数据,然后从最高位
(或最低位)开始遍历,遇到为1的则输出相应的数据。
 位图算法的局限:
节省空间,但只能用于整数型的数据,并且需要知道最大范围。
布隆过滤器(Bloom Filter)
 问题描述:1亿个不重复的正整数(大致范围已知)中,是否存在某个数可以使用位
图来实现,若是1亿个邮件地址,如何确定某个邮件地址是否在这1亿个地址中?
 分析: 通常情况下是利用Hash表,但Hash表不可避免的会发生碰撞,且Hash表需
要较大的存储空间。
 布隆过滤器: 是一种数据结构,由Burton Howard Bloom在1970年提出的,它
结合了位图和Hash表两者的优点,位图的优点是节省空间,但是只能处理整型值
一类的问题,无法处理字符串一类的问题,而Hash表却恰巧解决了位图无法解决
的问题,然而Hash太浪费空间。针对这个问题,布隆提出了一种基于二进制向量
和一系列随机函数的数据结构-布隆过滤器。它的空间利用率和时间效率是很多算
法无法企及的。
布隆过滤器(Bloom Filter)
 布隆过滤器的原理:
布隆过滤器需要的是一个位数组和k个映射函数,在初始状态时,长度为m的
位数组array,其所有位都置为0。
布隆过滤器(Bloom Filter)
 布隆过滤器的原理:
对于有n个元素的集合S={s1,s2......sn},通过k个映射函数{f1,f2,......fk},将集
合S中的每个元素sj(1<=j<=n)映射为k个值{g1,g2......gk},然后再将位数组array
中相对应的array[g1],array[g2]......array[gk]置为1:
如果要查找某个元素item是否在S中,则通过映射函数{f1,f2.....fk}得到k个值
{g1,g2.....gk},然后再判断array[g1],array[g2]......array[gk]是否都为1,若全为1,
则item在S中,否则item不在S中。
布隆过滤器(Bloom Filter)
 布隆过滤器存在的问题:误判
集合中的若干个元素通过映射之后得到的数值恰巧同为g1,g2,.....gk,那么这
种情况下就会造成误判。布隆过滤器的误判率和这k个映射函数的设计有关。
另外布隆过滤器不允许删除元素。
 邮件实例分析: 假设一个邮件地址为8 bytes
• 使用hash存储,装填因子为0.5,则需要1*10^8*8/0.5 bytes = 1.6G
• 使用布隆过滤器,空间利用率为50%,k=8,则需要1*10^8*8/0.5 bits = 200MB
显然,布隆所需空间比哈希结构小得多。
PS: 误判率为p,位数组大小为m,集合数据个数为n,映射函数个数为k
这几个量存在一定的关系,通常是先设定一个误判率,然后去确定m和k。
(有兴趣可查阅更详细的介绍)
布隆过滤器(Bloom Filter)
 布隆过滤器的常见应用:
• 垃圾邮件地址过滤(前面分析的例子)
• 网页爬虫对重复URL的判别:若将url存入数据库中,当url数量很多时,效率低下,
可使用布隆过滤器来实现。
 适合的使用场景: 内存空间受限,用于节约空间
• 如Semi-Join
Semi-Join(半连接)
 半连接算法:
假设一个场景,需要连接两个很大的数据集,例如,用户日志和和用户数据。
任何一个数据集都不是足够小到可以缓存在map作业的内存中(这样就可以使用
广播连接算法)。
进一步考虑,如果在数据集的连接操作中,一个数据集中有的记录由于因为无
法连接到另一个数据集的记录,将会被移除。这样就不必将整个数据集放到内存中
了。
所以在这个例子中,在用户日志中的出现的用户仅仅是用户数据里,所有用户
当中的很小的一部分。因此可以从用户数据里只取出存在于用户日志中的那部分用
户的数据,这样就可以得到足够小、可以放在内存中的数据集了。
Semi-Join(半连接)

1.
2.
3.
半连接算法步骤:使用三个MapReduce Job来完成:
从日志文件中提取出用户名/用户标识,生成一个唯一用户名/用户标识的集合;
采用复制连接,过滤掉用户数据中,不存在日志文件中的用户数据;
同样使用复制连接,进行最后的数据连接。
问题:万一提取的用户集不够小,不能放入内存中,怎么办?
解决:使用布隆过滤器,节约内存空间。
Semi-Join(半连接)
 使用布隆过滤器的半连接算法:
将小表中的key保存到BloomFilter中,在map阶段过滤大表,可能有一些不
在小表中的记录没有过滤掉(误判,不过没关系,只是增加了少量网络I/O),但
是在小表中的记录一定不会过滤掉。
Ps: Hadoop早已支持布隆过滤器,调用相应的API即可。
遇到的问题
Thanks.
21