使用SpringBoot角度讲解
布隆过滤器
布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,由计算机科学家 Burton Howard Bloom 于 1970 年提出,核心用途是快速判断 “一个元素是否在某个集合中”。它的本质是通过 “牺牲部分准确性”(允许极低的假阳性),换取 “极致的空间占用和查询速度”,特别适合处理海量数据场景下的高效过滤。
优点:空间效率极高(比哈希表节省 10-100 倍内存)、查询速度快(O (k),k 为哈希函数数量);
缺点:存在误判率(可能把不存在的元素判为存在)、不支持删除元素。
核心原理
布隆过滤器的底层是二进制数组(bit array) 和k 个独立的哈希函数,核心流程分为 “插入” 和 “查询” 两步。
- 数据结构组成
二进制数组(bit array):长度为m(单位:位 /bit),初始值全为 0;
k 个哈希函数:每个函数能将任意输入(数字、字符串等)映射为[0, m-1]范围内的整数索引。 插入元素流程(以 “user1” 为例)
① 将元素转换为字节数组(如 “user1”→[117, 115, 101, 114, 49]);
② 用 k 个哈希函数计算出 k 个索引(如i1, i2, ..., ik);③ 将数组中i1, i2, ..., ik位置的 0 改为 1。哈希函数是已经封装了的,直接使用,传入字节数组以后,每一次计算返回二进制数组索引序号,将对应位置标记为1
(简化示例:k=3,m=10,“user1” 的哈希索引为 2、5、7 → 数组 [0,0,1,0,0,1,0,1,0,0])- 查询元素流程(判断 “user1” 是否存在)
① 同样将元素转为字节数组,用 k 个哈希函数计算 k 个索引;
② 检查数组中这些索引的位:
若有任何一位为 0 → 元素一定不存在(100% 准确);
若所有位都为 1 → 元素可能存在(存在误判可能)。 - 误判原因:哈希碰撞
不同元素可能通过哈希函数计算出相同的 k 个索引,导致 “不存在的元素” 被误判为 “存在”。例如:“user2” 的哈希索引恰好也是 2、5、7 → 布隆过滤器会误判 “user2 存在”。
SpringBoot项目讲解
Java 21,JDK 22
导入Redisson
导入Redisson了就不用导入spring-boot-starter-data-reids了,已经包含了
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.5</version>
</dependency>
配置文件
spring:
application:
name: RBloomFilterDemo
data:
redis:
host: localhost
port: 6379
database: 2
bloom:
filter:
user:
expectedInsertions: 100000 # 预期元素数量(100000)
falseProbability: 0.0001 # 误判率(0.01%)配置类
@Configuration
public class RedissonConfig {
// 从配置文件读取参数
@Value("${bloom.filter.user.expectedInsertions}")
private long expectedInsertions; // 预期元素数量
@Value("${bloom.filter.user.falseProbability}")
private double falseProbability; // 误判率
/**
* 初始化用户ID布隆过滤器
* 存储用户ID(如"user1"、"user2"等字符串)
*/
@Bean(name="userRBloomFilter")
public RBloomFilter<String> userRBloomFilter(RedissonClient redissonClient) {
RBloomFilter<String> bloomFilter=redissonClient.getBloomFilter("userBloomFilter_RedisKey");
bloomFilter.tryInit(expectedInsertions,falseProbability);
return bloomFilter;
}
}
RBloomFilterbloomFilter=redissonClient.getBloomFilter("userBloomFilter_RedisKey");是内部将布隆布过滤器需要使用到的二进制数组,增加到一共自定义key为userBloomFilter_RedisKey的键值里面,没有则创建,有则下一次直接使用
实现类
@Service
public class userService {
@Autowired
private RBloomFilter<String> userBloomFilter;
public void addUser(String userId) {
System.out.println("已经添加用户在布隆过滤器" + userId);
userBloomFilter.add(userId);
}
public String getUser(String userId) {
if(userBloomFilter.contains(userId)){
return userId+"用户存在";
}
return userId+"用户不存在";
}
}
userBloomFilter.add(userId);内部方法,大概将userId转为字节数组,再根据字节数组使用对应哈希函数计算索引
userBloomFilter.contains(userId)判断是否存在,一定可以判断不存在的用户,但是可能会将’不存在‘的用户判断为‘存在’
,因为哈希可能冲突
测试类
@SpringBootTest
class RBloomFilterDemoApplicationTests {
@Autowired
private RBloomFilter<String> userRBloomFilter;
@Autowired
private userService userService;
@BeforeEach
public void initData(){
List<String> ids = new ArrayList<>(1000);
for (int i = 1; i <= 1000; i++) {
ids.add("user" + i);
}
for (String id : ids) {
userRBloomFilter.add(id);
}
}
@Test
void contextLoads() {
System.out.println(userService.getUser("user100"));
System.out.println(userService.getUser("user100000"));
userService.addUser("user100000");
System.out.println(userService.getUser("user100000"));
}
}
initData预先写个方法模拟数据库返回id或者其它字段来储存在布隆过滤器
下一次运行测试,这里的user100000之前被记录过了,所以这一次直接判断存在



评论已关闭