布隆过滤器(Bloom Filter)

2023-11-18

1.引言

通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,最终达到瓶颈。同时检索速度也越来越慢,上述三种结构的检索时间复杂度分别为O(n),O(logn),O(1)。这种时候,布隆过滤器就是一种比较好的解决方案了。

2.什么是布隆过滤器

布隆过滤器(Bloom Filter)其实是基于bitmap的一种应用, 1970 年由布隆提出。它由一个很长的二进制比特数组和一系列哈希函数构成,用于高效地检索数据是否存在。通俗的说可以把布隆过滤器理解为一个集合,我们可以往里面添加值,并且能判断某个值是否在里面。当布隆过滤器告诉我们某个值存在时,其实这个值只是有可能存在;可是它说某个值不存在时,那这个值就真的不存在。

3.工作机制

如图1 所示,初始化比特数组的值全为0,长度m=23,并假设有k=3个能把数据均匀映射到值域为 [0,m) 的哈希函数,经过一系列添值操作后,数组的值会散乱地被赋为1。我们先将数据a、b、c放入布隆过滤器,对a、b、c各自分别使用三个哈希函数得到映射值(即比特数组索引下标)。再根据下标将比特数组对应的值置为1,从而表示这三个数据已经存在。

然后我们用两个不曾被布隆过滤器标记的数据d、e模拟布隆过滤器的筛选过程。同样要使用前文设定的3个哈希函数,经散列得到比特数组索引下标,然后按下标查询得到对应的数组值。如果说3个索引值里出现了至少一个值为0,那么可以肯定的说这个数据肯定不存在,比如d。但是也会出现e这种情况,查得的值均为1,但是e明明不存在。其实出现这种情况的原因很好理解:那些被置为 1 的位置也可能是由于其他元素的操作而改变的。所以布隆过滤器存在假正率(False Positive)。

4.时间复杂度 空间复杂度

时间复杂度:在查找过程里,取值过程是直接查找,但是取值的次数等于哈希函数的个数成,所以时间复杂度为O(k),k为哈希函数的个数。另外哈希计算可以使用硬件加速,故查找效率很高。

空间复杂度:存储上,假设比特数组长度为m=10000000,则申请的内存大小为10000000bit=1250000B=1220.703125KB≈1.20MB≈0.001164GB。这在动辄内存8G起步的设备上,其实占用很小。

 5.正确率和容错

首先对False positive概率进行推导:

假设 Hash 函数以等概率条件选择并设置比特数组中的某一位,m 是该位数组的大小,k 是 Hash 函数的个数,那么位数组中某一特定的位在进行元素插入时的 Hash 操作中没有被置位的概率是:

 那么在所有 k 次 Hash 操作后该位都没有被置 "1" 的概率是:

如果我们插入了 n 个元素,那么某一位仍然为 "0" 的概率是:

因而该位为 "1"的概率是:

现在检测某一元素是否在该集合中。标明某个元素是否在集合中所需的 k 个位置都按照如上的方法设置为 "1",但是该方法可能会使算法错误的认为某一原本不在集合中的元素却被检测为在该集合中(False Positive),该概率由以下公式确定:

其实上述结果是在假定由每个 Hash 计算出需要设置的位(bit) 的位置是相互独立为前提计算出来的,不难看出,随着 m (比特数组大小)的增加,False Positive的概率会下降,同时随着插入元素个数 n 的增加,False Positive的概率又会上升,对于给定的m,n,如何选择Hash函数个数 k 由以下公式确定:

此时False Positive的概率为:

而对于给定的False Positive概率 p,如何选择最优的位数组大小 m 呢,

上式表明,比特数组的大小最好与插入元素的个数成线性关系。

对于布隆过滤器不会漏报,但可能误报这个情况,我们当然希望准确度越高越好。

 false positive rate under various m/n and k combinations

 从上图可以看出,数据冗余量越大,哈希函数越多,错误率越低。但是总体来看,错误率控制在1%以内

确定了正确率的问题后,接下来就是关键的容错了,怎么容错才算完美,既能解决问题,又能照顾容错成本呢?一方面由于布隆过滤器使用多个哈希函数进行处理,所以生成的值正常会均匀分布,数据不均衡从而造成数据稀疏时成本较高的问题就不存在了;另一方面,虽然说数据量增大超过预先设计的最大值也会对布隆过滤器造成影响,但是影响并不是很严重,除非差别过于巨大。因为实际数据量增大后,只会影响到上图m/n的值,带来的影响只是略微影响到布隆过滤器的正确率。

