最后更新时间 2021-10-05.
布隆过滤器 (Bloom Filter) 是 1970 年由布隆提出的。它可以检索一个元素是否存在于集合中。它的优点是空间效率高,查询时间极快,缺点是有一定的误判率,而且删除困难。
编程中,经常会有判断一个元素是否存在一个集合中:
其中,最直接的办法是,将集合所有元素存储起来,判断时与集合中的元素比较即可。
一般来说会使用哈希表来存储集合,速度快效率高,可以在 O(1) 的时间复杂度返回结果。但是哈希表本身由于负载因子的存在,不可能用满,也就是会有空间浪费的问题,对于网络爬虫来说,可能会处理几十亿的 URL 链接集合,哈希表占据的内存大小是非常可观的。
布隆过滤器,实际上是由一个很长的 bit 向量和一系列的随机映射函数构成的。
它的原理是,当集合新增元素时,通过 K 个哈希函数将该元素映射为多个哈希值,并对每个生成的哈希值对应的 bit 位置为 1。
举个例子,针对 张三
使用 3 个哈希函数,生成了 3 个哈希值 1、5、7,设置对应的 bit 位后如下图所示:
^-------------------------------^ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | --------------------------------- | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | v-------------------------------v
同样,也对 李四
使用 3 个哈希函数,生成了 3 个哈希值 2、3、7:
^-------------------------------^ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | --------------------------------- | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | v-------------------------------v
要判断 钱五
是不是在集合里,计算哈希值 5、6、7,显然不在。
特别注意的是,对张三、李四、钱五都生成了相同的哈希值 7,所以布隆过滤器是会误判的。
以检测一个可疑电子邮件地址是否存在黑名单为例:
布隆过滤器绝对不会漏掉任何一个存在黑名单的电子邮箱地址,但它可能将不在黑名单中的电子邮箱误判。补救方法是建立一个白名单,将可能误判的电子邮箱地址保存起来。
引用维基百科的解释:
一般情况下不能从布隆过滤器中删除元素。
我们很容易想到把位数组变成整数数组,每插入一个元素相应的计数器加 1,这样删除元素时将计数器减掉就可以了。
然而要保证安全地删除元素并非如此简单。
首先我们必须保证删除的元素的确在布隆过滤器里面。
这一点单凭这个过滤器是无法保证的。
另外计数器回绕也会造成问题。
False positives 概率推导:https://www.cnblogs.com/liyulong1982/p/6013002.html
关于如何选择哈希函数个数和布隆过滤器长度,有一个公式,可以根据业务情况,在误断率和内存空间权衡:
m = - (n * ln p) / (ln 2) ^ 2, k = m * ln * 2 / n
其中,k 为哈希函数个数,m 为布隆过滤器长度,n 为插入的元素个数,p 为误断率。
网上有个 Golang 版,有时间的话写个 PHP 版,不过 PHP 处理二进制真心不爽……
文章来源于本人博客,发布于 2018-06-02,原文链接:https://imlht.com/archives/150/
Copyright © 2023 leiyu.cn. All Rights Reserved. 磊宇云计算 版权所有 许可证编号:B1-20233142/B2-20230630 山东磊宇云计算有限公司 鲁ICP备2020045424号
磊宇云计算致力于以最 “绿色节能” 的方式,让每一位上云的客户成为全球绿色节能和降低碳排放的贡献者