布隆过滤器的推导

bloom filter

intro

布隆过滤器是一种很有意思的数据结构,它的用途是检测某个元素是否在一个集合中。

首先,有一个数组,它的元素全部是0,然后共有m个坑:

我现在有一个集合S={x,y,z}S=\left\{ x,y,z \right\},对于每一个元素,通过3个hash函数,将其打到数组上,打中的位置设置为1。

比如xx,三次hash后,数组上就会有3个位置变为1(蓝色线条)。

至于hash函数,你可以认为它对xx做了处理,最后模上数组的长度得到一个下标。

注意,元素hash后可能打中同一个坑,这点不必惊奇。当m的值(也就是数组的长度)越来越大,这种情况的概率就会越来越小。

现在我来了一个ww,我要问:ww在不在SS中?

ww也三次hash一下:

  • 如果有打中0的情形,那么,它肯定不在SS中。
  • 如果打中的全部是1,那么它很有可能在SS中,也就是说,可以判定它在SS中,并带有一定的错误概率。

more general

我们的根本目的是减少错误概率。

现在考虑一般情况。

  • 数组的长度为mm
  • 集合为S={x1,x2,,xn}S=\left\{ x_1,x_2,\dots,x_n \right\},有nn个元素
  • hash函数有kk个:h1,h2,,hkh_1,h_2,\dots,h_k0hi(xj)<m(1ik,1jn)0 \le h_i(x_j)\lt m(1 \le i \le k, 1 \le j \le n),换句话说,每个元素xix_i的每次hash的下标都落在数组内
  • hash函数产生的下标是等概率均匀分布的,不是说全部挤在前面或者某一个地方

好,现在我们考虑一个元素(比如x1x_1)的插入(占坑)。

经过一次hash后,某个坑为1的概率为:

1m\frac{1}{m}

某个坑为0的概率是:

11m1-\frac{1}{m}

kk个hash函数过后,某个坑依旧为0的概率是:

(11m)k(1-\frac{1}{m})^k

因为limm+(11m)m=e\lim\limits_{m\to+\infty}(1-\frac{1}{m})^{-m}=e,所以

limm(11m)k=limm[(11m)m]km=ekm\lim\limits_{m\to\infty}(1-\frac{1}{m})^k=\lim\limits_{m\to\infty}[(1-\frac{1}{m})^{-m}]^{-\frac{k}m{}}=e^{-\frac{k}{m}}

我们会假设数组的长度mm无穷大,所以上面的式子是成立的。

完成了一个元素的插入后,现在我插入 nn个元素

nn个元素插入后,某个坑依旧为0的概率是:

enkme^{-\frac{nk}{m}}

于是某个坑为1的概率是:

1enkm1-e^{-\frac{nk}{m}}

现在我来了一个元素yyyy并不在SS

yy经过 kk个hash函数 后,全部打到了标记为1的坑,这个概率是:

(1enkm)k(1-e^{-\frac{nk}{m}})^k

好了,我们找到了最终的函数。

目标:使f=(1enkm)kf=(1-e^{-\frac{nk}{m}})^k

最小。


f=eln(1enkm)k=ekln(1enkm)f=e^{\ln(1-e^{-\frac{nk}{m}})^k}=e^{k\ln(1-e^{-\frac{nk}{m}})}


g=kln(1enkm)g=k\ln(1-e^{-\frac{nk}{m}})

问题转化为求gg的最小值。

gk=ln(1enkm)+(11enkm)(enkm)(nm)(k)\frac{\partial g}{\partial k}=\ln(1-e^{-\frac{nk}{m}})+(\frac{1}{1-e^{-\frac{nk}{m}}})(-e^{-\frac{nk}{m}})(-\frac{n}{m})(k)

gk=0\frac{\partial g}{\partial k}=0

同时,令

enkm=pe^{-\frac{nk}{m}}=p

于是

nm=lnpk\frac{n}{m}=\frac{\ln p}{-k}

那么

ln(1p)+(11p)(p)(lnpk)(k)=ln(1p)p1plnp=0\ln(1-p)+(\frac{1}{1-p})(p)(\frac{\ln p}{-k})(k)=\ln(1-p)-\frac{p}{1-p} \ln p=0

整理一下:

(1p)ln(1p)=plnp(1-p)\ln (1-p)=p \ln p

得到

p=12p=\frac{1}{2}

于是

k=mnln2k=\frac{m}{n} \ln 2

k,m,nk,m,n满足k=mnln2k=\frac{m}{n} \ln 2能够使得ff最小。

也就是说,如果数组长度比上元素个数为8的话(mn=8\frac{m}{n}=8),那么hash函数的个数最好有8ln25.458\ln 2 \approx5.45个(你可以取个整)。

这是一个令人愉快的结果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章