news 2026/4/16 7:42:56

布隆过滤器:用概率换空间的奇妙数据结构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
布隆过滤器:用概率换空间的奇妙数据结构

目录

从图书馆查书说起

什么是布隆过滤器?

核心特点:

工作原理:多哈希与位数组的舞蹈

1. 基础组件

2. 添加元素

3. 查询元素

为什么会有误判?

关键参数与设计

1. 误判率公式

2. 最优参数选择

应用场景:哪些地方在用布隆过滤器?

1. 网络爬虫去重

2. 数据库查询优化

3. 缓存穿透防护

4. 分布式系统

动手实现一个简单的布隆过滤器

布隆过滤器的变体与改进

1. 计数布隆过滤器

2. 布谷鸟过滤器

3. 可扩展布隆过滤器

优缺点总结

优点:

缺点:

何时使用布隆过滤器?

结语:接受不完美,换取高效率


从图书馆查书说起

想象一下,你来到一个巨大的图书馆,想要查找某本书。传统的方式是去查阅图书目录——这很准确,但如果你要频繁查询成千上万本书,目录查找的成本会变得很高。

现在,图书管理员告诉你一个更快捷的方法:“我这里有一个神奇的本子,记录了所有馆内肯定没有的书。如果你的书在这个本子上,那一定不在图书馆;如果不在这个本子上,有可能在图书馆,你需要再去目录确认。”

这就是布隆过滤器的核心思想:一种用概率和空间效率换取确定性的数据结构。

什么是布隆过滤器?

布隆过滤器(Bloom Filter)是伯顿·布隆在1970年提出的一种空间高效的概率型数据结构。它用来判断一个元素是否可能在一个集合中,或者肯定不在集合中

核心特点:

  • 空间效率极高:相比哈希表等数据结构,布隆过滤器使用的内存少得多

  • 查询速度极快:插入和查询都是常数时间复杂度 O(k),k为哈希函数数量

  • 存在误判率:可能会误判存在的元素(假阳性),但绝不会漏掉存在的元素(假阴性)

工作原理:多哈希与位数组的舞蹈

1. 基础组件

  • 一个很长的二进制向量(位数组):初始状态所有位都是0

  • 多个相互独立的哈希函数:每个函数能将元素映射到位数组的某个位置

2. 添加元素

当我们要添加一个元素时:

  1. 用k个哈希函数计算该元素的k个哈希值

  2. 将位数组中对应这些哈希值的位置设为1

添加元素 "apple": hash1("apple") = 5 → 位数组[5]=1 hash2("apple") = 12 → 位数组[12]=1 hash3("apple") = 20 → 位数组[20]=1

3. 查询元素

当查询一个元素是否存在时:

  1. 用同样的k个哈希函数计算该元素的k个哈希值

  2. 检查位数组中这些位置是否全部为1

    • 如果全部为1 → "可能存在"

    • 如果有任何一个为0 → "肯定不存在"

查询 "apple": 检查位[5]、[12]、[20] → 全为1 → "可能存在" 查询 "banana": hash1("banana") = 5 → 位[5]=1 ✓ hash2("banana") = 8 → 位[8]=0 ✗ → "肯定不存在"

为什么会有误判?

假设我们添加了"apple",然后查询从未添加过的"orange"。如果"orange"的哈希值恰好覆盖了"apple"设置的所有位(可能还有其他元素设置的位),那么布隆过滤器会误判"orange"存在。

这就是假阳性的根源:不同元素的哈希值可能碰撞到相同的位。

关键参数与设计

1. 误判率公式

误判率 p 与三个参数有关:

  • m:位数组大小

  • n:预期插入元素数量

  • k:哈希函数数量

近似公式:p ≈ (1 - e^(-kn/m))^k

2. 最优参数选择

对于给定的n和期望的误判率p:

  • 最优位数组大小:m = -n·ln(p) / (ln2)²

  • 最优哈希函数数量:k = (m/n)·ln2

应用场景:哪些地方在用布隆过滤器?

1. 网络爬虫去重

爬虫需要判断URL是否已爬取过。使用布隆过滤器可以极大减少内存使用:

# 伪代码示例 if not bloom_filter.might_contain(url): # 肯定没爬过,可以爬取 crawl(url) bloom_filter.add(url)

2. 数据库查询优化

在查询前先用布隆过滤器判断数据是否存在,避免昂贵的磁盘查询:

-- 传统查询(直接查数据库) SELECT * FROM users WHERE id = 123; -- 使用布隆过滤器优化 if bloom_filter.might_contain(123): # 可能存在,再查询数据库 SELECT * FROM users WHERE id = 123; else: # 肯定不存在,直接返回 return null;

3. 缓存穿透防护

防止恶意查询不存在的数据反复击穿缓存到数据库:

// 查询缓存前先检查布隆过滤器 public Object getData(String key) { if (!bloomFilter.mightContain(key)) { return null; // 肯定不存在,直接返回 } Object data = cache.get(key); if (data == null) { data = database.get(key); if (data != null) { cache.put(key, data); } } return data; }

4. 分布式系统

  • 比特币和以太坊:使用布隆过滤器加速钱包同步

  • Cassandra、HBase:使用布隆过滤器减少磁盘查找

  • Chrome浏览器:用布隆过滤器识别恶意网址

动手实现一个简单的布隆过滤器

