【redis】布隆过滤器详解

布隆过滤器原理与应用
布隆过滤器是一种概率型数据结构,用于高效检索集合中元素的存在性,特别适用于大数据场景下的快速判断和防止缓存穿透。其优点在于极高的空间效率和查询速度,但存在一定的误识别率。

简介

本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),它实际上是一个很长的二进制向量和一系列随机映射函数。

布隆过滤器可以用于检索一个元素是否在一个集合中,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,逻辑是当布隆过滤器说某个值存在时,这个值 可能不存在;当它说不存在时,那么 一定不存在。

优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

适用场景

1.大数据判断是否存在

HashMap可以判断某个元素是否存,可以将值映射到 HashMap 的 Key,然后可以在 O(1) 的时间复杂度内返回结果,效率奇高。但是 HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的,而一旦你的值很多例如上亿的时候,那 HashMap 占据的内存大小就变得很可观了。这时候我们就需要考虑布隆过滤器了。

2.解决缓存穿透

什么是缓存穿透就不在这里解释了,在我之前的博客已经讲解过了。https://blog.youkuaiyun.com/wangyunzhao007/article/details/106478806

当有大量的请求访问我们不存在的数据中,缓存失效,会直接访问到数据库,当数据库扛不住压力时,数据库崩溃,这既是缓存穿透。而布隆过滤器可以判断访问的数据是否存在,当存在是才可以访问,不存在直接返回,避免了缓存穿透的发生。

数据结构和原理

布隆过滤器是一个 bit 向量或者说 bit 数组,长这样:

如果我们要映射一个值到布隆过滤器中,我们需要使用多个不同的哈希函数生成多个哈希值,并对每个生成的哈希值指向的 bit 位置 1

例如针对值 “hello” 和三个不同的哈希函数分别生成了哈希值 1、3、5,这把1,3,5对应的位改为1,则上图转变为:

再存一个值 “world”,如果哈希函数返回 3、4、8 ,我们把3,4,8对应的位改为1

接下来我们判断hello,world,haha,三个是否存在。根据上图的二进制向量图可以判断,三个哈希值对应的位都是1,则认为值存在,有一个零或者多个,则认为值不存在。

布隆过滤器认为当哈希值1,3,5对应的都是1,则认为world存在。

布隆过滤器认为当哈希值 3、4、8对应的都是1,则认为hello存在。

如果我们haha映射的值为3,4,5,布隆过滤器也认为haha存在,但其实是不存在,所以布隆过滤器会误判。

所以布隆过滤器说某个值存在时,这个值 可能不存在;当它说不存在时,那么 一定不存在。

缺点

  1. 随着数据的增加,误判率随之增加;
  2. 无法做到删除数据;
  3. 只能判断数据是否一定不存在,而无法判断数据是否一定存在。

guava实现布隆过滤器

引入pom

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

 代码

   private static int size = 1000000;//预计要插入多少数据

    private static double fpp = 0.01;//期望的误判率

    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);

    public static void main(String[] args) {
        //插入数据
        for (int i = 0; i < 1000000; i++) {
            bloomFilter.put(i);
        }
        int count = 0;
        for (int i = 1000000; i < 2000000; i++) {
            if (bloomFilter.mightContain(i)) {
                count++;
                System.out.println(i + "误判了");
            }
        }
        System.out.println("总共的误判数:" + count);
    }

代码简单分析:
我们定义了一个布隆过滤器,有两个重要的参数,分别是 我们预计要插入多少数据,我们所期望的误判率,误判率不能为0。
我向布隆过滤器插入了0-1000000,然后用1000000-2000000来测试误判率。

运行结果

 

用过判断了100万数据,一共误判10314,误判率10314/1000000=0.010314

和我们定义的期望误判率0.01相差无几

参考博客https://www.cnblogs.com/CodeBear/p/10911177.html

### 正确配置Spring Boot项目中的布隆过滤器容量 在Spring Boot项目中设置布隆过滤器的容量对于确保其有效性和准确性至关重要。当设定布隆过滤器的预期元素数量和误报率时,可以计算出合适的位数组大小以及哈希函数的数量。 #### 计算布隆过滤器参数 为了合理配置布隆过滤器,在创建实例之前应当估算预计存储的最大元素数目n,并决定可接受的最大假阳性概率p。基于这两个因素,可以通过下面两个公式来确定m(bit array长度)和k(hash functions数目的估计值): \[ m = -\frac{n \ln p}{(\ln 2)^2} \] \[ k = \frac{m}{n}\ln 2 \] 其中\( n \)代表期望插入到集合中的元素总数目,而 \( p \) 是允许的最大错误几率[^1]。 #### 应用场景下的具体操作 考虑到实际开发环境,通常会在应用程序属性文件application.properties或application.yml内指定这些参数。例如,在YAML格式下,可能如下所示: ```yaml bloomfilter: expectedElements: 1000000 # 预期元素数量 fpp: 0.03 # 可容忍的误判概率, 即false positive probability ``` 接着可以在Java代码里读取上述配置项并初始化布隆过滤器对象: ```java @ConfigurationProperties(prefix="bloomfilter") public class BloomFilterConfig { private long expectedElements; private double fpp; public FilterBuilder getBloomFilterBuilder(){ return new ClassicBloomFilter.Builder() .expectedInsertions(expectedElements) .fpp(fpp); } // getters and setters... } ``` 这样做的好处是可以方便地修改配置而不必重新编译源码,同时也便于管理不同环境下不同的配置版本[^2]。 #### 动态调整策略 随着业务的发展变化,原始预估可能会变得不再准确。因此建议定期评估当前系统的负载情况,并相应更新布隆过滤器的相关参数。如果发现现有资源不足以支撑新的需求,则应该考虑增加服务器集群规模或是改进算法设计以提高效率[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值