聊聊布隆过滤器

目录

一、什么是布隆过滤器?

二、使用场景

三、原理

四、使用

4.1、Guava实现

4.2、Redisson实现


一、什么是布隆过滤器

        布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的,是一种数据结构。它实际上是一个很长的二进制向量和一系列随机映射函数

        布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是高效的插入和查询,而且非常节省空间,缺点是hash 碰撞造成的误识别率和删除困难。

二、使用场景

        一般使用较多的场景就是避免缓存穿透,具体场景就是在使用 Reids 做数据缓存的时候,很有可能会遇到一个问题:用户想要查询一个数据,发现 redis 缓存没有命中,于是向数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求数据库。这会给数据库造成很大的压力,这时候就相当于出现了缓存穿透。缓存穿透也是实际开发中必须要避免和提前预防的内容之一。

避免缓存穿透,有以下几种解决方案:
1、缓存空值。为了解决这个问题呢,通常我们可以向分布式缓存中写入一个过期时间较短的空值占位,但这样会占用较多的存储空间,性价比不足。

2、使用 HashMap。将需要查询的 key 提前加载到 HashMap 中,因为 HashMap 查找的时间复杂度为 O(1) ,因此通过映射可以快速查找到相应的 Key 来判定 Key 是否存在 ,如果查不出来就没必要继续查找缓存了。但是这样做的话极其消耗宝贵的内存,数据量大的情况下成本也会上升。此种做法会对内容造成不可测的负担,不推荐使用。

3、使用 Bloom Filter。原理上和使用 HashMap 一样,但更省空间。此种做法为主流做法,推荐使用布隆过滤器。

三、原理

布隆过滤器的原理:当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点,把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在

简单来说就是准备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len (m) 取余得到 k 个位置并将 m 中对应位置设置为 1。

如上图,位数组的长度是8,散列函数个数是 3,先后存入两个元素x,y。这两个元素都经过三次哈希函数生成三个哈希值,并映射到位数组的不同的位置,并置为1。元素 x 映射到位数组的第0位,第4位,第7位,元素y映射到数组的位数组的第1位,第4位,第6位。

保存元素 x 后,位数组的第4位被设置为1之后,在处理元素 y 时第4位会被覆盖,同样也会设置为 1。

当布隆过滤器保存的元素越多被置为 1 的 bit 位也会越来越多,元素 x 即便没有存储过,假设哈希函数映射到位数组的三个位都被其他值设置为 1 了,对于布隆过滤器的机制来讲,元素 x 这个值也是存在的,也就是说布隆过滤器存在一定的误判率

若位数组长度太小则会导致所有 bit 位很快都会被置为 1 ,那么检索任意值都会返回”可能存在“ , 起不到过滤的效果。位数组长度越大,则误判率越小。

同时,哈希函数的个数也需要考量,哈希函数的个数越大,检索的速度会越慢,误判率也越小,反之,则误判率越高。相同位数组长度的情况下,随着哈希函数的个人的增长,误判率显著的下降。

布隆过滤器支持删除吗

布隆过滤器其实并不支持删除元素,因为多个元素可能哈希到一个布隆过滤器的同一个位置,如果直接删除该位置的元素,则会影响其他元素的判断。但我们可以通过计数布隆过滤器(不推荐)定时重新构建布隆过滤器两种方案实现删除元素的效果。

四、使用

4.1、Guava实现

添加Maven依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>22.0</version>
</dependency>
package com.cjian.boomfilter;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

import java.nio.charset.StandardCharsets;

/**
 * @Author: cjian
 * @Date: 2023/4/20 11:53
 * @Des:
 */
public class Demo {
    static BloomFilter<String> filter;

    static {
        filter = BloomFilter.create(
                //Funnel 是一个接口,用于将任意类型的对象转换为字节流,
                //以便用于布隆过滤器的哈希计算。
                Funnels.stringFunnel(StandardCharsets.ISO_8859_1),
                10000,  // 插入数据条目数量
                0.001  // 误判率
        );
        addDate();
    }

    public static void main(String[] args) {
        System.out.println(mayContain("aaa"));
        System.out.println(mayContain("bbb"));
    }

    private static void addDate() {
        System.out.println("初始化布隆过滤器数据开始");
        //插入2个元素
        filter.put("aaa");
        filter.put("bbb");
        System.out.println("初始化布隆过滤器数据结束");
    }

    public static boolean mayContain(String id) {
        return filter.mightContain(id);
    }
}

4.2、Redisson实现

添加Maven依赖 

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.16.1</version>
</dependency>
package com.cjian.boomfilter;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

/**
 * @Author: cjian
 * @Date: 2023/4/20 13:54
 * @Des:
 */
public class RedissonDemo {
    static RBloomFilter<String> bloomFilter;

    static {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        bloomFilter = Redisson.create(config).getBloomFilter("myBloomFilter");
    }

    public static void main(String[] args) {
        init();
        System.out.println(mightContain("aaaa"));
        System.out.println(mightContain("bbbb"));
    }

    private static void init() {
        //10000表示插入元素的个数,0.001表示误判率
        bloomFilter.tryInit(10000, 0.001);
        //插入2个元素
        bloomFilter.add("aaaa");
        bloomFilter.add("bbbb");
    }

    private static boolean mightContain(String id) {
        return bloomFilter.contains(id);
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redisson布隆过滤器是基于Redis实现的Java分布式布隆过滤器。它可以在多个JVM节点或其他进程中通过相同的KEY获取到布隆过滤器布隆过滤器的主要功能是判断某个元素是否存在于容器中,因此非常适合解决缓存穿透问题和检查数据是否重复的场景使用Redisson布隆过滤器时,需要单独开一个定时任务来初始化布隆过滤器的数据,并在删除或更新数据时重新刷新布隆过滤器。虽然使用布隆过滤器可能稍显麻烦,但可以使用Redis的Set类型来替代。\[1\]\[2\] 在代码示例中,可以看到使用Redisson布隆过滤器的示例代码。首先通过redisson.getBloomFilter方法获取布隆过滤器实例,然后使用tryInit方法初始化布隆过滤器的容量和误差率。接下来可以使用add方法向布隆过滤器中添加元素,使用contains方法判断元素是否存在于布隆过滤器中。\[2\]\[3\] 总结来说,Redisson布隆过滤器是一种解决缓存穿透和检查数据重复的有效工具,但在使用时需要注意初始化和刷新布隆过滤器的操作。 #### 引用[.reference_title] - *1* *2* *3* [从头开始学Redisson--------布隆过滤器](https://blog.csdn.net/yanluandai1985/article/details/104848454)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值