布隆过滤器

article/2025/7/12 18:57:37

文章目录

  • 布隆过滤器(Bloom Filter)详解:原理、实现与应用场景
    • 一、引言
    • 二、布隆过滤器的基本原理
      • 1. 数据结构
      • 2. 插入操作
      • 3. 查询操作
      • 4. 误判率
    • 三、布隆过滤器的实现
    • 四、布隆过滤器的应用场景
      • 1. 网络爬虫
      • 2. 缓存穿透防护
      • 3. 垃圾邮件过滤
      • 4. 分布式系统
      • 5. 搜索引擎
    • 五、布隆过滤器的优缺点
      • 优点
      • 缺点
    • 六、布隆过滤器的变种
      • 1. 计数布隆过滤器(Counting Bloom Filter)
      • 2. 动态布隆过滤器(Dynamic Bloom Filter)
      • 3. 加密布隆过滤器(Cryptographic Bloom Filter)
    • 七、总结

布隆过滤器(Bloom Filter)详解:原理、实现与应用场景

一、引言

在海量数据处理场景中,我们经常需要快速判断一个元素是否存在于某个集合中。传统的解决方案(如哈希表、树结构)需要存储元素本身,这在数据量极大时会占用大量内存。布隆过滤器(Bloom Filter)则提供了一种空间效率极高的概率型数据结构,它可以告诉你“可能存在”或“一定不存在”,用极小的错误率换取了内存占用的大幅降低。

本文将深入探讨布隆过滤器的原理、实现细节及其在现实场景中的应用,并通过C++代码演示其核心功能。

二、布隆过滤器的基本原理

1. 数据结构

布隆过滤器本质上是一个二进制位数组(通常用位图表示)和一系列哈希函数。初始状态下,整个位数组的所有位都被置为0。

在这里插入图片描述

(布隆过滤器示意图:位数组和多个哈希函数)

2. 插入操作

当要插入一个元素时,布隆过滤器会做以下操作:

  1. 每个哈希函数对元素进行计算,得到多个哈希值
  2. 将这些哈希值对位数组长度取模,得到对应的位索引
  3. 将这些索引位置的位全部置为1

3. 查询操作

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

  1. 用同样的哈希函数对元素进行计算,得到多个哈希值
  2. 检查这些哈希值对应的位是否全部为1:
    • 如果全部为1,则元素可能存在(存在误判可能)
    • 如果有任何一位为0,则元素一定不存在

4. 误判率

布隆过滤器的一个重要特性是存在误判率(False Positive Rate)。即当查询返回“可能存在”时,实际上元素可能并不存在。误判率取决于三个因素:

  • 位数组的大小(m)
  • 哈希函数的数量(k)
  • 已插入元素的数量(n)

误判率公式:
[
P \approx \left(1 - e{-\frac{kn}{m}}\right)k
]

三、布隆过滤器的实现

下面是一个基于C++的布隆过滤器实现示例:

#include <vector>
#include <string>
#include <functional>
#include <bitset>
#include <cmath>template <size_t N>
class BloomFilter {
private:std::bitset<N> bitset_;std::vector<std::function<size_t(const std::string&)>> hash_functions_;public:// 构造函数,接收哈希函数数量explicit BloomFilter(size_t num_hash_functions) {// 使用不同种子的哈希函数for (size_t i = 0; i < num_hash_functions; ++i) {hash_functions_.push_back([i](const std::string& key) {return std::hash<std::string>{}(key + std::to_string(i));});}}// 添加元素到布隆过滤器void add(const std::string& key) {for (const auto& hash_fn : hash_functions_) {size_t index = hash_fn(key) % N;bitset_.set(index);}}// 检查元素是否可能存在bool might_contain(const std::string& key) const {for (const auto& hash_fn : hash_functions_) {size_t index = hash_fn(key) % N;if (!bitset_.test(index)) {return false;}}return true;}// 计算当前误判率double false_positive_rate() const {double m = N;double k = hash_functions_.size();double n = bitset_.count();  // 已设置的位数return std::pow(1.0 - std::exp(-k * n / m), k);}// 重置布隆过滤器void clear() {bitset_.reset();}
};// 优化版本:自动计算最佳哈希函数数量
template <size_t N, size_t ExpectedElements>
class OptimizedBloomFilter : public BloomFilter<N> {
public:OptimizedBloomFilter() : BloomFilter<N>(optimal_num_hash_functions()) {}private:// 计算最优哈希函数数量:k = (m/n) * ln(2)static size_t optimal_num_hash_functions() {return static_cast<size_t>((N / ExpectedElements) * std::log(2));}
};    

