作者逆境不可逃技术永无止境希望我的内容可以帮助到你大家吼 ! 我是 逆境不可逃 今天给大家带来文章《“会说谎” 的布隆过滤器凭什么称霸高并发》本文章属于栏目 后端新手谈布隆过滤器Bloom Filter是计算机科学中最巧妙、最实用的数据结构之一它用极小的内存解决了 一个元素是否在海量集合中 的判断问题。虽然它有 可能说谎 的小缺点但在互联网海量数据场景下它的优势无可替代。一、用生活例子秒懂布隆过滤器想象你是一家大型图书馆的管理员每天有上万人来问这本书你们馆有吗传统方法你需要翻遍几十万本书的目录卡片速度极慢而且要占用巨大的柜子存放所有卡片。布隆过滤器方法你提前做了一张巨大的白纸二进制数组和3 支不同颜色的笔哈希函数。当图书馆新增一本书时你用 3 支笔分别在白纸上画 3 个不同位置的黑点当有人问某本书有没有时你同样用 3 支笔在白纸上找那 3 个位置如果有任何一个位置是空白说明这本书绝对没有如果3 个位置都是黑点说明这本书可能有因为可能其他书也刚好在这 3 个位置画了点这就是布隆过滤器的核心思想用多个哈希函数将元素映射到二进制数组的多个位置通过检查这些位置是否都被标记来判断元素是否存在。溜溜溜二、核心原理详解1. 基本组成布隆过滤器由两部分组成一个很长的二进制数组bit 数组初始时所有位都为 0k 个独立的哈希函数将输入的元素映射到数组的不同位置2. 两个核心操作1添加元素将元素输入 k 个哈希函数得到 k 个不同的数组索引将数组中这 k 个索引位置的 bit 值都设置为 12查询元素同样将元素输入 k 个哈希函数得到 k 个索引检查数组中这 k 个位置的 bit 值只要有一个位置是 0 → 元素一定不存在所有位置都是 1 → 元素可能存在3. 为什么会有误判当不同的元素经过哈希函数计算后恰好映射到了相同的 k 个位置时就会发生误判。例如元素 A 映射到位置 1、3、5元素 B 也恰好映射到位置 1、3、5。当添加了 A 之后查询 B 时布隆过滤器会错误地认为 B 也存在。4. 关键特性✅不会漏判说不存在的一定不存在❌可能误判说存在的可能不存在空间效率极高10 亿个元素只需要几百 MB 内存⚡时间复杂度极低添加和查询都是 O (k)k 是哈希函数个数不支持删除元素删除会影响其他元素的判断改进版有计数布隆过滤器5. 误判率计算布隆过滤器的误判率由三个参数决定m二进制数组的长度bit 数n预计要存储的元素个数k哈希函数的个数最优哈希函数个数k ≈ 0.7 * (m/n)近似误判率公式P ≈ (1 - e^(-kn/m))^k常用参数参考误判率每个元素需要的 bit 数最优哈希函数个数1%9.670.1%14.4100.01%19.2140.001%2417三、Java 实现布隆过滤器1. 手动实现简单版理解原理用这个版本适合学习原理不建议在生产环境使用。import java.util.BitSet; public class SimpleBloomFilter { // 二进制数组的大小 private static final int DEFAULT_SIZE 2 24; // 16MB // 哈希函数的种子保证不同哈希函数的独立性 private static final int[] SEEDS {3, 5, 7, 11, 13, 17, 19, 23}; // 二进制数组 private final BitSet bits new BitSet(DEFAULT_SIZE); // 哈希函数数组 private final HashFunction[] functions new HashFunction[SEEDS.length]; // 初始化哈希函数 public SimpleBloomFilter() { for (int i 0; i SEEDS.length; i) { functions[i] new HashFunction(DEFAULT_SIZE, SEEDS[i]); } } // 添加元素 public void add(String value) { for (HashFunction f : functions) { bits.set(f.hash(value), true); } } // 查询元素是否存在 public boolean contains(String value) { if (value null) { return false; } boolean result true; for (HashFunction f : functions) { // 只要有一个位置为0就返回false result result bits.get(f.hash(value)); if (!result) { break; } } return result; } // 哈希函数内部类 private static class HashFunction { private final int size; private final int seed; public HashFunction(int size, int seed) { this.size size; this.seed seed; } // 简单但有效的哈希函数 public int hash(String value) { int result 0; int len value.length(); for (int i 0; i len; i) { result seed * result value.charAt(i); } // 确保结果在数组范围内 return (size - 1) result; } } // 测试 public static void main(String[] args) { SimpleBloomFilter filter new SimpleBloomFilter(); // 添加10000个元素 for (int i 0; i 10000; i) { filter.add(user i); } // 测试存在的元素 System.out.println(filter.contains(user9999)); // true System.out.println(filter.contains(user0)); // true // 测试不存在的元素 int falsePositive 0; for (int i 10000; i 20000; i) { if (filter.contains(user i)) { falsePositive; } } System.out.println(误判数 falsePositive); System.out.println(误判率 (falsePositive / 10000.0)); } }2. 生产环境使用Google Guava 布隆过滤器实际项目中强烈推荐使用 Google Guava 库提供的布隆过滤器它经过了严格的测试和优化。第一步添加 Maven 依赖dependency groupIdcom.google.guava/groupId artifactIdguava/artifactId version32.1.3-jre/version /dependency第二步基本使用import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import java.nio.charset.StandardCharsets; public class GuavaBloomFilterDemo { public static void main(String[] args) { // 预计插入100万个元素期望误判率为0.01% int expectedInsertions 1000000; double fpp 0.0001; // 0.01% // 创建布隆过滤器 BloomFilterString bloomFilter BloomFilter.create( Funnels.stringFunnel(StandardCharsets.UTF_8), expectedInsertions, fpp ); // 添加元素 bloomFilter.put(user1); bloomFilter.put(user2); bloomFilter.put(user3); // 查询元素 System.out.println(bloomFilter.mightContain(user1)); // true System.out.println(bloomFilter.mightContain(user4)); // false // 批量添加 for (int i 0; i 1000000; i) { bloomFilter.put(product i); } // 测试误判率 int falsePositive 0; for (int i 1000000; i 2000000; i) { if (bloomFilter.mightContain(product i)) { falsePositive; } } System.out.println(实际误判数 falsePositive); System.out.println(实际误判率 (falsePositive / 1000000.0)); } }第三步高级特性// 合并两个布隆过滤器必须有相同的配置 BloomFilterString filter1 BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1000); BloomFilterString filter2 BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1000); filter1.put(a); filter2.put(b); filter1.putAll(filter2); // 现在filter1包含a和b // 复制布隆过滤器 BloomFilterString copy filter1.copy(); // 估算布隆过滤器中元素的数量 long approximateElementCount filter1.approximateElementCount();四、布隆过滤器的经典应用场景1. 解决缓存穿透问题问题黑客故意查询数据库中不存在的 key导致请求绕过缓存直接打到数据库数据库压力剧增甚至宕机。解决方案将数据库中所有存在的 key 预先加载到布隆过滤器中当有查询请求时先经过布隆过滤器如果布隆过滤器说不存在 → 直接返回不访问缓存和数据库如果布隆过滤器说可能存在 → 再访问缓存缓存未命中再访问数据库代码示例Service public class UserService { Autowired private UserMapper userMapper; Autowired private RedisTemplateString, User redisTemplate; private BloomFilterString userIdBloomFilter; // 项目启动时初始化布隆过滤器 PostConstruct public void initBloomFilter() { ListLong allUserIds userMapper.getAllUserIds(); userIdBloomFilter BloomFilter.create( Funnels.stringFunnel(StandardCharsets.UTF_8), allUserIds.size(), 0.001 ); for (Long userId : allUserIds) { userIdBloomFilter.put(userId.toString()); } } public User getUserById(Long userId) { String key user: userId; // 先经过布隆过滤器 if (!userIdBloomFilter.mightContain(userId.toString())) { return null; // 直接返回防止缓存穿透 } // 再查缓存 User user redisTemplate.opsForValue().get(key); if (user ! null) { return user; } // 最后查数据库 user userMapper.selectById(userId); if (user ! null) { redisTemplate.opsForValue().set(key, user, Duration.ofHours(1)); } return user; } }2. 爬虫 URL 去重问题爬虫在爬取网站时会遇到大量重复的 URL如果不进行去重会重复爬取相同页面浪费资源和时间。解决方案使用布隆过滤器存储已经爬取过的 URL每次发现新 URL 时先检查布隆过滤器如果不存在 → 加入爬取队列并添加到布隆过滤器如果存在 → 跳过优势可以处理数十亿级别的 URL 去重内存占用极小。3. 垃圾邮件过滤问题每天有数十亿封垃圾邮件发送需要快速判断发件人是否在黑名单中。解决方案将所有垃圾邮件发件人的邮箱地址存入布隆过滤器收到新邮件时先检查发件人是否在布隆过滤器中如果不存在 → 正常投递如果存在 → 进一步检查如内容分析4. 黑名单系统问题大型网站需要维护一个庞大的 IP 黑名单或手机号黑名单快速判断请求是否来自黑名单。解决方案将所有黑名单 IP / 手机号存入布隆过滤器每次请求时先检查布隆过滤器如果不存在 → 正常处理如果存在 → 拒绝请求或进行更严格的验证5. 数据库查询优化问题在分布式数据库中查询一个不存在的记录会遍历所有分片浪费资源。解决方案为每个分片维护一个布隆过滤器存储该分片的所有主键查询时先检查对应分片的布隆过滤器如果不存在 → 跳过该分片如果存在 → 再查询该分片6. 推荐系统去重问题推荐系统需要避免向用户推荐已经看过的内容。解决方案为每个用户维护一个布隆过滤器存储该用户已经看过的内容 ID生成推荐列表时过滤掉布隆过滤器中存在的内容五、布隆过滤器的优缺点与注意事项优点空间效率极高比哈希表节省 90% 以上的空间查询和添加速度极快时间复杂度为 O (k)与数据量无关无冲突不需要处理哈希冲突易于实现原理简单代码量少缺点存在误判率不能 100% 准确判断元素是否存在不支持删除元素普通布隆过滤器无法删除元素需要提前预估数据量如果实际数据量超过预估误判率会急剧上升注意事项合理设置参数根据业务需求选择合适的误判率和数据量定期重建当数据量增长超过预估时需要重建布隆过滤器处理误判对于布隆过滤器返回 存在 的结果需要进行二次验证不要存储敏感数据布隆过滤器无法直接获取存储的元素但可以通过暴力破解推断六、布隆过滤器的变种计数布隆过滤器Counting Bloom Filter将每个 bit 位改为计数器支持删除操作但会增加空间占用布谷鸟过滤器Cuckoo Filter支持删除操作误判率更低查询速度更快分层布隆过滤器用于处理动态增长的数据分布式布隆过滤器在分布式系统中使用如 Redis 布隆过滤器七、Redis 布隆过滤器生产环境首选在分布式系统中通常使用 Redis 提供的布隆过滤器功能Redis 4.0 通过 RedisBloom 模块支持。Redis 布隆过滤器基本命令# 创建布隆过滤器 BF.RESERVE user_filter 0.001 1000000 # 添加元素 BF.ADD user_filter user1 BF.ADD user_filter user2 # 批量添加元素 BF.MADD user_filter user3 user4 user5 # 查询元素是否存在 BF.EXISTS user_filter user1 BF.EXISTS user_filter user6 # 批量查询 BF.MEXISTS user_filter user1 user2 user6Java 中使用 Redis 布隆过滤器import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.List; Component public class RedisBloomFilter { private final RedisTemplateString, Object redisTemplate; public RedisBloomFilter(RedisTemplateString, Object redisTemplate) { this.redisTemplate redisTemplate; } /** * 创建布隆过滤器 * param key 过滤器key * param errorRate 误判率 * param capacity 容量 */ public void createFilter(String key, double errorRate, long capacity) { redisTemplate.execute((connection) - { connection.execute(BF.RESERVE, key.getBytes(), String.valueOf(errorRate).getBytes(), String.valueOf(capacity).getBytes()); return null; }); } /** * 添加元素 */ public boolean add(String key, String value) { Boolean result redisTemplate.execute((connection) - connection.execute(BF.ADD, key.getBytes(), value.getBytes())); return Boolean.TRUE.equals(result); } /** * 查询元素是否存在 */ public boolean exists(String key, String value) { Boolean result redisTemplate.execute((connection) - connection.execute(BF.EXISTS, key.getBytes(), value.getBytes())); return Boolean.TRUE.equals(result); } }总结布隆过滤器是一种用准确性换空间和时间的数据结构它的核心价值在于快速判断元素不存在。在处理海量数据时它能极大地提升系统性能降低资源消耗。记住布隆过滤器的黄金法则它说不存在的一定不存在它说存在的可能存在。只要你能接受这个小小的缺点布隆过滤器就能成为你解决海量数据问题的利器。
“会说谎” 的布隆过滤器,凭什么称霸高并发?
作者逆境不可逃技术永无止境希望我的内容可以帮助到你大家吼 ! 我是 逆境不可逃 今天给大家带来文章《“会说谎” 的布隆过滤器凭什么称霸高并发》本文章属于栏目 后端新手谈布隆过滤器Bloom Filter是计算机科学中最巧妙、最实用的数据结构之一它用极小的内存解决了 一个元素是否在海量集合中 的判断问题。虽然它有 可能说谎 的小缺点但在互联网海量数据场景下它的优势无可替代。一、用生活例子秒懂布隆过滤器想象你是一家大型图书馆的管理员每天有上万人来问这本书你们馆有吗传统方法你需要翻遍几十万本书的目录卡片速度极慢而且要占用巨大的柜子存放所有卡片。布隆过滤器方法你提前做了一张巨大的白纸二进制数组和3 支不同颜色的笔哈希函数。当图书馆新增一本书时你用 3 支笔分别在白纸上画 3 个不同位置的黑点当有人问某本书有没有时你同样用 3 支笔在白纸上找那 3 个位置如果有任何一个位置是空白说明这本书绝对没有如果3 个位置都是黑点说明这本书可能有因为可能其他书也刚好在这 3 个位置画了点这就是布隆过滤器的核心思想用多个哈希函数将元素映射到二进制数组的多个位置通过检查这些位置是否都被标记来判断元素是否存在。溜溜溜二、核心原理详解1. 基本组成布隆过滤器由两部分组成一个很长的二进制数组bit 数组初始时所有位都为 0k 个独立的哈希函数将输入的元素映射到数组的不同位置2. 两个核心操作1添加元素将元素输入 k 个哈希函数得到 k 个不同的数组索引将数组中这 k 个索引位置的 bit 值都设置为 12查询元素同样将元素输入 k 个哈希函数得到 k 个索引检查数组中这 k 个位置的 bit 值只要有一个位置是 0 → 元素一定不存在所有位置都是 1 → 元素可能存在3. 为什么会有误判当不同的元素经过哈希函数计算后恰好映射到了相同的 k 个位置时就会发生误判。例如元素 A 映射到位置 1、3、5元素 B 也恰好映射到位置 1、3、5。当添加了 A 之后查询 B 时布隆过滤器会错误地认为 B 也存在。4. 关键特性✅不会漏判说不存在的一定不存在❌可能误判说存在的可能不存在空间效率极高10 亿个元素只需要几百 MB 内存⚡时间复杂度极低添加和查询都是 O (k)k 是哈希函数个数不支持删除元素删除会影响其他元素的判断改进版有计数布隆过滤器5. 误判率计算布隆过滤器的误判率由三个参数决定m二进制数组的长度bit 数n预计要存储的元素个数k哈希函数的个数最优哈希函数个数k ≈ 0.7 * (m/n)近似误判率公式P ≈ (1 - e^(-kn/m))^k常用参数参考误判率每个元素需要的 bit 数最优哈希函数个数1%9.670.1%14.4100.01%19.2140.001%2417三、Java 实现布隆过滤器1. 手动实现简单版理解原理用这个版本适合学习原理不建议在生产环境使用。import java.util.BitSet; public class SimpleBloomFilter { // 二进制数组的大小 private static final int DEFAULT_SIZE 2 24; // 16MB // 哈希函数的种子保证不同哈希函数的独立性 private static final int[] SEEDS {3, 5, 7, 11, 13, 17, 19, 23}; // 二进制数组 private final BitSet bits new BitSet(DEFAULT_SIZE); // 哈希函数数组 private final HashFunction[] functions new HashFunction[SEEDS.length]; // 初始化哈希函数 public SimpleBloomFilter() { for (int i 0; i SEEDS.length; i) { functions[i] new HashFunction(DEFAULT_SIZE, SEEDS[i]); } } // 添加元素 public void add(String value) { for (HashFunction f : functions) { bits.set(f.hash(value), true); } } // 查询元素是否存在 public boolean contains(String value) { if (value null) { return false; } boolean result true; for (HashFunction f : functions) { // 只要有一个位置为0就返回false result result bits.get(f.hash(value)); if (!result) { break; } } return result; } // 哈希函数内部类 private static class HashFunction { private final int size; private final int seed; public HashFunction(int size, int seed) { this.size size; this.seed seed; } // 简单但有效的哈希函数 public int hash(String value) { int result 0; int len value.length(); for (int i 0; i len; i) { result seed * result value.charAt(i); } // 确保结果在数组范围内 return (size - 1) result; } } // 测试 public static void main(String[] args) { SimpleBloomFilter filter new SimpleBloomFilter(); // 添加10000个元素 for (int i 0; i 10000; i) { filter.add(user i); } // 测试存在的元素 System.out.println(filter.contains(user9999)); // true System.out.println(filter.contains(user0)); // true // 测试不存在的元素 int falsePositive 0; for (int i 10000; i 20000; i) { if (filter.contains(user i)) { falsePositive; } } System.out.println(误判数 falsePositive); System.out.println(误判率 (falsePositive / 10000.0)); } }2. 生产环境使用Google Guava 布隆过滤器实际项目中强烈推荐使用 Google Guava 库提供的布隆过滤器它经过了严格的测试和优化。第一步添加 Maven 依赖dependency groupIdcom.google.guava/groupId artifactIdguava/artifactId version32.1.3-jre/version /dependency第二步基本使用import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import java.nio.charset.StandardCharsets; public class GuavaBloomFilterDemo { public static void main(String[] args) { // 预计插入100万个元素期望误判率为0.01% int expectedInsertions 1000000; double fpp 0.0001; // 0.01% // 创建布隆过滤器 BloomFilterString bloomFilter BloomFilter.create( Funnels.stringFunnel(StandardCharsets.UTF_8), expectedInsertions, fpp ); // 添加元素 bloomFilter.put(user1); bloomFilter.put(user2); bloomFilter.put(user3); // 查询元素 System.out.println(bloomFilter.mightContain(user1)); // true System.out.println(bloomFilter.mightContain(user4)); // false // 批量添加 for (int i 0; i 1000000; i) { bloomFilter.put(product i); } // 测试误判率 int falsePositive 0; for (int i 1000000; i 2000000; i) { if (bloomFilter.mightContain(product i)) { falsePositive; } } System.out.println(实际误判数 falsePositive); System.out.println(实际误判率 (falsePositive / 1000000.0)); } }第三步高级特性// 合并两个布隆过滤器必须有相同的配置 BloomFilterString filter1 BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1000); BloomFilterString filter2 BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1000); filter1.put(a); filter2.put(b); filter1.putAll(filter2); // 现在filter1包含a和b // 复制布隆过滤器 BloomFilterString copy filter1.copy(); // 估算布隆过滤器中元素的数量 long approximateElementCount filter1.approximateElementCount();四、布隆过滤器的经典应用场景1. 解决缓存穿透问题问题黑客故意查询数据库中不存在的 key导致请求绕过缓存直接打到数据库数据库压力剧增甚至宕机。解决方案将数据库中所有存在的 key 预先加载到布隆过滤器中当有查询请求时先经过布隆过滤器如果布隆过滤器说不存在 → 直接返回不访问缓存和数据库如果布隆过滤器说可能存在 → 再访问缓存缓存未命中再访问数据库代码示例Service public class UserService { Autowired private UserMapper userMapper; Autowired private RedisTemplateString, User redisTemplate; private BloomFilterString userIdBloomFilter; // 项目启动时初始化布隆过滤器 PostConstruct public void initBloomFilter() { ListLong allUserIds userMapper.getAllUserIds(); userIdBloomFilter BloomFilter.create( Funnels.stringFunnel(StandardCharsets.UTF_8), allUserIds.size(), 0.001 ); for (Long userId : allUserIds) { userIdBloomFilter.put(userId.toString()); } } public User getUserById(Long userId) { String key user: userId; // 先经过布隆过滤器 if (!userIdBloomFilter.mightContain(userId.toString())) { return null; // 直接返回防止缓存穿透 } // 再查缓存 User user redisTemplate.opsForValue().get(key); if (user ! null) { return user; } // 最后查数据库 user userMapper.selectById(userId); if (user ! null) { redisTemplate.opsForValue().set(key, user, Duration.ofHours(1)); } return user; } }2. 爬虫 URL 去重问题爬虫在爬取网站时会遇到大量重复的 URL如果不进行去重会重复爬取相同页面浪费资源和时间。解决方案使用布隆过滤器存储已经爬取过的 URL每次发现新 URL 时先检查布隆过滤器如果不存在 → 加入爬取队列并添加到布隆过滤器如果存在 → 跳过优势可以处理数十亿级别的 URL 去重内存占用极小。3. 垃圾邮件过滤问题每天有数十亿封垃圾邮件发送需要快速判断发件人是否在黑名单中。解决方案将所有垃圾邮件发件人的邮箱地址存入布隆过滤器收到新邮件时先检查发件人是否在布隆过滤器中如果不存在 → 正常投递如果存在 → 进一步检查如内容分析4. 黑名单系统问题大型网站需要维护一个庞大的 IP 黑名单或手机号黑名单快速判断请求是否来自黑名单。解决方案将所有黑名单 IP / 手机号存入布隆过滤器每次请求时先检查布隆过滤器如果不存在 → 正常处理如果存在 → 拒绝请求或进行更严格的验证5. 数据库查询优化问题在分布式数据库中查询一个不存在的记录会遍历所有分片浪费资源。解决方案为每个分片维护一个布隆过滤器存储该分片的所有主键查询时先检查对应分片的布隆过滤器如果不存在 → 跳过该分片如果存在 → 再查询该分片6. 推荐系统去重问题推荐系统需要避免向用户推荐已经看过的内容。解决方案为每个用户维护一个布隆过滤器存储该用户已经看过的内容 ID生成推荐列表时过滤掉布隆过滤器中存在的内容五、布隆过滤器的优缺点与注意事项优点空间效率极高比哈希表节省 90% 以上的空间查询和添加速度极快时间复杂度为 O (k)与数据量无关无冲突不需要处理哈希冲突易于实现原理简单代码量少缺点存在误判率不能 100% 准确判断元素是否存在不支持删除元素普通布隆过滤器无法删除元素需要提前预估数据量如果实际数据量超过预估误判率会急剧上升注意事项合理设置参数根据业务需求选择合适的误判率和数据量定期重建当数据量增长超过预估时需要重建布隆过滤器处理误判对于布隆过滤器返回 存在 的结果需要进行二次验证不要存储敏感数据布隆过滤器无法直接获取存储的元素但可以通过暴力破解推断六、布隆过滤器的变种计数布隆过滤器Counting Bloom Filter将每个 bit 位改为计数器支持删除操作但会增加空间占用布谷鸟过滤器Cuckoo Filter支持删除操作误判率更低查询速度更快分层布隆过滤器用于处理动态增长的数据分布式布隆过滤器在分布式系统中使用如 Redis 布隆过滤器七、Redis 布隆过滤器生产环境首选在分布式系统中通常使用 Redis 提供的布隆过滤器功能Redis 4.0 通过 RedisBloom 模块支持。Redis 布隆过滤器基本命令# 创建布隆过滤器 BF.RESERVE user_filter 0.001 1000000 # 添加元素 BF.ADD user_filter user1 BF.ADD user_filter user2 # 批量添加元素 BF.MADD user_filter user3 user4 user5 # 查询元素是否存在 BF.EXISTS user_filter user1 BF.EXISTS user_filter user6 # 批量查询 BF.MEXISTS user_filter user1 user2 user6Java 中使用 Redis 布隆过滤器import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.List; Component public class RedisBloomFilter { private final RedisTemplateString, Object redisTemplate; public RedisBloomFilter(RedisTemplateString, Object redisTemplate) { this.redisTemplate redisTemplate; } /** * 创建布隆过滤器 * param key 过滤器key * param errorRate 误判率 * param capacity 容量 */ public void createFilter(String key, double errorRate, long capacity) { redisTemplate.execute((connection) - { connection.execute(BF.RESERVE, key.getBytes(), String.valueOf(errorRate).getBytes(), String.valueOf(capacity).getBytes()); return null; }); } /** * 添加元素 */ public boolean add(String key, String value) { Boolean result redisTemplate.execute((connection) - connection.execute(BF.ADD, key.getBytes(), value.getBytes())); return Boolean.TRUE.equals(result); } /** * 查询元素是否存在 */ public boolean exists(String key, String value) { Boolean result redisTemplate.execute((connection) - connection.execute(BF.EXISTS, key.getBytes(), value.getBytes())); return Boolean.TRUE.equals(result); } }总结布隆过滤器是一种用准确性换空间和时间的数据结构它的核心价值在于快速判断元素不存在。在处理海量数据时它能极大地提升系统性能降低资源消耗。记住布隆过滤器的黄金法则它说不存在的一定不存在它说存在的可能存在。只要你能接受这个小小的缺点布隆过滤器就能成为你解决海量数据问题的利器。