首页 > 编程知识 正文

布隆过滤器 redis击穿,布隆过滤器简书

时间:2023-05-05 04:46:44 阅读:130405 作者:1541

布隆过滤器:我说不存在。 200%不存在。 (我说它存在,我可能有错的时候…) )

前言:本文使用最简洁易懂的文字和小图进行说明。 (不详细说明哈希策略的计算。 )

一.布隆过滤器有什么用?

二.布隆过滤器的原理是什么?

三.在java中如何使用布隆过滤器?

这篇报道的内容可能很多,请耐心等待。

一.布隆过滤器有什么简单的两点要说:

1 .保存值

储值是指储值,类似于我们常用的映射、集等;

2 .检查值是否存在

我想知道模糊过滤器中是否存在检测,调用相关的检测方法,就能知道一个结果。

特别注意:布隆过滤器检查值的结果返回的结果为false,如果不存在,则肯定不存在。

然而,如果结果为true,则可能存在并且概率上是误报。

为什么? 看看下面的实现原理就知道了。

二.布隆过滤器的原理是什么

首先,从上面介绍的布隆过滤器的作用来说,是储存物品的容器。

但是,这个容器也有自己的特征,

1 .它有一定的大小。 也就是说,首先设定可以放多少东西。

2 .存在的检查要素的精度(指true存在的精度)越多,精度逐渐降低

怎样才能更好地理解这个原理呢?

决定根据布隆过滤器的作用角度进行说明。

首先,是储存数值的原理。 既然可以储存数值,然后可以检查是否存在,这个储存值显然不是直接扔进去就可以了,需要用算法计算。

这里不详细介绍这个算法,我用我的文字告诉你。 过程和结果。

模拟场景

假设完全空的光晕滤波器是由m个二进制位组成的数组,其中m=5个。

缺省情况下,这五个二进制位很容易理解为位置,并且都绑定了一个标记0

那么,让我们来看看如何存钱。

布隆过滤器存值,实际上不是存的 真实值,而且通过算法计算后,存入对应的标识。

过程简述,也就是布隆过滤器拿到我们传入的值, 它会将这个值,使用 K个 哈希函数去进行算法计算,计算完后,

会得出K个 二进制位的标识 0或者1 ,然后对应位置就会存入这个标识0或者1.

存值过程举例说明:我们必须存入的值是‘JC test’,

布隆过滤器采用相关的计算公式来计算需要使用多少散列函数,即k。

(m是数组的长度,n是要插入的元素的个数,k是hash函数的个数)

公式很容易明白。 这里假设k是3。

也就是说,‘JC test’需要经过三个散列函数来计算h1、h2、h3。

计算算法后,结果如下。

h1算法对“‘JCtest”的结果是二进制位置为1

h2算法对“JC测试”的结果是二进制位置为3

h2算法对“‘JCtest”进行的结果表明,二进制位置为5

此时,对应的图如下所示。

一三五个位置的标志现在就可以联系到1

类似地,假设存储在第二个值“‘BFtest”中也需要经由三个散列函数,并且,

计算出的二进制位分别为2、3和5,当前的光晕滤波器如下所示:

到目前为止,我实际上知道了该布隆过滤器的值的存储方法。 简言之,每个值都会转换为几个位置之一。 储存在里面的话,位置是1。 在所有位置都达到1之前,不能再存了。 (请不要担心这个位置是否马上变成1。 这里只举例说明了5个位置,所以在后面的使用介绍环节中储存100万并不是问题。 )

对光晕过滤器有无检查值的原理进行说明。很简单,其实也是我们告诉布隆过滤器一个值, 它也会通过K计算公式,取出一定数量的哈希函数,也是计算出很多个位置,

然后进行一个个的位置监视,如果所有的位置都是1的话,这个时候它会返回true,告诉我们这个值存在;

如果某个位置为0,则此时返回false,告诉我该值不存在。

如果要检查校验举例说明:值,请单击“‘JCtest”、

通过布隆过滤器

公式计算得出它准备使用三个函数 h1,h2,h3,
然后计算出对应的二进制位 一,三 ,五  ,接着去检查对应的位置上绑定的标识,如果都是1,那么就会返回存在 true。

 

误判举例说明:

那怎么会误判呢?
那就是例如,我们传入一个需要校验的值,‘CSDNTest’,布隆过滤器通过相关函数算出,位置恰好也是一,二,三 ,那我们实际上根本没存过CSDNTest,

