一、概念
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。
它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
二、原理
然后我们根据H个不同的散列函数,对传进来的字符串进行散列,并且每次的散列结果都不能大于位数组的长度。
然后在对应的位数组的元素设置为 1(当位数组初始化时 ,所有位置均为0)。当第二次存储相同字符串时,因为先前的对应位置已设置为1,所以很容易知道此值已经存在。
1、添加和查询
下图以添加 A,B 两个元素为例:使用 hash1,hash2,hash3 3个哈希函数映射
当一个元素加入布隆过滤器中的时候,会使用 k 个哈希函数对其进行k次计算,得到 k 个哈希值,并且根据得到的哈希值,在维数组中把对应下标的值置为1
A 映射到 4, 17,18,相应的位置置为1
B映射到 2, 7,15,相应的位置置为1
插入的元素越来越多时,当一个不在布隆过滤器中的元素,经过同样规则的哈希计算之后,得到的值在位数组中查询,有可能因为这些位置因为其他的元素先被置1了,
所以布隆过滤器存在误判的情况(例如有一个元素C,哈希结果为2,4,7,但是因为2,4,7已经置1了,所以无法判断C是否存在)。
但是如果布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就一定不在。
2、误判公式
二进制位个数,哈希函数个数,误判率公式:( n-数据规模,p-误判率,m-哈希函数个数,k-二进制位个数)
复杂度分析:
- 添加,查询的时间负责度都是 O(k),k 是哈希函数的个数。
- 空间复杂度是O(m),m 是二进制位的个数
三、实现方案
添加一个 long[] 用于保存二进制位,添加以下3个全局变量
// 二进制向量的长度(一共有多少个二进制位)
private int bitSize;
// 二进制向量
private long[] bits;
//哈希函数的个数
private int hashSize;
添加:先通过哈希函数计算哈希值,根据哈希值定位到 long 数组索引位,然后通过取余再定位到二进制位,最后将那个二进制位设为1。
查询:使用同样的哈希函数计算哈希值,根据哈希值查询相应的二进制位是否为1,如果计算出的所有的哈希值相应的二进制位都为1,那么可能存在,否则一定不存在
谷歌 guava 提供了布隆过滤器的实现,jar 地址:https://mvnrepository.com/artifact/com.google.guava