6.优点

  • 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关
  • 哈希函数相互之间没有关系,方便硬件并行运算
  • 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  • 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
  • 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  • 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

7.使用场景

布隆过滤器被广泛用于数据量庞大的情况下的查询、去重等业务,比如:

  • 黑名单过滤
  • 垃圾邮件过滤
  • 爬虫判重系统
  • 推荐系统去重
  • 缓存穿透
  • 区块链的SPV支付
  • Web拦截器
  • ……

8.缺点

  • 有误判率,即存在假正率,即不能准确判断元素是否在集合中
  • 不能获取元素本身
  • 一般情况下不能从布隆过滤器中删除元素
  • 随着使用的时间越来越长,因为不能删除,存进里面的元素越来越多,占用内存越来越多,误判率越来越高,最后不得不重置。
  • 如果采用计数方式删除,可能会存在计数回绕问题
  • 数据量过于庞大时,计算机内存也会进行频繁的页面置换(这个其实不独属于布隆过滤器的缺点) 

9.总结

总体来说,布隆过滤器是一个很有意思的数据结构,空间效率和查询时间都远远超过一般的算法。目前已经在业务中广泛使用,比如常用的redis里已经集成了布隆过滤器。本篇只是就最基本的布隆过滤器做了介绍,在具体应用中,布隆过滤器还有更多的有趣的功能和进一步改进的数据结构。朋友们可以亲自coding一下,比如尝试一下redis的布隆过滤器,或者尝试给布隆过滤器实现删除数据的功能等等。


9.Reference

布隆过滤器 - 维基百科,自由的百科全书 (wikipedia.org)

hash 算法原理及应用漫谈 (qq.com)

详解布隆过滤器的原理、优缺点_一只快乐的野指针吼的博客-CSDN博客_布隆过滤器原理

布隆过滤器,这一篇给你讲的明明白白-阿里云开发者社区 (aliyun.com)

布隆过滤器及其使用场景 - Master HaKu - 博客园 (cnblogs.com)

Redis布隆过滤器(原理+图解) (biancheng.net)

布隆过滤器(Bloom Filter)详解 - 李玉龙 - 博客园 (cnblogs.com)

Merkle Tree、Merkle Proof、SPV安全性分析、Bloom过滤器_真·skysys的博客-CSDN博客

简化的支付验证(SPV)和布隆过滤器(bloom fliter)

"不靠谱"的布隆过滤器是怎么成为大数据世界中的韦小宝的?

布隆过滤器踩坑日记

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

布隆过滤器(Bloom Filter) 的相关文章

  • 记一次Spark打包错误:object java.lang.Object in compiler mirror

    使用maven compile和package 一直报错scala reflect internal MissingRequirementError object scala runtime in compiler mirror not f
  • 【Linux】实现简易的Shell命令行解释器

    大家好我是沐曦希 文章目录 一 前言 二 准备工作 1 输出提示符 2 输入和获取命令 3 shell运行原理 4 内建命令 5 替换 三 整体代码 一 前言 前面学到了进程创建 进程终止 进程等待 进程替换 那么通过这些来制作一个简易的S
  • 多任务:分层特征融合网络 NDDR-CNN

    论文链接 NDDR CNN 论文摘要 In this paper we propose a novel Convolutional Neural Network CNN structure for general purpose multi
  • sqli-labs/Less-34

    这一关虽然属于宽字节注入 但是回归了post请求了 而且欢迎界面还是存在转义之后的样子和十六进制的样子 首先我们试试在username处输入admin 转义之后变成了admin 所以我们进行宽字节注入将注入修改为admin c0 结果界面还