import mmh3 # MurmurHash库 from bitarray import bitarray class BloomFilter: def __init__(self, size, hash_count): """ size: 位数组大小 hash_count: 哈希函数数量 """ self.size = size self.hash_count = hash_count self.bit_array = bitarray(size) self.bit_array.setall(0) def add(self, item): for i in range(self.hash_count): # 使用不同的种子生成不同的哈希值 digest = mmh3.hash(item, i) % self.size self.bit_array[digest] = 1 def might_contain(self, item): for i in range(self.hash_count): digest = mmh3.hash(item, i) % self.size if self.bit_array[digest] == 0: return False return True # 使用示例 bloom = BloomFilter(1000, 3) bloom.add("hello") print(bloom.might_contain("hello")) # True print(bloom.might_contain("world")) # False(可能误判为True)

布隆过滤器的变体与改进

1. 计数布隆过滤器

允许删除操作,每个位置不再是0/1,而是计数器:

添加元素:对应位置计数器+1

删除元素:对应位置计数器-1(如果>0)

2. 布谷鸟过滤器

比布隆过滤器有更好的空间效率和更低的误判率,同时支持删除操作。

3. 可扩展布隆过滤器

当插入元素超过容量时,自动创建新的布隆过滤器,避免误判率急剧上升。

优缺点总结

优点:

  1. 空间效率极高:比其他数据结构节省大量内存

  2. 查询速度快:常数时间复杂度,与数据量无关

  3. 安全:不存储原始数据,只有哈希值,保护隐私

  4. 可并行化:多个哈希函数可以并行计算

缺点:

  1. 存在误判:有假阳性,没有假阴性

  2. 不支持删除:标准布隆过滤器不支持删除操作

  3. 参数敏感:需要预先知道数据规模来合理设置参数

何时使用布隆过滤器?

适合场景

  • 数据量巨大,内存有限

  • 可以接受一定的误判率

  • 需要极快的查询速度

  • 不需要删除操作,或可以使用变体

不适合场景

  • 要求100%准确性的场景

  • 需要频繁删除元素的场景

  • 数据量很小,直接用哈希表更简单

结语:接受不完美,换取高效率

布隆过滤器教会我们一个重要的工程哲学:在合适的场景下,用可控的不完美换取巨大的效率提升

就像生活中的许多决策一样,我们不需要100%的确定性才能行动。在可以承受的误差范围内,选择更高效的方案,往往是更明智的选择。

在数据爆炸的时代,布隆过滤器这种"可能知道"比"确切知道"更经济的数据结构,正变得越来越重要。它让我们能够用有限的资源,处理近乎无限的数据。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/12 4:22:27

互联网公司数据库授权优化:用量预测+智能调度按需增减案例

互联网公司数据库授权优化:用量预测智能调度按需增减案例在互联网行业中,数据库服务是支撑业务运营的核心基础设施之一。但业务的快速发展,数据库资源的使用情况变得越来越复杂。很多公司都会遇到一个真实而头疼的问题——数据库授权费用过高…

作者头像 李华
网站建设 2026/4/11 21:32:20

工业设备故障预测不准 后来才知道用WaveNet替代LSTM捕捉时序依赖

💓 博客主页:借口的CSDN主页 ⏩ 文章专栏:《热点资讯》 目录从“人肉AI”到吃人AI:一个程序员的困惑日记 一、创业狗的AI生存指南 二、Magenta:AI作曲的魔幻现实 三、AI入侵日常生活的那些坑 四、吃人AI的恐怖故事&…

作者头像 李华
网站建设 2026/4/15 5:23:59

寻找两个正序数组的中位数

class Solution { public: int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) { int m nums1.size(); int n nums2.size(); int index1 0, index2 0; while (true) { // 边界情况 if (index1 m) { return nums2[index2…

作者头像 李华
网站建设 2026/4/12 22:48:33

如何通过Dify智能体平台集成Qwen3-14B实现自动化运营

如何通过Dify智能体平台集成Qwen3-14B实现自动化运营 在企业数字化转型的浪潮中&#xff0c;客服响应慢、运营流程重复、内容生产效率低等问题日益凸显。某电商公司曾面临这样的困境&#xff1a;每天上千条客户咨询涌入企业微信和官网&#xff0c;仅靠人工处理不仅成本高昂&…

作者头像 李华
网站建设 2026/4/11 21:56:31

MP4 转 GIF 转换器 (MP4 to GIF Converter)(源码分享)

&#x1f3a5; MP4 转 GIF 转换器 (MP4 to GIF Converter) 这是一个基于 Python 的轻量级桌面应用程序&#xff0c;旨在帮助用户将 MP4 视频文件快速转换为 GIF 动图。它提供了一个直观的图形用户界面 (GUI)&#xff0c;允许用户在转换前对视频进行裁剪、缩放和帧率调整&#…

作者头像 李华
网站建设 2026/4/15 12:28:04

公司只有功能测试,如何进一步提升自己?

一定要帮助想上进却又迷茫的人。 最近也听到一些做功能测试的同学的交流&#xff0c;天天做手工测试&#xff0c;想提升一下自己又不知道如何提升&#xff1f;其实还是在于这些同学对自己没有一个清晰的定位&#xff0c;没有明确的目标。 做为功能测试人员来讲&#xff0c;从…

作者头像 李华