四、布隆过滤器的应用场景

1. 网络爬虫

在网络爬虫中,布隆过滤器可以用于快速判断一个URL是否已经被爬取过,避免重复爬取。由于网络URL数量巨大,使用传统集合会占用过多内存,而布隆过滤器可以在极小的内存消耗下完成这个任务。

2. 缓存穿透防护

在缓存系统(如Redis)中,布隆过滤器可以用于防止缓存穿透攻击。当大量请求查询一个不存在于缓存和数据库中的key时,会导致请求全部穿透到数据库,造成性能压力。布隆过滤器可以在请求到达缓存前快速判断key是否存在,从而拦截无效请求。

3. 垃圾邮件过滤

邮件服务提供商可以使用布隆过滤器来快速判断一个邮箱地址是否在已知的垃圾邮件发送者列表中,减少垃圾邮件的干扰。

4. 分布式系统

在分布式系统中,布隆过滤器可以用于数据同步控制。例如,判断一个数据是否已经存在于其他节点中,避免重复传输。

5. 搜索引擎

搜索引擎索引系统可以使用布隆过滤器来快速判断一个文档是否已经被索引过,提高索引效率。

五、布隆过滤器的优缺点

优点

  1. 空间效率极高:相比传统数据结构,布隆过滤器用位数组表示集合,大大减少了内存占用。
  2. 查询效率高:所有操作都是常数时间复杂度O(k),其中k是哈希函数的数量。
  3. 无需存储元素本身:对于隐私敏感数据,布隆过滤器只存储哈希值,不存储原始数据。

缺点

  1. 存在误判率:无法100%准确判断元素是否存在。
  2. 不能删除元素:由于多个元素可能共享相同的位,删除一个元素可能影响其他元素的判断结果。
  3. 参数调整复杂:需要根据预期元素数量和误判率精心调整位数组大小和哈希函数数量。

六、布隆过滤器的变种

1. 计数布隆过滤器(Counting Bloom Filter)

普通布隆过滤器不能删除元素的问题可以通过计数布隆过滤器解决。计数布隆过滤器将位数组的每个位扩展为一个计数器,当插入元素时计数器加1,删除元素时计数器减1。但这种方法会增加内存消耗。

2. 动态布隆过滤器(Dynamic Bloom Filter)

动态布隆过滤器可以在运行时调整大小,当元素数量超过预期时,可以创建一个新的布隆过滤器并合并原有的数据。

3. 加密布隆过滤器(Cryptographic Bloom Filter)

在需要保护数据隐私的场景中,可以使用加密布隆过滤器。这种布隆过滤器在哈希过程中加入了加密算法,提高了数据安全性。

七、总结

布隆过滤器是一种空间效率极高的概率型数据结构,特别适合用于大规模数据的快速存在性判断。虽然存在一定的误判率,但在很多场景下这种误判是可以接受的,并且可以通过调整参数来控制误判率。

通过本文的介绍,你应该已经掌握了布隆过滤器的基本原理、实现方法及其应用场景。在实际应用中,你可以根据具体需求选择合适的布隆过滤器变种,或者使用现有的开源库(如Python的pybloom_live、Java的Google Guava中的BloomFilter)来快速实现功能。


