确定不了解下布隆过滤器?

在学习Redis时,三大缓存问题是不可避免的,所以,我也是在此学习到了布隆过滤器?于是总结了这篇文章。

一、什么是布隆过滤器?

布隆过滤器是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,但是缺点是其返回的结果是概率性的,而不是非常准确的。理论情况下添加到集合中的元素越多,误报的可能性就越大。并且,存放在布隆过滤器的数据不容易删除。
在这里插入图片描述
说到检索一个元素是否在一个集合中,我们可能想到Java中的HashMap这些,但为什么不用这些来做呢?其实HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的,如果上亿数据时候,那 HashMap 占据的内存大小就变得很不可观了。

当一个元素加入布隆过滤器中的时候,会进行两步:
第一步:使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(有几个哈希函数得到几个哈希值)。
第二步:根据得到的哈希值,在位数组中把对应下标的值置为 1。

如下图,添加了两个字符串,但是要注意的是,5这个 bit 位由于两个值的哈希函数都返回了这个 bit 位,因此它被覆盖了。
在这里插入图片描述
在这里插入图片描述
当我们需要判断一个元素是否存在于布隆过滤器的时候,也会进行两步:
第一步:对给定元素再次进行相同的哈希计算;
第二步:得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值可能在布隆过滤器中,如果存在一个值不为 1,说明该元素一定不在布隆过滤器中。

如果现在要判断听风逝夜,计算出的结果为2、6、7,可其中有两位为0,则表示这数据一定不存在。但如果计算结果为1、3、4,可这几位都为1,能说明存在吗?答案是不能,只能说明可能存在。原因是因为随着增加的值越来越多,被置为 1 的 bit 位也会越来越多,这样某个值即使没有被存储过,但是万一哈希函数返回的三个 bit 位都被其他值置位了 1 ,那么程序还是会判断这个值存在。

二、布隆过滤器使用场景

  1. 判断给定数据是否存在:比如判断一个数字是否在于包含大量数字的数字集中、 防止缓存穿透(判断请求的数据是否有效避免直接绕过缓存请求数据库)等等、邮箱的垃圾邮件过滤、黑名单功能等等。
  2. 去重:比如爬给定网址的时候对已经爬取过的 URL 去重。

三、布隆过滤器实现

我们可以利用Google开源的 Guava中自带的布隆过滤器来做。Guava 中布隆过滤器的实现算是比较权威的,所以实际项目中我们不需要手动实现一个布隆过滤器。

<dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>28.0-jre</version>
</dependency>
 public static void main(String[] args) {
     // 创建布隆过滤器对象
     int size =100000;
     BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), size);
     for (int i = 1; i <=size; i++) {
         filter.put(i);
     }
     int count =0;
     for (int i = (size+1); i <=size*2; i++) {
         boolean b = filter.mightContain(i);
         if (b){
             count++;
         }
     }
     DecimalFormat df=new DecimalFormat("0.00");
     System.out.println("错判率为:" + df.format((float)count/10000));
 }

运行后我们发现,过滤器有 3% 的错判率,通过源码阅读,发现 3% 的错判率是系统写死的。
在这里插入图片描述
当然我们也可以通过传参,降低错判率。测试了一下,查询速度稍微有一丢丢降低,但也只是零点几毫秒级的而已。

static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp, Strategy strategy);
// 参数含义:
// funnel 指定布隆过滤器中存的是什么类型的数据,有:IntegerFunnel,LongFunnel,StringCharsetFunnel等。
// expectedInsertions 预期需要存储的数据量
// fpp 误判率,默认是0.03。

四、什么不支持删除

可以举一个例子来说明。

比如要删除集合中的成员”听风“,那么就会先用 k个哈希函数对其计算,因为”听风“已经是集合成员,那么在位数组的对应位置一定是 1,我们如要要删除这个成员”听风“,就需要把计算出来的所有位置上的 1 置为 0,也就是将1、3 和 5 位置为 0 。但是,“逝夜”也是属于集合的元素,如果需要查询 “逝夜” 是否在集合中,通过哈希函数计算后,我们会去判断2、4、5位是否为 1, 这时候就得到了第5位为0的结果,即“逝夜”不属于集合。 显然这里是误判的。

​但是Counting Bloom Filter可以了解一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值