布隆过滤器(Bloom Filter)是什么?
我的理解是,一种可以在缓存等系统中,可以通过简单快速的操作初步判断元素是否在系统的方法。(以算力换时间)
通俗讲:比如说,我现在有三个值x、y、z
,通过某种规则编辑映射为1、2、3
数字值;那么另一个值过来的时候,我用这个规则,把他也编成一个值,如果这个值不在1、2、3
里面,那么这个值 【肯定不在】 这里面,如果这个值在1、2、3
里,那么,这个值 【有较大的可能性】 在我现有的x、y、z
,其实也是函数y=f(x)
的思想, y相同,x不一定相同,y不同,x一定不同。这个规则就是哈希函数。
具体怎么操作?
定义一个足够大的位数组,例如 100w,那么占用空间为: 1000000bit =125000 Byte = 125000/1024 kb ≈ 122kb
通过一个或多个哈希函数,将某个字符串映射到数组某个或多个位置,【映射到的位置】把值设置为1,要检验输入值是否存在,对值进行同样的哈希运算,得到位置,检查这些位置是否都为1,有不为1的则说明该值不存在,都为1,则值可能存在,这样就可以过滤到很大一部分值进入系统。
在什么情况下用。
在明白了原理之后,其实有很多应用场景就明了了,例如,可以确定的判断不存在的值,那么可以判断给输入数据是否存在(有效)、判重等操作。如
- 防止缓存穿透(判断请求的数据是否有效避免直接绕过缓存请求数据库)等等、
- 邮箱的垃圾邮件过滤
- 黑名单功能等等。
- 判重:比如爬给定网址的时候对已经爬取过的 URL 去重。
其他情况
缺点:有一定的错误识别率和删除难度
相关模块:
- Google 开源的 Guava 中自带的布隆过滤器(单机)
// 创建布隆过滤器对象
//create(Funnel<? super T> funnel, int expectedInsertions, double fpp)
//funnel什么类型的过滤器, expecedInsertions预期输入数, fpp 错误率. 底层会根据输入数和错误率, 根据算法创建一个合适大小的位数组.
BloomFilter<Integer> filter = BloomFilter.create(
Funnels.integerFunnel(),
1500,
0.01);
// 判断指定元素是否存在
System.out.println(filter.mightContain(1));
System.out.println(filter.mightContain(2));
// 将元素添加进布隆过滤器
filter.put(1);
filter.put(2);
System.out.println(filter.mightContain(1));
System.out.println(filter.mightContain(2));
思考
以算力(或空间)换时间。其实一些类似的思想也有用过(先行检验)。
比如,在我们系统解决过一个情况,对一组数据集合进行操作,但是这个操作有点耗时,由于多个用户在使用相同的功能,这组数据的【部分数据】有可能在其他地方同时操作,如果同时操作的话,数据可能会有误差。
直接加全局锁不太现实,所以,我就把数据在使用前用缓存存起来,另一个员工操作时,验证其中是否有部分数据在这个缓存里面,有的话剔除或者提示员工。
这样我需要锁和验证的地方和时间就很少,因为不合适的数据不会到后续的流程中。