布隆过滤器
1、什么是Bloom Filter
布隆过滤器:利用位数组很简洁地表示一个集合,并判断一个元素是否属于这个集合。使用布隆过滤器,存在第一类出错(Falsepositive),但是不会存在第二类错误(Falsenegative),因此,布隆过滤器拥有100%的召回率。
- 也就是说,布隆过滤器能够
准确判断一个元素不在集合内
,但只能判断一个元素可能在集合内
。 - BloomFilter不适合“零错误”的应用场合。在能够容忍低错误的应用场合下,BloomFilter通过极少的错误换取了存储空间的极大节省。
我们可以向布隆过滤器里添加元素,但是不能从中移除元素(普通布隆过滤器,增强的布隆过滤器是可以移除元素的)。随着布隆过滤器中元素的增加,犯第一类错误的可能性也随之增大。
扩展:
统计学里的两类错误:
- 第一类错误是正确的null假设被错误地拒绝(假正);
- 第二类错误是错误的null假设被接受(假负)。
- 在这里null假设(null hypothesis)为:待检测元素不存在于集合中。
Bloom Filter是一个节省空间的概率型数据结构,被用来测试一个元素是否存在于集合中。
- “
元素实际不存在于集合中但判定为存在“的这类错误(False positive)在该数据结构上可能发生
(概率很低可以人为控制), - 但是“
实际存在于集合中但是判定为不存在”的错误(False Negative)不可能发生
。
2、使用原理
Bloom Filter是一种空间效率很高的随机数据结构,它的原理是,
- 1、当一个元素被加入集合时,通过
K个Hash函数
将这个元素映射成一个位阵列(Bit array)中的K个点,把它们置为1。 - 2、检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:
- 3、如果这些点有任何一个0,则被检索元素一定不在;如果都是1,则被检索元素很可能在。这就是布隆过滤器的基本思想。
具体过程如下
1、初始状态时,Bloom Filter是一个包含m位的位数组,每一位都置为0。
2、为了表达S={x1, x2,…,xn}这样一个n个元素的集合,Bloom Filter使用k个相互独立的哈希函数(Hash Function),它们分别将集合中的每个元素映射到{1,…,m}的范围中。对任意一个元素x,第i个哈希函数映射的位置hi(x)就会被置为1(1≤i≤k)。注意,如果一个位置多次被置为1,那么只有第一次会起作用,后面几次将没有任何效果。在下图中,k=3,且有两个哈希函数选中同一个位置(从左边数第五位,即第二个“1“处)。
- 一个元素通过K个不同的hash函数随机散列到bit数组的K个位置上,K必须远小于M。K和M的大小由错误率(false positiverate)决定。
3、在判断y是否属于这个集合时,我们对y应用k次哈希函数,如果所有hi(y)的位置都是1(1≤i≤k),那么我们就认为y是集合中的元素,否则就认为y不是集合中的元素。下图中y1就不是集合中的元素(因为y1有一处指向了“0”位)
。y2或者属于这个集合,或者刚好是一个false positive。
注意:
如果M中的k个位置全为1,则有两种情形。
- 情形一:这个元素在这个集合中;
- 情形二: 曾经有元素插入的时候将这k个位置的值置为1了(第一类错误产生的原因FalsePositive)。
- 简单的布隆过滤器无法区分这两种情况,在增强版中解决了这个问题。
3、主要参数估计
3.1、错误率估计
布隆过滤器判断一个元素是否属于它表示的集合时会存在一定的错误率(false positiverate),接下来就估计错误率的大小。
在估计误差前,我们假设kn<m(k哈希函数的个数,n集合中元素的个数,mbit数组的长度)
且哈希函数之间时相互独立
的,哈希函数散列的bit数组M中的位置时完全随机
的。
1、一个长度为m的bit数组,元素在插入时经过一次哈希散列后bit数组的某个位置的值没有被置为1的概率为
2、经过k个哈希函数散列后,还未被置为1的概率为
3、如果插入n个元素后,该位置还未被置为1的概率为
4、所以被置为1的概率为
5、现在判断一个元素是否在结合中,经过k个函数散列到k个bit数组的不同位置。所有这些位置的值为1的概率——误判率。
这里使用了极限
这种计算方法不严格,因为前面假设哈希函数和散列后值的分布是相互独立的。但是,这个假设随着m和n的增大误判率更接近真实的误判率。
3.2、最优的哈希函数个数
既然布隆过滤器将集合映射到位数组中,那么选多少个hash函数才是错误率最低的情况。这里有两个互斥的理由:
- 如果哈希函数的个数多,那么在对一个不属于集合的元素进行查询时得到0的概率就大;
- 但另一方面,如果哈希函数的个数少,那么位数组中的0就多。为了得到最优的哈希函数个数,我们需要根据上一小节中的错误率公式进行计算。
误判率:
两边取自然对数:
只要g取最小值,p就能取到最小值,带入上面的p公式,我们可以将g改写为
根据对称性法则可以很容易看出当p = 1/2
,也就是k = ln2· (m/n)
时,g取得最小值。在这种情况下,最小错误率f
等于(1/2)k≈ (0.6185)m/n
。另外,注意到p是位数组中某一位仍是0的概率,所以p = 1/2对应着位数组中0和1各一半
。换句话说,要想保持错误率低,最好让位数组有一半还空着。
需要强调的一点是,p = 1/2
时错误率最小这个结果并不依赖于近似值p和f。同样对于f’ = exp(k ln(1 − (1 − 1/m)^kn))
,g’ = k ln(1 − (1 − 1/m)^kn)
,p’ = (1 − 1/m)^kn
,我们可以将g’写成
同样根据对称性法则可以得到当p’ = 1/2时,g’取得最小值。
3.3、位数组的大小
在给定n(集合中元素的个数)和错误率(最优函数个数k的的错误率)的情况下,位数组M的大小计算,在最优k的情况下.
化简为
这意味着在错误率为p的情况下,布隆过滤器的长度为m才能容纳n个元素(以上计算基于n,m->∞
)。
4、问题实例
给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。如果是三个乃至n个文件呢 ?
根据这个问题我们来计算下内存的占用,4G=2^32
大概是40亿*8
大概是340亿,n=50亿,如果按出错率0.01算需要的大概是650亿个bit。 现在可用的是340亿,相差并不多,这样可能会使出错率上升些。另外如果这些urlip是一一对应的,就可以转换成ip,则大大简单了。
参考
1、https://blog.csdn.net/v_july_v/article/details/6685894
2、https://blog.csdn.net/To_be_to_thought/article/details/84887435