随机推荐

  • 微信小程序隐私保护指引设置

    今天修改了发布规则 发布前必须填写用户隐私保护指引设置 就是以下内容
  • 解决Unity导出的APK启动黑屏的问题

    今天准备把最近写的Unity游戏编一个版本 但是放真机上运行时 一启动就黑屏 网上各种查资料 折腾半天后 找到了解决方案 需要指定Graphics APIs 为OpenGLES3 在 Project Settings gt Player g
  • sort中用lambda函数(看完就会)

    介绍 sort函数是默认从小到大排列的 如果我们想要改变排序方式就要自己写个cmp函数 如果排列方式比较简单的话我们可以在sort函数中用一个简单的lambda函数 源码及讲解 对非结构体的数组 前面的 表示对数的操作方式 如果填个 说明是
  • shell指令,通过函数实现数组求和,通过函数获取用户uid和gid

    一 实现一个对数组求和的函数 数组通过实参传递给函数 num 0 read p 请输入一组数据 a arr function add for i 0 i lt arr i do num arr i done return num add a
  • CSS中如何实现文字描边效果(Text Stroke)?

    聚沙成塔 每天进步一点点 专栏简介 文字描边效果 Text Stroke 示例 写在最后 专栏简介 前端入门之旅 探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅 这个专栏是为那些对
  • 手把手接入【微信测试公众号】,不会还有人不会调试公众号吧?

    仅使用微信的测试公众号 Java开发内容 遇错与参考 Java接入测试微信公众号调试流程 前提 创建并配置测试号 登陆注册微信测试公众号 沙箱 微信验签 免登授权获取用户信息 微信接口调试工具的使用 创建服务号菜单 常见错误 invalid
  • 最高月薪15K! 这个30岁的奶茶店老板说:这次转行,转对了!

    人生没有一成不变的风景 这一路上 我们会走过晴天 也会踏过泥泞 会穿越风雨 也将沐浴暖阳 不同的年龄 有不同的风景 不同的阶段 有不同的境遇 也许每个人的经历不同 对人生的感受也各异 但只要内心强大 不断让自己淬炼成长 就能从容面对人生 行
  • Yii Framework 开发教程(47) 主题 Theme 示例

    Theming是一个在Web应用程序里定制网页外观的系统方式 通过采用一个新的主题 可以非常方便的改变应用的外观 在Yii 每个主题由一个目录代表 包含view文件 layout文件和相关的资源文件 如图片 CSS文件 JavaScript
  • 1、安装配置

    一 安装 这里以Redis 5 0 5版本为例 实际安装过程中 可以去官网下载最新的稳定版本 官网地址 http redis io download wget http download redis io releases redis 5
  • 内核启动过程中对CPU型号的确认

    1 内核为什么要确认CPU型号 内核和CPU都是不断发展的 内核会不断的更新版本 CPU会不断的出新型号 每当厂商推出一款新的CPU都需要移植内核 使内核能在新款CPU上运行 如果我们将没有针对该款CPU移植过的内核放到该款CPU上运行 结
  • Linux定时器

    Linux定时器的实现主要用到itimerval结构体以及setitimer产生的信号 系统随使用signal信号处理函数来处理产生的定时信号 从而实现定时器 itimerval结构体说明 struct itimerval Value to
  • [谦实思纪 02]整理自2023雷军年度演讲——《成长》(下篇)创业之旅(创业与成长)

    文章目录 谦实思纪 整理自2023雷军年度演讲 成长 下篇 创业之旅 创业与成长 0 写在前面 1 创业 创业与成长 1 1 找互补的朋友一起干 更容易成功 1 2 创业中必须要有领导者 核心思维 1 3 从失败开始 学海无涯 1 4 金山
  • STM32G070进行flash读写操作

    STM32G070的flash读写问题 STM32G070xx的flash分布如下图 打算将Page 63用于保存用户数据 问题 开始一直出现flash写入失败 从返回码来看是FLASH FLAG PGSERR 一直找不到原因 代码如下 d
  • android throw exception 原理,Android Throw Exception

    It depends if this Close can throw an exception then it still needs to be declared as being thrown or caught Often times
  • grid常用属性及属性值介绍

    文章目录 前言 一 grid布局是什么 二 常用简写 必会 2 1 grid 2 2 gap grid gap 2 3 grid area 2 4 grid template 2 5 place content 2 6 place item
  • 1359: [Baltic209]Candy

    题目链接 题目大意 tan90 题解 不存在的 我的收获 如何快速升级
  • protobuf与protoc-gen-go

    什么是protobuf Protobuf Protocol Buffer 是google 的一种数据交换的格式 它独立于语言 独立于平台 google 提供了多种语言的实现 java c c go 和 python 每一种实现都包含了相应语
  • Jmeter接口测试+压力测试

    jmeter是apache公司基于java开发的一款开源压力测试工具 体积小 功能全 使用方便 是一个比较轻量级的测试工具 使用起来非常简单 因为jmeter是java开发的 所以运行的时候必须先要安装jdk才可以 jmeter是免安装的
  • OkHttp的使用之{RequestBody、FormBody、MultipartBody}

    目录 0 相关文章 1 POST请求 1 1 RequestBody json数据提交 1 2 FromBody 表单提交 这种能满足大部分的需求 1 3 MultipartBody 文件上传 1 4 图片下载 文件下载 0 相关文章 Ok
  • 布隆过滤器(Bloom Filter)

    1 引言 通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景 一般想到的是将集合中所有元素保存起来 然后通过比较确定 链表 树 散列表 又叫哈希表 Hash table 等等数据结构都是这种思路 但是随着集合中元素的增加 我们需要的