http://www.hkcw.cn/article/JQxBhAUPCA.shtml

相关文章

给stm32cubeide编译出来的bin文件追加crc32

在工程目录下创建ci目录&#xff0c;将AddCrc32.exe丢进去&#xff0c;在stm32cubeide的properties----C/C Build----Settings----Build Steps----Post-build steps Command:添加AddCrc32.exe的路径: source code如下&#xff1a; #include <stdio.h> #include <stdl…

算法-集合的使用

1、set常用操作 set<int> q; //以int型为例 默认按键值升序 set<int,greater<int>> p; //降序排列 int x; q.insert(x); //将x插入q中 q.erase(x); //删除q中的x元素,返回0或1,0表示set中不存在x q.clear(); //清空q q.empty(); //判断q是否为空&a…

网络地址转换

网络地址转换 网络地址转换(Network Address Translation&#xff0c;NAT)的功能是将企业内部自行定义的私有IP地址转换为Internet上可识别的合法IP地址。由于现行IP地址标准--IPv4的限制&#xff0c;Internet面临着IP地址空间短缺的问题&#xff0c;因此从ISP申请并给企业的每…

4.大语言模型预备数学知识

大语言模型预备数学知识 复习一下在大语言模型中用到的矩阵和向量的运算&#xff0c;及概率统计和神经网络中常用概念。 矩阵的运算 矩阵 矩阵加减法 条件&#xff1a;行数列数相同的矩阵才能做矩阵加减法 数值与矩阵的乘除法 矩阵乘法 条件&#xff1a;矩阵A的列数 矩阵…

leetcode hot100刷题日记——35.子集

解答&#xff1a; 方法一&#xff1a;选or不选的dfs&#xff08;输入视角&#xff09; 思路&#xff1a;[1,2,3]的全部子集可以看成是对数组的每一位数字做选择。 eg.空集就是一个数字都不选&#xff0c;[1,2]就是1&#xff0c;2选&#xff0c;3不选。 class Solution { pub…

【数据库】关系数据库标准语言-SQL(金仓)下

4、数据查询 语法&#xff1a; SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>] … FROM <表名或视图名>[, <表名或视图名> ] … [ WHERE <条件表达式> ] [ GROUP BY <列名1> [ HAVING <条件表达式> ] ] [ ORDER BY <…

好用的C/C++/嵌入式 IDE: CLion的下载安装教程(保姆级教程)

CLion简介 CLion是由著名的JetBrains公司开发出的一个C/C的IDE。它原是付费软件&#xff0c;但在最近(指2025年5月)开放了非商业用途免费&#xff0c;就像WebStorm、Rider、RustRover等。 除了这些&#xff0c;JetBrains的IntelliJ IDEA(社区版)和PyCharm(社区版)也是免费的。…

SpringBoot统一功能处理

1.拦截器 拦截器是Spring框架提供的核心功能之一,主要是用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的…

prometheus v3.4.1正式发布!解析全新特性与安装指南,打造高效云原生监控体系

一、引言 随着云原生时代的快速发展&#xff0c;监控系统成为保障业务平稳运行的核心利器。作为CNCF&#xff08;Cloud Native Computing Foundation&#xff09;旗下的开源监控项目&#xff0c;Prometheus凭借其卓越的多维数据模型、灵活强大的查询语言及自主运行的架构设计&a…

PCA(K-L变换)人脸识别(python实现)

数据集分析 ORL数据集&#xff0c; 总共40个人&#xff0c;每个人拍摄10张人脸照片 照片格式为灰度图像&#xff0c;尺寸112 * 92 特点&#xff1a; 图像质量高&#xff0c;无需灰度运算、去噪等预处理 人脸已经位于图像正中央&#xff0c;但部分图像角度倾斜&#xff08;可…

资源预加载+懒加载组合拳:从I/O拖慢到首帧渲染的全面优化方案

简介 在移动应用开发领域,首帧渲染性能已成为用户体验的关键指标之一。根据2025年最新行业数据,首屏加载时间每延迟1秒,用户跳出率可能增加32%,直接影响应用评分和留存率。当应用启动时,布局解析、图片解码等I/O操作往往成为首帧渲染的主要瓶颈,导致用户看到白屏或黑屏时…

【Doris基础】Apache Doris中的Coordinator节点作用详解

目录 1 Doris架构概述 2 Coordinator节点的核心作用 2.1 查询协调与调度 2.2 执行计划生成与优化 2.3 资源管理与负载均衡 2.4 容错与故障恢复 3 Coordinator节点的关键实现机制 3.1 两阶段执行模型 3.2 流水线执行引擎 3.3 分布式事务管理 4 Coordinator节点的高可…

【基于阿里云搭建数据仓库(离线)】IDEA导出Jar包(包括第三方依赖)

1.双击"package”即可进行打包呈jar 2.双击后就会自动打包生成jar了&#xff0c; 生成的jar在这个目录下 3.右击&#xff0c;点击“复制路径/引用”&#xff0c;即可获得“绝对路径”、“根路径”等相关信息

id()函数:窥探Python变量内存地址的奥秘

在Python程序设计中&#xff0c;变量、对象和内存是紧密相连的核心概念。理解变量的内存地址&#xff0c;是理解Python变量本质、内存管理与性能优化的关键。Python内置函数id()&#xff0c;作为变量与对象身份&#xff08;identity&#xff09;的“指纹识别器”&#xff0c;为…

MySQL中的事务

事物特性 原子性:事物时最小的执行单位&#xff0c;不允许分割。事物的原子性确保动作要么全部完成&#xff0c;要么完全不起作用&#xff0c;如果在执行过程中发生错误&#xff0c;会被回滚到事物开始前的状态&#xff0c;就像这个事务从来没有执行过一样。一致性&#xff1a…

像素转换案例实战

本案例介绍像素单位的基本知识与像素单位转换API的使用。通过像素转换案例&#xff0c;向开发者讲解了如何使用像素单位设置组件的尺寸、字体的大小以及不同像素单位之间的转换方法。主要功能包括&#xff1a; 展示了不同像素单位的使用。展示了像素单位转换相关API的使用。 …

结构型设计模式之桥接模式

文章目录 1. 桥接模式概述2. 模式结构3. 桥接模式的优缺点优点缺点 4. 桥接模式的应用场景5. C#代码示例5.1 简单示例 - 形状与颜色5.2 更复杂的示例 - 跨平台消息发送系统 6. 桥接模式与其他模式的比较7. 真实世界中的桥接模式应用7.1 数据库驱动7.2 UI框架中的渲染机制 8. 桥…

RAG系统中如何检测幻觉?

虽然我们的 RAG 系统通过将答案基于真实的医学证据来减少幻觉,但我们发现了一个关键的差距:即使有引用,系统仍然可能产生不可靠的输出。 想想看:仅仅因为一个系统可以引用来源,并不意味着它正确地使用了这些来源。 模型可能会: 从检索到的文档中提取不相关的信息不适当…

world quant教程学习

Understanding Corporate Fundamental Data &#x1f50d; 了解企业基本面数据 Lets explore fundamental data&#x1f60a; Fundamentals capture the underlying business, financial and operational health of a company, usually reported every quarter. This data is t…

详解鸿蒙仓颉开发语言中的计时器

今天又到了大家喜闻乐见的科普环节&#xff0c;也可以说是踩坑环节&#xff0c;哈哈哈。今天聊一聊仓颉开发语言中的计时器&#xff0c;这部分可老有意思了。 为什么这么说呢&#xff0c;因为关于仓颉的计时器你几乎搜不到任何的文档&#xff0c;也没有相关的代码提示&#xf…