当前位置: 首页 > article >正文

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

在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")); // trueSystem.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")); // trueSystem.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();// 检查所有位是否都为1for (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")); // trueSystem.out.println(filter.mightContain("world")); // 可能为false,也可能为误判的truefilter.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")); // trueSystem.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"

相关文章:

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

在Java中&#xff0c;要实现布隆过滤器&#xff08;Bloom Filter&#xff09;的方式有很多种&#xff0c;除了上一节中通过jedis包调用安装了布隆过滤器的redis外&#xff0c;还有以下几种常见的实现方式&#xff1a; 手写布隆过滤器 基于guava包实现 通过redis的bitmaps实现…...

【JAVA架构师成长之路】【电商系统实战】第12集:秒杀系统性能优化实战(CAN + Nginx + Sentinel)

30分钟课程&#xff1a;秒杀系统性能优化实战&#xff08;CDN Nginx Sentinel&#xff09; 课程目标 掌握静态资源 CDN 加速的配置与优化策略。通过 Nginx 实现负载均衡&#xff0c;提升系统横向扩展能力。使用 Sentinel 实现服务降级&#xff0c;保障核心链路稳定性。 课程…...

MySQL安装过程,创建数据库

window操作系统安装 存在两种安装方式&#xff1a; 1.安装包方式 2.压缩包方式 安装包方式 下载安装包 官网下载对应的安装包&#xff0c;根据需要下载对应的版本即可&#xff1a; 8.0&#xff1a;https://cdn.mysql.com//Downloads/MySQLInstaller/mysql-installer-comm…...

Linux上位机开发(开篇)

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

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

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

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_cycle_modules

声明在 src/core/ngx_module.h ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle);实现在 src/core/ngx_module.c ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle) {/** create a list of modules to be used for this cycle,* copy static modules to it*/cycle->modul…...

大彩串口屏开发 —— MODBUS通信

目 录 Modbus通信方式 1 使用变量与协议设置方式 2 使用LUA脚本方式 3 两者结合 Modbus通信 大彩串口屏可以采用三种方式实现与其它设备进行modbus通信和逻辑处理。 方式 1 使用变量与协议设置 步骤1 在协议设置里进行设置&#xff0c;包括开启modbus协议&#xff0c;屏做为主…...

React-异步队列执行方法useSyncQueue

1. 完整代码 import React, { useEffect, useRef } from react; import { useDebounceFn } from "ahooks"; // 队列任务类型 interface QueueTask {id: number | string;execute: () > PromiseLike<any>; } // 异步队列执行方法 function useSyncQueue(par…...

【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;每个…...

CentOS 9 系统安装 Docker

CentOS 9 系统安装 Docker 容器化技术如 Docker 已成为提升应用部署效率和管理便捷性的关键利器。你是否曾在使用 Docker 时遭遇安装繁琐、配置复杂的困扰&#xff1f;或者对如何在 CentOS 9 系统上标准化安装 Docker 充满好奇&#xff1f;今天&#xff0c;就让我们一同深入探索…...

pyqt联合designer的运用和设置

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

Linux(Centos 7.6)命令详解:zip

1.命令作用 打包和压缩(存档)文件(package and compress (archive) files)&#xff1b;该程序用于打包一组文件进行分发&#xff1b;存档文件&#xff1b;通过临时压缩未使用的文件或目录来节省磁盘空间&#xff1b;且压缩文件可以在Linux、Windows 和 macOS中轻松提取。 2.命…...

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…...

FPGA时序约束的几种方法

一,时钟约束 时钟约束是最基本的一个约束,因为FPGA工具是不知道你要跑多高的频率的,你必要要告诉工具你要跑的时钟频率。时钟约束也就是经常看到的Fmax,因为Fmax是针对“最差劲路径”,也就是说,如果该“最差劲路径”得到好成绩,那些不是最差劲的路径的成绩当然比…...

ClusterIP、Headless Service 和 NodePort 的比较

1. ClusterIP 1.1 定义 ClusterIP 是 Kubernetes 默认的 Service 类型&#xff0c;它会为 Service 分配一个虚拟的 IP 地址&#xff08;ClusterIP&#xff09;&#xff0c;这个 IP 是集群内部的虚拟地址&#xff0c;仅在集群内部有效。 1.2 工作原理 虚拟 IP&#xff1a;Clu…...

Ubuntu切换lowlatency内核

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

介绍一下Qt中的事件过滤

在 Qt 中&#xff0c;事件过滤&#xff08;Event Filter&#xff09;是一种强大的机制&#xff0c;它允许一个对象拦截并处理另一个对象接收到的事件。通过事件过滤&#xff0c;可以在事件到达目标对象之前对其进行监控和修改&#xff0c;这在很多场景下都非常有用&#xff0c;…...

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

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

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

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

快乐数 力扣202

一、题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&…...

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

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

Java基础面试题全集

1. Java语言基础 1.1 Java是什么&#xff1f; • Java是一种广泛使用的编程语言&#xff0c;最初由Sun Microsystems&#xff08;现为Oracle公司的一部分&#xff09;于1995年发布。它是一种面向对象的、基于类的、通用型的编程语言&#xff0c;旨在让应用程序“编写一次&…...

3.激活函数:神经网络中的非线性驱动器——大模型开发深度学习理论基础

激活函数在神经网络中扮演着至关重要的角色&#xff0c;它为模型引入非线性因素&#xff0c;使得网络能够拟合复杂的数据分布&#xff0c;从而实现高效的特征提取与预测。本文将从实际开发角度出发&#xff0c;介绍激活函数的基本概念、常见激活函数&#xff08;如 ReLU、GELU、…...

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…...

/***************************所有笔记汇总目录***************************/

文章分类目录 STM32CubeMX 01、STM32CubeMX——定时器&#xff08;普通模式和PWM模式&#xff09; 02、STM32CubeMX——串口&#xff08;HAL库&#xff09; 03、STM32CubeMX——(uart_IAP串口)简单示例 04、STM32CubeMX——ADC采集单通道&#xff0c;多通道&#xff0c;内部…...

Spring Framework中的IoC容器

控制反转(Inversion of Control, IoC)与面向切面编程(Aspect Oriented Programming, AOP)是Spring Framework中最重要的两个概念&#xff0c;本章会着重介绍前者。 2.1.1什么是IoC容器 使用XML来配置类实例 定义一个Java Bean类 在resources文件夹中定义一个beans.xml文件&a…...