【redis】布隆过滤器的Java实现

news2025/3/10 4:54:00

在Java中,要实现布隆过滤器(Bloom Filter)的方式有很多种,除了上一节中通过jedis包调用安装了布隆过滤器的redis外,还有以下几种常见的实现方式:

  • 手写布隆过滤器

  • 基于guava包实现

  • 通过redis的bitmaps实现

  • 基于redisson包实现

手写布隆过滤器

手写一个布隆过滤器的源代码:

package com.morris.redis.demo.bloomfilter;

import java.util.BitSet;

/**
 * 手写一个布隆过滤器
 */
public class MyBloomFilter {
    // 位数组的大小
    private static final int DEFAULT_SIZE = 2 << 24;
    // 哈希函数种子
    private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 61};
    // 位数组
    private final BitSet bits = new BitSet(DEFAULT_SIZE);
    // 哈希函数数组
    private final SimpleHash[] func = new SimpleHash[seeds.length];

    // 初始化哈希函数
    public MyBloomFilter() {
        for (int i = 0; i < seeds.length; i++) {
            func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
        }
    }

    // 添加元素
    public void add(String value) {
        for (SimpleHash f : func) {
            bits.set(f.hash(value), true);
        }
    }

    // 判断元素是否存在(可能误判)
    public boolean contains(String value) {
        boolean ret = true;
        for (SimpleHash f : func) {
            ret = ret && bits.get(f.hash(value));
            if (!ret) return false;
        }
        return true;
    }

    // 静态内部类,实现简单的哈希函数
    private static class SimpleHash {
        private final int cap;
        private final int seed;

        public SimpleHash(int cap, int seed) {
            this.cap = cap;
            this.seed = seed;
        }

        public int hash(String value) {
            int h = 0;
            int len = value.length();
            for (int i = 0;i < len;i++){
                h = seed * h + value.charAt(i);
            }
            return (cap - 1) & h;
        }
    }

}

手写一个布隆过滤器的使用:

package com.morris.redis.demo.bloomfilter;

/**
 * 手写一个布隆过滤器的使用
 */
public class MyBloomFilterDemo {

    public static void main(String[] args) {

        MyBloomFilter filter = new MyBloomFilter();
        filter.add("hello");

        System.out.println(filter.contains("hello")); // true
        System.out.println(filter.contains("world")); // 可能为false,也可能为误判的true
    }
}

基于guava包实现

先添加maven依赖:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.3.1-jre</version>
</dependency>

guava包中布隆过滤器的使用源码如下:

package com.morris.redis.demo.bloomfilter;

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

import java.nio.charset.Charset;

/**
 * guava包中布隆过滤器的使用
 */
public class GuavaBloomFilterDemo {
    
    public static void main(String[] args) {
        // 创建布隆过滤器对象
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), 10000, 0.001);

        bloomFilter.put("10080");
        bloomFilter.put("10081");
        bloomFilter.put("10082");
        bloomFilter.put("10083");
        bloomFilter.put("10084");
        bloomFilter.put("10085");
        bloomFilter.put("10086");

        System.out.println(bloomFilter.mightContain("10086")); // true
        System.out.println(bloomFilter.mightContain("10089")); // false
    }
}

通过redis的bitmaps实现

使用redis的bitmaps实现布隆过滤器源码如下:

package com.morris.redis.demo.bloomfilter;

import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 使用redis的bitmaps实现布隆过滤器
 */
public class RedisBloomFilter {
    private final Jedis jedis;
    private final String redisKey;
    private final int bitArraySize;
    private final int hashCount;
    private final int[] hashSeeds;

    /**
     * 构造布隆过滤器
     *
     * @param redisHost         Redis主机地址
     * @param redisPort         Redis端口
     * @param redisKey          存储位数组的Redis键
     * @param expectedElements  预期元素数量
     * @param falsePositiveRate 可接受的误判率(0.0到1.0之间)
     */
    public RedisBloomFilter(String redisHost, int redisPort, String redisKey,
                            int expectedElements, double falsePositiveRate) {
        this.jedis = new Jedis(redisHost, redisPort);
        this.redisKey = redisKey;
        this.bitArraySize = calculateOptimalSize(expectedElements, falsePositiveRate);
        this.hashCount = calculateOptimalHashCount(bitArraySize, expectedElements);
        this.hashSeeds = generateHashSeeds(hashCount);
    }

