【redis 布隆过滤器】
简述:
这个过滤器可以检索一个元素是否在一个集合中(优点是查询效率很高,缺点是有一定概率出现误判),可以理解为 利用高效的数据结构和算法快速判断出你这个 Key 是否在数据库中存在,不存在就 return ,存在就去查询 DB数据库 刷新 KV 再 return。
可以通过代码来看下效果:
先导入依赖:
<dependency> <groupId>com.google.guavagroupId> <artifactId>guavaartifactId> <version>20.0version> dependency>
测试demo:
private static int size = 1000000;//预计要插入多少数据,即布隆数组长度 private static double fpp = 0.01;//期望的误判率 // private static BloomFilterbloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp); private static BloomFilterbloomFilter = BloomFilter.create(Funnels.integerFunnel(), size); public static void main(String[] args) { //插入数据 for (int i = 0; i < 1000000; i++) { bloomFilter.put(i); } double count = 0; for (int i = 1000000; i < 2000000; i++) { if (bloomFilter.mightContain(i)) { count++; // System.out.println(i + "误判了"); } } System.out.println("100w条数据,其中总共的误判数:" + count + "误判率 :"+ (count/1000000L) * 100 + "%"); // 如果增加过滤器哈希数组长度为100 0000,则默认误判率会降低到 0.003% }
输出结果:
100w条数据,其中总共的误判数:30155.0误判率 :3.0155000000000003%
可以看到误判数为3%,源码里有create方法重载,可以看到 有一种方法(我代码里注释掉的)可以手动传入期望误判率,手动设置期望误差值的话输出如下:
100w条数据,其中总共的误判数:10314.0误判率 :1.0314%
如上图所示:其默认误判率在0.03左右。
为什么会有误判率?
从布隆过滤器的原理上来讲,其本身并不会存储真正的数据,只是在哈希数组中分配标记,例如:
也就是说,其根据对应位置是否为1,判断数据是否存在,于是就会有个问题,当3和7都占据这个长度为4的数组下标【3】处,只会被记录一次,所以这个数据实际上可能并不存在(对应缓存中其实没有),也就是说,如果布隆返回不存在那就是不存在,而返回存在时可能存在误判。这个误判通过增加布隆过滤器哈希数组长度可以得到减轻,因为01重复存入的概率会变小。
总结:
布隆过滤器的查询速度很快,而且保密性强,因为只是存储二进制01(不存储原始数据,可以节省存储空间),而它的误判概率并不大,对于零星的漏网之鱼落在缓存上应该是可以接受的。