温故知新-布隆过滤器的基本原理
- Posted by 微博@Yangsc_o
- 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
摘要
本文是我在公司内部技术培训整理的一篇文章,介绍了布隆过滤器的基本原理,布隆过滤器有非常多的应用场景,在项目开发、大数据推荐系统都有应用。
基本概念
布隆过滤器(Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出。它由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。
- 优点是空间效率和查询时间都远远超过一般的算法;
- 缺点是有一定的误识别率(假正例False positives,即Bloom Filter报告某一元素存在于某集合中,但是实际上该元素并不在集合中)和删除困难,但是没有识别错误的情形(即假反例False negatives,如果某个元素确实没有在该集合中,那么Bloom Filter 是不会报告该元素存在于集合中的,所以不会漏报);
基本原理
如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。但是随着集合中元素的增加,需要的存储空间越来越大,检索速度也越来越慢。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit Array)中的一个点。只要看看这个点是不是1就知道可以集合中有没有它了。这就是布隆过滤器的基本思想。
Hash面临的问题就是冲突。假设 Hash 函数是良好的,如果位阵列长度为 m 个点,如果想将冲突率降低到例如 1%, 这个散列表就只能容纳 m/100 个元素。解决方法也简单,就是使用多个 Hash,如果它们有一个说元素不在集合中,那肯定就不在。如果它们都说在,虽然也有一定可能性它们在说谎,不过直觉上判断这种事情的概率是比较低的。
布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。
直观理解,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。优:布隆过滤器在空间和时间方面都有巨大的优势,存储空间和插入/查询时间都是常数;布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势;缺:误算率(False Positive)是其中之一。随着存入的元素数量增加,误算率随之增加;很难从布隆过滤器中删除元素;
算法描述
- k个hash函数,每个函数可以把key散列成为1个整数;
- 初始化时,需要一个长度为m比特的数组,每个比特位初始化为0;
- 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1;
- 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位;
- 若其中任一位不为1,则此元素比不在集合中(因为如果在,则在add时已经把对应的k个bits位置为1);
- 同理所有的比特位都是1,认为在集合中;
误判概率的证明和计算
p 错误概率,m 为bit大小 ,n为需要判断的数据量,k为每次需要取bit位的次数)
假设布隆过滤器中的hash function满足假设:若m为bit数,每个元素都等概率地hash到m个位置中的任何一个,与其它元素被hash到哪个位置无关,则对某一特定bit位在一个元素由某特定hash function插入时没有被置位为1的概率为:
则 k 个hash function中 没有一个对其置位 的概率为:
如果插入了n个元素,但都未将其置位 的概率为:
则此位 被置位的概率为:
现在考虑query阶段,若对应某个待query元素的k bits全部置位为1,则可判定其在集合中。因此将某元素误判的概率为:
由于
,并且
当m很大时趋近于0,所以
现在计算对于给定的m和n,k为何值时可以使得误判率最低。设误判率为k的函数为:
设
, 则简化为
,两边取对数
两边对k求导
下面求最值
因此,即当
时误判率最低, (k的公式)此时误判率为:
设计和应用布隆过滤器的方法
- 首先要先由用户决定要add的元素数n和希望的误差率P(fpp)。这也是一个设计完整的布隆过滤器需要用户输入的仅有的两个参数,之后的所有参数将由系统计算,并由此建立布隆过滤器。
- 系统计算需要的内存大小M bits:
- 再由m,n得到hash function的个数 k:
- add n个元素至布隆过滤器中,再进行query。根据公式,当k最优时:
- 因此可验证当P=1%时,存储每个元素需要9.6 bits:
-
而每当想将误判率降低为原来的1/10,则存储每个元素需要增加4.8 bits:
-
9.6 bits/element不仅包含了被置为1的k位,还把包含了没有被置为1的一些位数。6.72bits 才是每个元素对应的为1的bit位数。
-
从而使得P(error)最小时:
-
此概率为某bit位在插入n个元素后未被置位的概率。因此,想保持错误率低,布隆过滤器的空间使用率需为50%。
典型应用场景
- 黑名单:比如邮件黑名单过滤器,判断邮件地址是否在黑名单中;
- 网络爬虫:判断某个URL是否已经被爬取过;
- K-V系统快速判断某个key是否存在:典型的例子有Hbase,Hbase的每个Region中都包含一个BloomFilter,用于在查询时快速判断某个key在该region中是否存在,如果不存在,直接返回,节省掉后续的查询。
- 搜索引擎中的海量网页去重;
- leveldb等数据库中快速判断元素是否存在,可以显著减少磁盘访问;
参考阅读
https://www.cnblogs.com/umpjls/p/7319954.html
https://blog.csdn.net/likaiwalkman/article/details/54310757