    // 计算最优位数组大小
    private int calculateOptimalSize(int n, double p) {
        return (int) Math.ceil(-n * Math.log(p) / (Math.log(2) * Math.log(2)));
    }

    // 计算最优哈希函数数量
    private int calculateOptimalHashCount(int m, int n) {
        return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
    }

    // 生成哈希种子(简单实现,实际可能需要更复杂的种子)
    private int[] generateHashSeeds(int count) {
        int[] seeds = new int[count];
        for (int i = 0; i < count; i++) {
            seeds[i] = 31 * (i + 1); // 使用质数生成种子
        }
        return seeds;
    }

    /**
     * 添加元素到布隆过滤器
     *
     * @param element 要添加的元素
     */
    public void add(String element) {
        byte[] bytes = element.getBytes(StandardCharsets.UTF_8);
        try (Pipeline pipeline = jedis.pipelined()) {
            for (int seed : hashSeeds) {
                long hash = murmurHash(bytes, seed);
                long bitOffset = (hash & Long.MAX_VALUE) % bitArraySize;
                pipeline.setbit(redisKey, bitOffset, true);
            }
            pipeline.sync();
        }
    }

    /**
     * 检查元素是否存在
     *
     * @param element 要检查的元素
     * @return true表示可能存在,false表示一定不存在
     */
    public boolean mightContain(String element) {
        byte[] bytes = element.getBytes(StandardCharsets.UTF_8);
        List<Long> offsets = new ArrayList<>(hashSeeds.length);

        // 计算所有位偏移量
        for (int seed : hashSeeds) {
            long hash = murmurHash(bytes, seed);
            long bitOffset = (hash & Long.MAX_VALUE) % bitArraySize;
            offsets.add(bitOffset);
        }

        // 使用管道批量查询
        try (Pipeline pipeline = jedis.pipelined()) {
            List<Response<Boolean>> responses = new ArrayList<>();
            for (Long offset : offsets) {
                responses.add(pipeline.getbit(redisKey, offset));
            }
            pipeline.sync();

            // 检查所有位是否都为1
            for (Response<Boolean> response : responses) {
                if (!response.get()) {
                    return false;
                }
            }
            return true;
        }
    }

    // 使用MurmurHash3算法计算哈希值
    private long murmurHash(byte[] data, int seed) {
        HashFunction hashFunction = Hashing.murmur3_128(seed);
        HashCode hashCode = hashFunction.hashBytes(data);
        return hashCode.asLong();
    }

    /**
     * 关闭Redis连接
     */
    public void close() {
        jedis.close();
    }

}

使用redis的bitmaps实现布隆过滤器的使用:

package com.morris.redis.demo.bloomfilter;


/**
 * 使用redis的bitmaps实现布隆过滤器 的使用
 */
public class RedisBloomFilterDemo {

    public static void main(String[] args) {
        // 示例用法
        RedisBloomFilter filter = new RedisBloomFilter("localhost", 6379, "myBloomFilter", 1000000, 0.01);

        filter.add("hello");

        System.out.println(filter.mightContain("hello")); // true
        System.out.println(filter.mightContain("world")); // 可能为false,也可能为误判的true
        
        filter.close();
    }
}

基于redisson包实现

先添加maven依赖:

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

Redisson包中布隆过滤器的使用:

package com.morris.redis.demo.bloomfilter;

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

/**
 * redisson包中布隆过滤器的使用
 */
public class RedissonBloomFilterDemo {
    
