百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Redis实现布隆过滤器(下)(redis bitmap 布隆过滤)

mhr18 2024-11-08 12:11 24 浏览 0 评论

Redis实现布隆过滤器(下)

Redis4.0通过模块化的形式集成了布隆过滤器,后续通过下面的命令就可以操作布隆过滤器,路径https://redis.io/commands/?group=bf

那么我们怎么通过Java代码去操作布隆过滤器呢?

RedisBloom官网提出了三种直接操作Redis布隆过滤器模块的方式,相关资料参考https://github.com/RedisBloom/RedisBloom,其中JreBloom已经弃用暂不讨论。

注意:远程连接时redis.conf配置文件中需要关闭受保护模式protected-mode no

Jedis支持布隆过滤器

jedis是专门为Redis设计的简单易用性客户端,同时最新版本也支持模块化服务如布隆过滤器

引入依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.2.0</version>
</dependency>

测试代码

public class JedisDemo {
    public static void main(String[] args) throws URISyntaxException {
        // 建立连接
        BloomFilterCommands bloomFilterCommands = new JedisPooled(new URI("redis://47.99.147.139:6379"),1000000);
        // 构建布隆过滤器参数
        BFReserveParams bfReserveParams = new BFReserveParams();
        bfReserveParams.expansion(2);
        // 创建一个过滤器
        String test = bloomFilterCommands.bfReserve("test", 0.1, 100, bfReserveParams);
        // 向过滤器中添加元素
        bloomFilterCommands.bfAdd("test",String.valueOf(1));
        // 判断元素是否存在
        boolean isExist = bloomFilterCommands.bfExists("test", "1");
        System.out.println(isExist);
    }
}

其余功能性API可以通过官方文档查阅https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html。

redis-modules支持布隆过滤器

redis-modules是基于Java的客户端,依赖于redisson,所以也需要引入redisson依赖。

引入依赖

<!-- 引入redisson依赖 -->
<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.17.1</version>
</dependency>  
<!-- release  这里是引入所有支持的module-->
<dependency>
    <groupId>io.github.dengliming.redismodule</groupId>
    <artifactId>all</artifactId>
    <version>2.0.0</version>
</dependency>
<!-- 也可以只引入单一的module:如布隆过滤器,两者选其一即可 -->
<dependency>
    <groupId>io.github.dengliming.redismodule</groupId>
    <artifactId>redisbloom</artifactId>
    <version>2.0.0</version>
</dependency>

测试代码

public static void main(String[] args) {
    // redisson创建连接一样的写法,需要引入redisson依赖
    Config config = new Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:6379");
    RedisBloomClient redisBloomClient = new RedisBloomClient(config);
    // 得到指定名字的布隆过滤器对象
    BloomFilter bloomFilter = redisBloomClient.getRBloomFilter("bf");
    // 指定布隆过滤器错误率和容量
    bloomFilter.create(0.1d, 100);
    // 向布隆过滤器中添加元素
    bloomFilter.madd(new String[] {"a", "b", "c"});
    // 批量判断元素是否存在类似BF.MEXISTS
    List<Boolean> booleans = bloomFilter.existsMulti("a", "b", "d");
    System.out.println(booleans);
    // 关闭客户端
    redisBloomClient.shutdown();
}

redis布隆过滤器命令和Java代码对应可以参考官方在线链接https://github.com/dengliming/redis-modules-java/tree/master/redisbloom

上面提到的jedis和redis-modules支持布隆过滤器,存储到redis中也是布隆过滤器的形式

但除了这种形式外,还有其它的方法去实现布隆过滤器,如redisson不需要采用redis集成的redis-bloom就可以实现布隆过滤器。

Redisson支持布隆过滤器

引入依赖

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.17.1</version>
</dependency>  

测试连接代码

