布隆过滤器
场景分析
如何解决这个问题,这个时候会想到布隆过滤器,有用redis
的,也有用guava
的,还有自己实现的。
首先布隆过滤器是一个bit
向量或数组,这里就当做数组了。
我们得初始化这个数组即给与这个过滤器一定的长度,然后我们对一个key
进行hash
算法,可以多次hash
,下图就hash
了3次,将数组的对应的index
的值设置为1。
完成了以后当该key
再次请求过来的时候将三次hash
的结果进行与运算,如果结果为1时就说明我们的这个key
存在,即可以继续请求缓存或者数据库,如果为0就直接返回。如果一个key
的hash
结果与其他key
的hash
结果有冲突的话,就出现误判的情况。
// 假设我的bloomFilter算法用的是String的hashCode()的方法,就会出现哈希碰撞
@Test
public void testVoid(){
System.out.println("Ea".hashCode());
System.out.println("FB".hashCode());
}
// 打印结果
// 2236
// 2236
这就是 否一定为否,真不一定为真
。
实现
关于BloomFilter
的实现也有很多,我们就用最简单的guava
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
</dependency>
@Test
public void bloomFilter(){
// 指定过滤器的大小
int size = 100000;
// 误差率
double fpp = 0.001;
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), size, fpp);
// 将过滤器存满数据,当数据<1000000时 一定存在,大于1000000 理论上不存在,但是存在误判
for (int i = 0; i < 100000 ; i++) {
bloomFilter.put(""+i);
}
int count = 0;
// 取100000以上的数字 执行1000000次 存在一次 计数器+1
for (int j = 100000; j < 200000 ; j++) {
if (bloomFilter.test(""+j)){
count++;
}
}
System.out.println(count/100000.0);
}
// 打印结果
0.00112
参考资料
[布隆过滤器的误判率该如何计算?(https://www.zhihu.com/question/38573286)]
[布隆过滤器(Bloom Filter) 未完待续 (https://www.cnblogs.com/noKing/p/9352377.html)]
[大白话布隆过滤器(https://www.cnblogs.com/CodeBear/p/10911177.html)]