但是因为我们之前存JCtest 和 BFTest 导致了相关的位置都绑定了标识1,所以这时候布隆过滤器就产生了误判现象。(这个概率不高其实,接下来的实用介绍会了解到)

 

PS: 也是因为这种校验的策略,所以只要在校验的时候,检测到一个对应的位置不为1,那么毫无疑问!这个值是百分之两百不存在的!

 

 三.java中怎么使用布隆过滤器

了解了布隆过滤器的作用和原理后,那么我们接下来在java中使用它。

该篇就不去手动实现布隆过滤器了,因为 在GoogleGuavalibrary中Google为我们提供了一个布隆过滤器的实现。

所以我们第一步,导入jar包:

<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency>

 

然后建一个BloomFilterTest.class :

import com.google.common.base.Charsets;import com.google.common.hash.BloomFilter;import com.google.common.hash.Funnels;/** * @Author : JCccc * @CreateTime : 2020/3/31 * @Description : **/public class BloomFilterTest { private static int size = 1000000;//预计要插入多少数据 private static double fpp = 0.01;//期望的误判率 public static void main(String[] args) { //存入的是字符串 BloomFilter<CharSequence> bloomFilterStr = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), size, fpp); for (int i = 0; i < size; i++) { bloomFilterStr.put("test" + i); } boolean containsValue1 = bloomFilterStr.mightContain("test1"); boolean containsValue2 = bloomFilterStr.mightContain("test34"); boolean containsValue3 = bloomFilterStr.mightContain("test1000001"); System.out.println(containsValue1); System.out.println(containsValue2); System.out.println(containsValue3); }}

校验结果:

 

然后再试下,使用布隆过滤器存入数字:

 

BloomFilter<Integer> bloomFilterInt = BloomFilter.create(Funnels.integerFunnel(), size, fpp); for (int i=0; i<size;i++){ bloomFilterInt.put(i); } boolean containsValue4 = bloomFilterInt.mightContain(1); boolean containsValue5 = bloomFilterInt.mightContain(2); boolean containsValue6 = bloomFilterInt.mightContain(10000002); System.out.println(containsValue4); System.out.println(containsValue5); System.out.println(containsValue6);

结果:

 

可以看到以上两存值&校验的测试都是准确无误的,那么我们大规模的存值检查,看看存在的误判现象:

 

 我们刚刚往 bloomFilterInt 这个过滤器里面存入了0到1000000 个数字值,

那么接下来我们直接从1000000开始去累加到2000000,去进行校验,

我们明确知道 这时候的布隆过滤器里面有1百万个值,而我们的1000000到2000000除了‘1000000’其实都是不存在的,都应该返回false。
接下来我们用代码来模拟下这个判断存在 的误判现象:

int size = 1000000;//预计要插入多少数据 double fpp = 0.01;//期望的误判率 BloomFilter<Integer> bloomFilterInt = BloomFilter.create(Funnels.integerFunnel(), size, fpp); for (int i=0; i<size;i++){ bloomFilterInt.put(i); } int count = 0; for (int i = 1000000; i < 2000000; i++) { if (bloomFilterInt.mightContain(i)) { count++; System.out.println(i + "误判了"); } } System.out.println("总共的误判数:" + count);

结果:

在这一百万个数值的布隆过滤器里面,再校验一百万次,存在的误判数是10314次。 

 

 

所以咱们使用布隆过滤器进行值的存入和校验时, 我们应该更偏向使用 它返回的false 进行结合业务做操作,因为它的判断如果返回fasle,那是百分之两百可信的!

当然其实true误报的情况,概率也是非常小的,在一定的业务场景也能使用的其实。

 

ps:

例如,我们先到布隆过滤器查询一个订单是否存在,不存在就当失败订单处理;
存在的话,我们再去数据库获取详情信息进行订单的后续操作。
这时候只需要我们再接收到订单存入数据库的时候,把单独的订单号存入布隆过滤器即可。
就算布隆过滤器误判了,我们再去数据库查询订单时,加上多一步校验存在与否即可。

这样就可以减轻每个订单都需要查数据库的压力。

(其实有过了解redis使用的小伙伴,就明显知道布隆过滤器配和redis使用会非常不错,可以一定程度防止缓存穿透,这些我有时间会在我的redis栏目写一篇对缓存穿透和缓存雪崩的介绍和解决思路相关的文章)

 

 

那么这篇普及布隆过滤器就先到这吧。

 

 

如果光看这个觉得没有安全感,那么可以继续看一下我这篇,springboot结合redis去使用布隆过滤器:

https://blog.csdn.net/qq_35387940/article/details/105700615

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。