    public static void main(String[] args) {
        // 配置Redisson客户端
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://127.0.0.1:6379");
        
        // 创建Redisson客户端实例
        RedissonClient redisson = Redisson.create(config);
        
        // 获取或创建布隆过滤器
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("userEmails");
        
        // 初始化布隆过滤器(重要!)
        // expectedInsertions: 预期插入数量
        // falseProbability: 误判率(0.0-1.0)
        bloomFilter.tryInit(1000000L, 0.01);
        
        // 添加元素
        bloomFilter.add("user1@example.com");
        bloomFilter.add("user2@example.com");
        
        // 检查元素是否存在
        System.out.println(bloomFilter.contains("user1@example.com")); // true
        System.out.println(bloomFilter.contains("unknown@test.com"));  // false
        
        // 关闭客户端
        redisson.shutdown();
    }
}

布隆过滤器的配置会在redis中生成一个key:

127.0.0.1:6379> hgetall {userEmails}:config
1) "size"
2) "9585058"
3) "hashIterations"
4) "7"
5) "expectedInsertions"
6) "1000000"
7) "falseProbability"
8) "0.01"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2312486.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux上位机开发(开篇)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 传统的上位机开发&#xff0c;一般都是默认pc软件开发。既然是pc软件&#xff0c;一般来说都是基于windows平台开发。开放的框架&#xff0c;无非是…

算法005——有效三角形个数

力扣——有效三角形个数点击链接跳转 判断三条边是否能组成三角形&#xff0c;大家第一时间想到的就是两边之和大于第三边 但是运用这个方法&#xff0c;我们需要判断三次&#xff0c;有一个更简单的方法&#xff0c;只需要判断一次 因为 C 已经是三边之中最大的了&#xff…

【STM32】江科大STM32学习笔记汇总(已完结)

00. 目录 文章目录 00. 目录01. STM32学习笔记汇总02. 相关资料下载03. 打赏04. 附录 01. STM32学习笔记汇总 【STM32】STM32学习笔记-课程简介(01) 【STM32】STM32学习笔记-STM32简介(02) 【STM32】STM32学习笔记-软件安装(03) 【STM32】STM32学习笔记-新建工程(04) 【ST…

【Python编程】高性能Python Web服务部署架构解析

一、FastAPI 与 Uvicorn/Gunicorn 的协同 1. 开发环境&#xff1a;Uvicorn 直接驱动 作用&#xff1a;Uvicorn 作为 ASGI 服务器&#xff0c;原生支持 FastAPI 的异步特性&#xff0c;提供热重载&#xff08;--reload&#xff09;和高效异步请求处理。 启动命令&#xff1a; u…

OSPF的各种LSA类型,多区域及特殊区域

一、OSPF的LSA类型 OSPF&#xff08;开放最短路径优先&#xff09;协议使用多种LSA&#xff08;链路状态通告&#xff09;类型来交换网络拓扑信息。以下是主要LSA类型的详细分类及其作用&#xff1a; 1. Type 1 LSA&#xff08;路由器LSA&#xff09; 生成者&#xff1a;每个…

pyqt联合designer的运用和设置

PyQt Designer 简介 PyQt Designer 是一个用于创建和设计 PyQt 应用程序用户界面的可视化工具。它允许用户通过拖放方式添加和排列各种控件,如按钮、文本框、滑块等,并设置它们的属性和样式,从而快速构建出美观且功能完整的 UI 界面。 Windows版本:【免费】安装包别管啊啊…

vulnhub靶场之【digitalworld.local系列】的snakeoil靶机

前言 靶机&#xff1a;digitalworld.local-snakeoil&#xff0c;IP地址为192.168.10.11 攻击&#xff1a;kali&#xff0c;IP地址为192.168.10.6 kali采用VMware虚拟机&#xff0c;靶机选择使用VMware打开文件&#xff0c;都选择桥接网络 这里官方给的有两种方式&#xff0…

Ubuntu切换lowlatency内核

文章目录 一. 前言二. 开发环境三. 具体操作 一. 前言 低延迟内核&#xff08;Lowlatency Kernel&#xff09; 旨在为需要低延迟响应的应用程序设计的内核版本。Linux-lowlatency特别适合音频处理、实时计算、游戏和其他需要及时响应的实时任务。其主要特点是优化了中断处理、调…

C++修炼之路:初识C++

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 引言 …

微信小程序+SpringBoot的单词学习小程序平台(程序+论文+讲解+安装+修改+售后)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统背景 &#xff08;一&#xff09;社会需求背景 在全球化的大背景下&#xff0c;英语作为国际…

