扩展:一种可扩容布隆过滤器设计
什么是布隆过滤器
这个问题网上一搜一大把,随便复制一段[维基百科](布隆过滤器 - 维基百科,自由的百科全书 (wikipedia.org))的解释:布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
在看了一段没什么意思的介绍后,来看看为什么它最大的特点:
布隆过滤器说这个对象不存在则一定不存在
布隆过滤器说这个对象不存在则一定不存在
布隆过滤器说这个对象不存在则一定不存在
布隆过滤器为什么能行
如图,我们将全集(“张三”、“李四”)输入布隆过滤器。布隆过滤器对每个元素计算多次哈希(图中为3次)。建立一个BitSet记录每个哈希函数的结果:将结果对应的位设置为真(1)。
在验证阶段,与输入阶段一样,对每个待验证的元素计算多次哈希:
- 当任意一个哈希结果对应的位为假(0),则证明该元素没有出现过,不会误判。(图中“王五”)
- 当所有哈希结果对应的位均为真时,则认为是曾经被输入过。但是随着元素的增多,BitSet内真值密度增加,可能存在误判。(图中“赵六”)
布隆过滤器的参数选取
在使用布隆过滤器之前,我们需要评估打算放入过滤器的元素数目n
以及可以接受的误判率p
。
需要的BitSet长度m
和哈希函数个数k
可以按照一下公式计算出来。
$$
m=\frac{-n*ln(p) }{ (ln(2)^2)}
$$
$$
k=ln2*\frac{m}{n}
$$
具体推导请看参考文献1和2。
如果想要在线计算的话,可以试试Bloom Filter Calculator (krisives.github.io)
简单的JAVA实现
代码里有注释,大概可以明白?有不明白的请在评论留言,我看到后会立刻补上解释
主体
哈希函数
所有的哈希函数集合都会实现hash
方法,用于计算key
的numHashFunctions
个哈希值,并返回。
这里使用的哈希函数思路来源于秦怀杂货店 - 掘金 (juejin.cn)和HahMap的哈希函数
现实中更广泛使用的还有MurmurHash等,感兴趣的可以看MurmurHash - Wikipedia。
测试
测试指标
这也算是个二分类问题,于是使用混淆矩阵作为评价。在参考文献6中可以找到相关的介绍。
测试过程
先往布隆过滤器中添加0-9000,随后测试1000-6000(出现过)以及10000-13000(之前未输入)的预测情况。代码内truePositive
、falsePositive
、falseNegative
、trueNegative
的意义同样参见参考文献6。
格式化打印结果
测试结果
可以看到,当布隆过滤器认定元素未被输入时,结果一定可信(FN)。当布隆过滤器认定为曾经输入过时,有一定几率误判(FP),总体上符合预期。
参考文献
- Bloom filter - Wikipedia
- Bloom Filters - the math (wisc.edu)
- algorithm - How many hash functions does my bloom filter need? - Stack Overflow
- 01ly/bloompy (github.com)
- 【实战问题】– 布隆过滤器的三种实践:手写,Redission以及Guava(2) - 掘金 (juejin.cn)
- 二分类模型评价标准:混淆矩阵 - 知乎 (zhihu.com)