一 简介
布隆过滤器也即Bloom Filter算法 一个布隆过滤器由以下几个部分组成
(1)n个位组成的数组,每个位初始值都是0
(2)一系列哈希哈书h1,h2,h3.....hk组成的集合。每个哈希函数将“键”值映射到上述n个桶(对应于位数组的n个位)中。
(3)m个键值组成的集合S。
布隆过滤器的目的是让所有键值在S中的流元素通过,而阻挡大部分键值不再S中的流元素,哈希函数hi及S中的键值K,将每个hi(K)对应的位置为1.
当键值为K的流元素到达时,检查所有的h1(k), h2(k) ,h3(k)....hk(k)对应的位是否全部都是1.如果是则允许该元素通过,如果有一位或多位为0,则认为K不可能在S中。则拒绝该元素通过。
如果元素键值在S中出现一定会通过布隆过滤器,但是元素键值不在S中的元素也有可能会通过。我们需要了解如何基于位数组长度n,集合S的元素数目m及哈希函数的数目k来计算false positive概率。
二 Bloom Filter算法思路
1.我们有一个长度为n的比特数组,开始的时候将这个比特数组里所有的元素都初始化为0
00000000000000000000
上面的比特数组n为20
2. 然后选取k个哈希函数,这k个哈希函数产生的结果的值的范围在0到n-1之间(对于上面的比特数组,即0到19) 。对每个要添加进集合的对象进行哈希运算,然后将哈希计算结果作为数组的索引,将索引位置的比特位设置为 1(不管该比特位原先为0还是为1)。
比如我们选取三个哈希函数,对于对象A哈希值为0,5,7。那么比特数组就为:
10000101000000000000
对象B的值为2,8,13,那么添加B后的比特数组为:
10100101100001000000
对象C为0,4,7(对象C的第一个哈希函数的值与对象A的相同了,没关系我们还是设置为1就可以了):
10101101100001000000
现在我们的Bloom Filter里已经有3个元素了。现在我们要判断某元素X是否在该集合中。就相当于我们要实现一个contains方法。
对元素X采用相同的三个哈希函数哈希,然后以这三个哈希值为索引去比特数组里找。如果三个索引位置的比特位都为1我们就认为该元素在集合中,否则不是。
三 Bloom Filter算法应用
比如假设我们有一个缓存服务器集群,集群里的不同的服务器承担的缓存也不尽相同。如果一个用户请求过来了,我们如何能快速的判断出用户请求的这个url在集群里哪台服务器上呢?因为每台服务器上缓存的url对应的页面非常庞大,我们全部弄到内存里代价也很高。我们就可以在每台服务器上放一个Bloom Filter,里面添加的都是本服务器上有缓存的那些url。这样即使Bloom Filter误报了,那就是把一个url发到了一个并不持有该url对应的缓存的服务器上,结果就是缓存未命中,缓存服务器只需要将该url打到后端的上游服务器就好了。
3.1 计算false positive概率:
假设有y只飞镖和x个靶位。每只飞镖投中每个靶位的机会均等,飞镖投出去之后预计有多少个靶位至少会被投中一次?
**给定飞镖不能投中给定靶位的概率是(x-1)/x
**y只飞镖全部都没有投中给定靶位的概率是((x-1)/x)^y,该式可以写成(1-1/x)^x*(y/x)
高等数学中有证明:a很小时有 (1-a)^1/a=1/e. 其中e 为自然对数。
假定集合有S个元素,位数组容量为n,而哈希函数有k个。靶位数目为x=n,飞镖数目为 y=km。投完所有飞镖之后某位任然为0的概率为
e^(-km/n)
我们的目标是使得0的比率很大,否则非S中的元素至少有一次哈希为0的概率就太小,从而出现太多的假正例。
假正例也即一个位为1的概率(1-e^(-km/n))的k次方,即(1-e^(-km/n))^k