VBA 数据库同一表的当前行与其他行的主键重复判断实现方案1

目的&#xff0c;判断是否主键重复&#xff0c;不重复则登录新数据&#xff0c;重复则不登录。 定义类型&#xff1a; DataRecord   tableName 表名   rowNumber 行号   columnName 列名   data 数据 想要实现的代码逻辑如下&#xff1a; 模拟数据库的登录过程。假设…

VUE的第二天

1. 指令修饰符 1.1什么是指令修饰符&#xff1f; ​ 所谓指令修饰符就是通过“.”指明一些指令后缀 不同的后缀封装了不同的处理操作 —> 简化代码 1.2按键修饰符 keyup.enter —>当点击enter键的时候才触发 代码演示&#xff1a; <div id"app"><…

Element Plus中的树组件的具体用法(持续更新!)

const defaultProps {//子树为节点对象的childrenchildren: children,//节点标签为节点对象的name属性label: name, } 属性 以下是树组件中的常用属性以及作用&#xff1a; data&#xff1a;展示的数据&#xff08;数据源&#xff09; show-checkbox&#xff1a;节点是否可…

尚硅谷爬虫note14

一、scrapy scrapy&#xff1a;为爬取网站数据是&#xff0c;提取结构性数据而编写的应用框架 1. 安装 pip install scrapy 或者&#xff0c;国内源安装 pip install scrapy -i https&#xff1a;//pypi.douban.com/simple 2. 报错 报错1&#xff09;building ‘twisted.te…

永洪科技深度分析实战,零售企业的销量预测

随着人工智能技术的不断发展&#xff0c;智能预测已经成为各个领域的重要应用之一。现在&#xff0c;智能预测技术已经广泛应用于金融、零售、医疗、能源等领域&#xff0c;为企业和个人提供决策支持。 智能预测技术通过分析大量的数据&#xff0c;利用机器学习和深度学习算法…

2.数据结构-栈和队列

数据结构-栈和队列 2.1栈2.1.1栈的表示和实现2.1.2栈的应用举例数制转换括号匹配检验迷宫给求解表达式求值 2.1栈 栈是限定仅在表尾进行插入或删除操作的线性表&#xff0c;因此&#xff0c;对栈来说&#xff0c;表尾端有其特殊含义&#xff0c;称为栈顶&#xff08;top&#x…

android studio开发文档

android基本样式 1.文本 2.设置文本大小 3.字体颜色 背景 资源文件 xml’引用资源文件 4.视图宽高 5.间距 6.对齐方式 常用布局 1.linearLayout线性布局 2.相对布局 RelativeLayout 3.网格布局GridLayout 4.scrollview滚动视图 Button 点击事件与长按事件 长按 按钮禁用与…

Java 对象与类——从 C++ 到 Java

文章目录 面向对象程序设计概述使用预定义类用户自定义类静态字段与静态方法方法参数对象构造包JAR 文件文档注释类设计技巧 面向对象程序设计概述 面向对象程序设计&#xff08;OOP&#xff09;在 20 世纪 70 年代出现&#xff0c;是当今主流编程范型&#xff0c;Java 是面向…

一篇文章讲解清楚ARM9芯片启动流程

SAM9X60 ARM9 boot启动流程关键词介绍&#xff1a; 第一级bootloader - 也叫boot ROM&#xff0c;是集成在MPU内部的ROM里面 它的主要功能是执行对MPU的基本初始化和配置&#xff0c;查找并将第二级bootloader从外部NVM中读取出来并放到MPU内部的SRAM. 可以让MPU强制停留在第一…

【2025】Electron + React 架构筑基——从零到一的跨平台开发

引言 源代码仓库&#xff1a; Github仓库【electron_git】 你是否厌倦了在命令行中反复输入git status&#xff0c;却依然无法直观看到文件变化&#xff1f; 是否羡慕VS Code的丝滑Git集成&#xff0c;却苦恼于无法定制自己的专属工具&#xff1f; 本专栏将为你打开一扇新的…