布隆过滤器处理流程
布隆过滤器应用很广泛,比如垃圾邮件过滤,爬虫的url过滤,防止缓存击穿等等。下面就来说说布隆过滤器的一个完整流程,相信读者看到这里应该能明白布隆过滤器是怎样工作的。
第一步:开辟空间
开辟一个长度为m的位数组(或者称二进制向量),这个不同的语言有不同的实现方式,甚至你可以用文件来实现。
第二步:寻找hash函数
获取几个hash函数,前辈们已经发明了很多运行良好的hash函数,比如BKDRHash,JSHash,RSHash等等。这些hash函数我们直接获取就可以了。
第三步:写入数据
将所需要判断的内容经过这些hash函数计算,得到几个值,比如用3个hash函数,得到值分别是1000,2000,3000。之后设置m位数组的第1000,2000,3000位的值位二进制1。
第四步:判断
接下来就可以判断一个新的内容是不是在我们的集合中。判断的流程和写入的流程是一致的。
误判问题
布隆过滤器虽然很高效(写入和判断都是O(1),所需要的存储空间极小),但是缺点也非常明显,那就是会误判。当集合中的元素越来越多,二进制序列中的1的个数越来越多的时候,判断一个字符串是否在集合中就很容易误判,原本不在集合里面的字符串会被判断在集合里面。
数学推导
布隆过滤器原理十分简单,但是hash函数个数怎么去判断,误判率有多少?
假设二进制序列有m位,那么经过当一个字符串hash到某一位的概率为:
1m
也就是说当前位被反转为1的概率:
p(1)=1m
那么这一位没有被反转的概率为:
p(0)=1−1m
假设我们存入n各元素,使用k个hash函数,此时没有被翻转的概率为:
p(0)=(1−1m)nk
那什么情况下我们会误判呢,就是原本不应该被翻转的位,结果翻转了,也就是
p(误判)=1−(1−1m)nk
由于只有k个hash函数同时误判了,整体才会被误判,最后误判的概率为
p(误判)=(1−(1−1m)nk)k
要使得误判率最低,那么我们需要求误判与m、n、k之间的关系,现在假设m和n固定,我们计算一下k。可以首先看看这个式子:
(1−1m)nk
由于我们的m很大,通常情况下我们会用2^32来作为m的值。上面的式子中含有一个重要极限
limx→∞(1+1x)x=e
因此误判率的式子可以写成
p(误判)=(1−(e)−nk/m)k
接下来令t=−n/m,两边同时取对数,求导,得到:
p′1p=ln(1−etk)+klnet(−etk)1−etk
让p′=0,则等式后面的为0,最后整理出来的结果是