public static void main(String[] args) {
    // 1. Create config object
    Config config = new Config();
    /** 根据redis实例模式选择对于实例化方法
       * 集群模式:useClusterServers
       * 单实例模式:useSingleServer
       * Sentinel 模式:useSentinelServers
       * 主从模式:useMasterSlaveServers
       */
    config.useSingleServer().setAddress("redis://47.99.147.139:6379");
    // 2. Create Redisson instance
    RedissonClient redisson = Redisson.create(config);
    RBloomFilter bloomFilter = redisson.getBloomFilter("sample");
    // initialize bloom filter with 在使用前必须使用tryInit初始化
    // expectedInsertions = 55000000 期望值
    // falseProbability = 0.03 错误率
    bloomFilter.tryInit(10, 0.03);
    bloomFilter.add("1001");
    System.out.println(bloomFilter.contains("1002"));
    redisson.shutdown();
}

执行完上述代码后我们可以查看redis中存储的数据

### redisson执行bloomFilter.tryInit,并且成功,
### 不往布隆过滤器中添加元素那么redis只有一个值{**}:config
127.0.0.1:6379> keys *
1) "{sample}:config"
### 查看存入值的类型
127.0.0.1:6379> type "{sample}:config"
hash
127.0.0.1:6379> HKEYS "{sample}:config"
1) "size" ### 二进制bit数组长度 
2) "hashIterations" ### 哈希函数的个数
3) "expectedInsertions" ### 容量
4) "falseProbability" ### 错误率
127.0.0.1:6379> hget "{sample}:config" "size"
"72"
127.0.0.1:6379> hget "{sample}:config" "hashIterations"
"5"
127.0.0.1:6379> hget "{sample}:config" "expectedInsertions"
"10"
127.0.0.1:6379> hget "{sample}:config" "falseProbability"
"0.03"
#### 存放真正值
127.0.0.1:6379> type sample
string

redisson会生成两个键值{sample}:config和sample,其中{sample}:config是哈希类型,用于存储用户配置的布隆过滤器配置,sample为string类型,用于存储真实的bit数组。

那么除了依赖redis还有没有办法去实现布隆过滤器呢?当然Google就开源出了guava工具类就可以实现布隆过滤器。

Guava实现布隆过滤器

guava是谷歌开源工具类,其中就有能直接实现布隆过滤器的方法,不需要重复造轮子。

引入依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>

测试代码

public static void main(String[] args) {
    int num = 100000;
    // 创建布隆过滤器对象,误判率默认0.03,可以指定
    // num表示布隆过滤器的容量
    BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(),num,0.01);
    // 往布隆过滤器中添加数据
    for (int i = 0; i <num ; i++) {
        bloomFilter.put(i);
    }
    // 判断刚添加进去的值误判情况
    for (int i = 0; i <num ; i++) {
        // mightContain 判断布隆过滤器是否包含对象
        if (!bloomFilter.mightContain(i)){
            System.out.println("出现误判了~,值:"+i+"==是存在的");
        }
    }
    int count = 0;
    // 判断没有在布隆过滤器中的值是否有误判情况
    for (int i = num; i <num+num ; i++) {
        if (bloomFilter.mightContain(i)){
            count += 1;
        }
    }
    System.out.println("不存在布隆过滤器中的元素误判数量:"+count);
}

结果展示,存在误判情况,符合预设置的误差范围

其它命令可以参考guava官网API文档https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/hash/BloomFilter.html

布隆过滤器配置参考

我们可以通过github上开源工具,输入布隆过滤器大小以及可以接受的误差率,计算布隆过滤器的最佳配置,计算工具参考https://krisives.github.io/bloom-calculator/

错误率和哈希函数以及内存容量有关,当错误率越低,那么需要的哈希函数个数就得越多,内存容量就得越大,所以布隆过滤器的设置需要根据实际业务确定,这是在准确率和性能上做了取舍。

布隆过滤器的应用场景

