参考原文:http://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html
在线JS演示
以及 《数学之美》
布隆过滤器 (Bloom Filter)是由Burton Howard Bloom于1970年提出,它是一种space efficient的概率型数据结构,用于判断一个元素是否在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的网址判重模块中等等经常被用到。哈希表也能用于判断元素是否在集合中,但是布隆过滤器只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,false positive rate(误报率)越大,但是false negative (漏报)是不可能的。
理论很明了,但要知道所谓的误报率这个概念,即俗称的 “假阳性”,把不应该识别的个体识别为了黑名单。以及了解误报率如何估算,如何解决。
一、误报率的计算
假设有m个bit作为bit array,每个元素会用k个随机函数进行随机,当已有n个元素时,下一个元素的误报率计算
- 1.对于bit array的某一个位置来说,当第一个元素来时,第一个随机函数后置位1的概率为1/m
因此,置为0的概率为 1-1/m
所以,当k个随机函数结束时,为0的概率为
-
2.插入n个元素后
该位置仍然为0的概率为
为1的概率为
-
3.此时来了第n+1个元素,这个元素通过k个随机函数分布后,全为1的概率为
通过数学变化,化简为
二、如何设计布隆过滤器
需要考虑的m,n,k3个参数,一般n是固定的,是和你业务实际相关的数据
如果你很懒,可以参考误报率的表格,可以满足大部分需要
计算解析
2.1、我们首先先考虑当n,m确定的时候,K应该如何取值
懒得打公式,就找了个计算过程,重点是,对每个步骤进行注释
- 1、为什么最值的时候,直接求右边为0,这是典型的倒推,正确的方式是,因为f(x)是不为0的,先去求f(x)的求导单数有几个点为0,是最后求出来导数为0的点只有1个,才能得出最值的结果,一开始不过得到一个局部的最值罢了
-
2.xlnx=(1-x)ln(1-x)是怎么一下子得到 x=1-x的?
因为x属于(0,1)先画图
可以看到为0的点只有1个,为x=1/2,这算是用数值法
xlnx并不是个单调函数,并不能很容易得出相等只有1/2一个点的,当然同过求导,计算2个局部最值,然后分段单调性等证明也是可以的,数值法只是因为比较方便
2.2、知道k后,计算p,m,n的关系
将K带入,很容易得到
此时可以看到,当false positive的概率P确定时,m和n其实是线性关系,而当n业务确定时,m和p是对数关系
2.3、举例子,简单计算下bloom filter的效率
假设有1亿个人邮箱地址,一条记录8个byte,负载因子为0.75
10^8 * 8/0.75=0.8 GB/0.75=1.06G
而Bloom Filter为当我们接受万分之一的误判率时,
-(10^8)*ln(1/10000) / ((ln2)^2) /8 大概需要 0.23G
如何解决误报
布隆过滤器,本质上是一个概率匹配的模型,他的特性就是肯定不会漏报,但有几率误报,通俗的将"有杀错,没放过"
一般用于邮箱等黑名单时,一般情况下都是黑名单远远小于正常邮箱,但黑名单对也有上亿的量,因此是对黑名单进行布隆。对于误杀的,再通过白名单解决。
结合自身的业务特点,你有上亿的商品,但你为了防止有人用虚假的商品号对你进行攻击,即可以反过来使用布隆过滤器,将有效的放在布隆过滤器,只要正常的都可以过来,但是不正常的攻击,只有很小的概率能过来,一般我们控制在万分之五以下是很容易的。当然,当数量少时,直接用哈希表即可。毕竟布隆过滤器只需要哈希表的1/8或1/4的空间复杂度,仍然是同一量级的