1 布隆过滤器简介
布隆过滤器是一种空间利用率较高的概率型数据结构,用来测试一个元素是否在集合中。但是存在一定可能,导致结果误判。即元素不在集合中,查询结果却返回元素在集合中。
布隆过滤器一些的性质
- 与哈希表不同,布隆过滤器是一个大小固定的过滤器,可以通过任意大的数字来描述集合大小
- 添加一个元素到集合中永远不会添加失败,但误报率会随着添加元素数量的增多逐渐上升,直到集合中所有位都设置位1
- 查询一个元素是否存在会产生误报的可能
- 不应该从集合中删除元素。例如一个元素对应k的hash函数,当我们尝试删除,可能导致将hash值相同的元素也一并删除。
布隆过滤器的工作方式
一个空的布隆过滤器是一个由m个二进制位构成的数组。
我们需要k个hash函数来计算输入的hash值。当我们向过滤器中添加一个元素事,k个hash函数计算出的索引值 h1(x), h2(x),… hk(x)被设置位1。例如将geeks加入到过滤器中,我们用到3个hash函数,过滤器的长度为10,初始
值被设置为0。哈希函数的计算结果如下:
h1(“geeks”) % 10 = 1
h2(“geeks”) % 10 = 4
h3(“geeks”) % 10 = 7
接着我们将1,4,7位设置位1。
接着我们将nerd添加到集合中,hash值计算结果如下。
h1(“nerd”) % 10 = 3
h2(“nerd”) % 10 = 5
h3(“nerd”) % 10 = 4
如果我们想检查geeks是否在集合中,我们以相反的方式进行处理。我们使用h1,h2,h3计算初hash值。如果对应的二进制位都位1,那么可以判定“geeks”可能在集合中。如果任何一位为0,那么"geeks"一定不在集合中。
布隆过滤器结果误判
假如我们希望判定cat是否在集合中,首先计算hash值。得到1,3,7。但1,3,7是之前添加其它单词后设置的结果,我们之前并没有添加cat,因此造成了误判。
h1(“cat”) % 10 = 1
h2(“cat”) % 10 = 3
h3(“cat”) % 10 = 7
如果我们希望降低误判率,我们需要使用更多的hash函数及更大的数组。
布隆过滤器的误报概率
假设数组长度为m,并使用k个hash函数,n是要插入到过滤器中的元素个数,那么误报率的计算如下:
位数组的大小如果过滤器中的元素数量已直,期望的误报率位p,那么二进制位数组大小计算公式如下:
最优哈希函数数量
如果m是数组长度,n是插入的元素个数,k是hash函数的个数,k计算公式如下:
哈希函数的选择
哈希函数独立且生成的数值均匀分布,并且尽可能的快。比如MurmurHash、Jenkins_hash_function。
2 Guava提供的布隆过滤器
首先添加依赖,版本可根据实际使用来调整。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>22.0</version>
</dependency>
创建布隆过滤器时要传入期望处理的元素数量,及最期望的误报的概率。如下分别是500和0.01。
BloomFilter<Integer> filter = BloomFilter.create(
Funnels.integerFunnel(),
500,
0.01);
接着向过滤器中插入元素。
filter.put(1);
filter.put(2);
filter.put(3);
我们添加了3个元素,并且定义了最大元素数量为500,因此我们的过滤器将会产生非常准确的结果。我们使用mightContain()方法来测试。
assertThat(filter.mightContain(1)).isTrue();
assertThat(filter.mightContain(2)).isTrue();
assertThat(filter.mightContain(3)).isTrue();
assertThat(filter.mightContain(100)).isFalse();
因为布隆过滤器是一种概率型数据结构,因此返回true表示元素有极大的概率存在。当返回false那么表示元素一定不存在。
当我们创建布隆过滤器时,尽可能提供准确的元素数量。否则将会产生较高的误报率。
下面的例子表示集合最多5个元素,这样在实际使用时就会产生很高的误报率。
BloomFilter<Integer> filter = BloomFilter.create(
Funnels.integerFunnel(),
5,
0.01);
IntStream.range(0, 100_000).forEach(filter::put);
3 参考资料
[1]布隆过滤器算法介绍,https://www.geeksforgeeks.org/bloom-filters-introduction-and-python-implementation/
[2]Guava中的布隆过滤器,https://www.baeldung.com/guava-bloom-filter