布隆过滤器虽然存在误判率和删除困难的缺点,但其能快速判断对象是否存在的特性依旧应用广泛,常见用于

  • 防止Redis缓存穿透。
  • 爬虫过滤,已抓取的url不再抓取。
  • 垃圾邮件过滤等。

相关推荐

Java面试题及答案总结(2025版)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Redis、Linux、SpringBoot、Spring、MySQ...

Java面试题及答案最全总结(2025春招版)

大家好,我是Java面试分享最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Spring...

Java面试题及答案最全总结(2025版持续更新)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...

蚂蚁金服面试题(附答案)建议收藏:经典面试题解析

前言最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答。点击上方“捡田螺的小男孩”,选择“设为星标”,干货不断满满1.用到分布式事务嘛?为什么用这种方案,有其他方案...

测试工程师面试必问的十道题目!全答上来的直接免试

最近参加运维工程师岗位的面试,笔者把自己遇到的和网友分享的一些常见的面试问答收集整理出来了,希望能对自己和对正在准备面试的同学提供一些参考。一、Mongodb熟悉吗,一般部署几台?部署过,没有深入研究...

10次面试9次被刷?吃透这500道大厂Java高频面试题后,怒斩offer

很多Java工程师的技术不错,但是一面试就头疼,10次面试9次都是被刷,过的那次还是去了家不知名的小公司。问题就在于:面试有技巧,而你不会把自己的能力表达给面试官。应届生:你该如何准备简历,面试项目和...

java高频面试题整理

【高频常见问题】1、事务的特性原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。一致性或可串性:事务的执行使得数据库从一种正确状态转换成另一种正确状态隔离性:在事务正确提交之前,不允许把该...

2025 年最全 Java 面试题,京东后端面试面经合集,答案整理

最近京东搞了个TGT计划,针对顶尖青年技术天才,直接宣布不设薪资上限。TGT计划面向范围包括2023年10月1日到2026年9月30日毕业的海内外本硕博毕业生。时间范围还...

idGenerator测评

工作中遇到需要生成随机数的需求,看了一个个人开发的基于雪花算法的工具,今天进行了一下测评(测试)。idGenerator项目地址见:https://github.com/yitter/IdGenera...

2024年开发者必备:MacBook Pro M1 Max深度体验与高效工作流

工作机器我使用的是一台16英寸的MacBookProM1Max。这台电脑的表现堪称惊人!它是我用过的最好的MacBook,短期内我不打算更换它。性能依然出色,即使在执行任务时也几乎听不到风扇的...

StackOverflow 2022 年度调查报告

一个月前,StackOverflow开启了2022年度开发者调查,历时一个半月,在6月22日,StackOverflow正式发布了2022年度开发者调查报告。本次报告StackO...

这可能是最全面的SpringDataMongoDB开发笔记

MongoDB数据库,在最近使用越来越广泛,在这里和Java的开发者一起分享一下在Java中使用Mongodb的相关笔记。希望大家喜欢。关于MongoDB查询指令,请看我的上一篇文章。SpringD...

Mac M2 本地部署ragflow

修改配置文件Dockerfile文件ARGNEED_MIRROR=1//开启国内镜像代理docker/.envREDIS_PORT=6380//本地redis端口冲突RAGFLOW_IMA...

别再傻傻分不清!localhost、127.0.0.1、本机IP,原来大有讲究!

调试接口死活连不上?部署服务队友访问不了?八成是localhost、127.0.0.1、本机IP用混了!这三个看似都指向“自己”的东西,差之毫厘谬以千里。搞不清它们,轻则调试抓狂,重则服务裸奔。loc...

我把 Mac mini 托管到机房了:一套打败云服务器的终极方案

我把我积灰的Macmini托管到机房了,有图有真相。没想到吧?一台在家吃灰的苹果电脑,帮我省了大钱!对,就是控制了自己的服务器,省了租用云服务器的钱,重要数据还全捏在自己手里,这感觉真爽。你可...

取消回复欢迎 发表评论: