前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >布隆过滤器

布隆过滤器

作者头像
大学里的混子
修改于 2019-02-21 03:07:15
修改于 2019-02-21 03:07:15
8580
举报
文章被收录于专栏:LeetCodeLeetCode

布隆过滤器 (Bloom Filter)是由Burton Howard Bloom于1970年提出,它是一种space efficient的概率型数据结构,用于判断一个元素是否在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的网址判重模块中等等经常被用到。哈希表也能用于判断元素是否在集合中,但是布隆过滤器只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,false positive rate(误报率)越大,但是false negative (漏报)是不可能的。

本文将详解布隆过滤器的相关算法和参数设计,在此之前希望大家可以先通过谷歌黑板报的数学之美系列二十一 - 布隆过滤器(Bloom Filter)来得到些基础知识。

一. 算法描述

一个empty bloom filter是一个有m bits的bit array,每一个bit位都初始化为0。并且定义有k个不同的hash function,每个都以uniform random distribution将元素hash到m个不同位置中的一个。在下面的介绍中n为元素数,m为布隆过滤器或哈希表的slot数,k为布隆过滤器重hash function数。

为了add一个元素,用k个hash function将它hash得到bloom filter中k个bit位,将这k个bit位置1。

为了query一个元素,即判断它是否在集合中,用k个hash function将它hash得到k个bit位。若这k bits全为1,则此元素在集合中;若其中任一位不为1,则此元素比不在集合中(因为如果在,则在add时已经把对应的k个bits位置为1)。

不允许remove元素,因为那样的话会把相应的k个bits位置为0,而其中很有可能有其他元素对应的位。因此remove会引入false negative,这是绝对不被允许的。

当k很大时,设计k个独立的hash function是不现实并且困难的。对于一个输出范围很大的hash function(例如MD5产生的128 bits数),如果不同bit位的相关性很小,则可把此输出分割为k份。或者可将k个不同的初始值(例如0,1,2, … ,k-1)结合元素,feed给一个hash function从而产生k个不同的数。

当add的元素过多时,即n/m过大时(n是元素数,m是bloom filter的bits数),会导致false positive过高,此时就需要重新组建filter,但这种情况相对少见。

二. 时间和空间上的优势

当可以承受一些误报时,布隆过滤器比其它表示集合的数据结构有着很大的空间优势。例如self-balance BST, tries, hash table或者array, chain,它们中大多数至少都要存储元素本身,对于小整数需要少量的bits,对于字符串则需要任意多的bits(tries是个例外,因为对于有相同prefixes的元素可以共享存储空间);而chain结构还需要为存储指针付出额外的代价。对于一个有1%误报率和一个最优k值的布隆过滤器来说,无论元素的类型及大小,每个元素只需要9.6 bits来存储。这个优点一部分继承自array的紧凑性,一部分来源于它的概率性。如果你认为1%的误报率太高,那么对每个元素每增加4.8 bits,我们就可将误报率降低为原来的1/10。add和query的时间复杂度都为O(k),与集合中元素的多少无关,这是其他数据结构都不能完成的。

如果可能元素范围不是很大,并且大多数都在集合中,则使用确定性的bit array远远胜过使用布隆过滤器。因为bit array对于每个可能的元素空间上只需要1 bit,add和query的时间复杂度只有O(1)。注意到这样一个哈希表(bit array)只有在忽略collision并且只存储元素是否在其中的二进制信息时,才会获得空间和时间上的优势,而在此情况下,它就有效地称为了k=1的布隆过滤器。

而当考虑到collision时,对于有m个slot的bit array或者其他哈希表(即k=1的布隆过滤器),如果想要保证1%的误判率,则这个bit array只能存储m/100个元素,因而有大量的空间被浪费,同时也会使得空间复杂度急剧上升,这显然不是space efficient的。解决的方法很简单,使用k>1的布隆过滤器,即k个hash function将每个元素改为对应于k个bits,因为误判度会降低很多,并且如果参数k和m选取得好,一半的m可被置为为1,这充分说明了布隆过滤器的space efficient性。

三. 举例说明

以垃圾邮件过滤中黑白名单为例:现有1亿个email的黑名单,每个都拥有8 bytes的指纹信息,则可能的元素范围为 

,对于bit array来说是根本不可能的范围,而且元素的数量(即email列表)为

,相比于元素范围过于稀疏,而且还没有考虑到哈希表中的collision问题。

若采用哈希表,由于大多数采用open addressing来解决collision,而此时的search时间复杂度为 :

即若哈希表半满(n/m = 1/2),则每次search需要probe 2次,因此在保证效率的情况下哈希表的存储效率最好不超过50%。此时每个元素占8 bytes,总空间为:

若采用Perfect hashing(这里可以采用Perfect hashing是因为主要操作是search/query,而并不是add和remove),虽然保证worst-case也只有一次probe,但是空间利用率更低,一般情况下为50%,worst-case时有不到一半的概率为25%。

若采用布隆过滤器,取k=8。因为n为1亿,所以总共需要

被置位为1,又因为在保证误判率低且k和m选取合适时,空间利用率为50%(后面会解释),所以总空间为:

所需空间比上述哈希结构小得多,并且误判率在万分之一以下。

四. 误判概率的证明和计算

假设布隆过滤器中的hash function满足simple uniform hashing假设:每个元素都等概率地hash到m个slot中的任何一个,与其它元素被hash到哪个slot无关。若m为bit数,则对某一特定bit位在一个元素由某特定hash function插入时没有被置位为1的概率为:

则k个hash function中没有一个对其置位的概率为:

如果插入了n个元素,但都未将其置位的概率为:

则此位被置位的概率为:

现在考虑query阶段,若对应某个待query元素的k bits全部置位为1,则可判定其在集合中。因此将某元素误判的概率为:

由于

,并且

  当m很大时趋近于0,所以

从上式中可以看出,当m增大或n减小时,都会使得误判率减小,这也符合直觉。

现在计算对于给定的m和n,k为何值时可以使得误判率最低。设误判率为k的函数为:

设 

, 则简化为

,两边取对数

  , 两边对k求导

下面求最值

因此,即当

  时误判率最低,此时误判率为:

可以看出若要使得误判率≤1/2,则:

这说明了若想保持某固定误判率不变,布隆过滤器的bit数m与被add的元素数n应该是线性同步增加的。

五. 设计和应用布隆过滤器的方法

应用时首先要先由用户决定要add的元素数n和希望的误差率P。这也是一个设计完整的布隆过滤器需要用户输入的仅有的两个参数,之后的所有参数将由系统计算,并由此建立布隆过滤器。

系统首先要计算需要的内存大小m bits:

再由m,n得到hash function的个数:

至此系统所需的参数已经备齐,接下来add n个元素至布隆过滤器中,再进行query。

根据公式,当k最优时:

因此可验证当P=1%时,存储每个元素需要9.6 bits:

而每当想将误判率降低为原来的1/10,则存储每个元素需要增加4.8 bits:

这里需要特别注意的是,9.6 bits/element不仅包含了被置为1的k位,还把包含了没有被置为1的一些位数。此时的

才是每个元素对应的为1的bit位数。

   从而使得P(error)最小时,我们注意到:

中的

  ,即

此概率为某bit位在插入n个元素后未被置位的概率。因此,想保持错误率低,布隆过滤器的空间使用率需为50%。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
微信公众号是html页面吗,微信公众号网页开发
如果有相关接口权限无法开启,推荐使用:微信公众平台-开发-开发者工具-公众平台测试帐号开发
全栈程序员站长
2022/09/06
14.5K0
微信公众号是html页面吗,微信公众号网页开发
微信公众号网页开发之拍照、上传本地图片
JS-SDK说明文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#0
全栈程序员站长
2022/09/02
1.5K0
微信公众号x低代码,微搭公众号应用开发快速上手教程
基于大家对"漫话开发者"前面的微信支付x低代码、微信小程序消息推送x低代码等系列文章的关注,最近也有同学问到公众号相关的问题,今天就简单介绍下低代码开发的H5应用如何调用微信公众号的能力,目前的方式主要有如下两种,大家可按需选取适用方案。
漫话开发者
2023/01/28
2.5K0
微信公众号x低代码,微搭公众号应用开发快速上手教程
微信JSSDK接入Java版--步骤及问题处理和解决
可以关注测试微信号,查看效果  服务器是个人的。请不要恶意攻击。 JSSDK使用步骤 http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp142
小帅丶
2018/02/09
3.9K0
微信JSSDK接入Java版--步骤及问题处理和解决
微信公众号开发——2、微信网页开发
在公众号平台下,自定义菜单,添加菜单,并选择菜单内容跳转到指定页面地址即可(需认证后方可添加页面地址,个人账号暂不支持认证)。
全栈程序员站长
2022/09/01
7.8K0
Web端声纹识别
本文作者:IMWeb ssttm169 原文出处:IMWeb社区 未经同意,禁止转载 最近做一个微信的口令红包的功能,准备都要投入使用了, 老板突然发愁,他说 现在的羊毛党这么猖狂,一不小心,1
IMWeb前端团队
2019/12/03
3.3K0
Web端声纹识别
微信中页面二次分享小图标丢失问题
在我们有房APP1.1的版本中增加了房产资讯的功能,昨天晚上有同事在群里反馈从APP中分享的资讯到微信中,然后再次分享出去的时候标题和小图标不见了,见下图:
猿天地
2018/07/25
3.3K0
微信中页面二次分享小图标丢失问题
Java微信公众平台开发(十一)--微信JSSDK中Config配置 (一)在微信公众平台绑定安全域名(二)后端接口实现JS-SDK配置需要的参数 (三)页面实现JS-SDk中con
JSSDK曾经引爆前端以及后端的工程师,其魔性的力量毋庸置疑,在我们的技术眼里它的实现原理和根本是不能够被改变的,这篇文章就不对其js的实现做任何评价和解说了(因为我也不是很懂,哈哈),这里要说的是它的config配置实现,参考文档:http://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html !
用户2417870
2019/09/18
3.2K0
Java微信公众平台开发(十一)--微信JSSDK中Config配置

        (一)在微信公众平台绑定安全域名(二)后端接口实现JS-SDK配置需要的参数 (三)页面实现JS-SDk中con
Java调用微信扫一扫
公司公众号二次开发需要调用微信扫一扫接口,在网上查了很多相关资料感觉也不是特别的全,在此特意整理一遍资料,供给自己和大家参考,如有相关缺陷请大家指出。
gang_luo
2020/08/13
3.1K0
Java调用微信扫一扫
uni-app使用微信JS-SDK
前段时间因为修改bug的原因学习了下如何在uni-app下面使用多图上传,所以基于uni-app做了一个微信JS-SDK调用的Demo
薛定喵君
2021/07/28
7.2K0
微信公众号开发 —— 自定义分享
微信公众号开发JS-SDK说明文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 1.绑定JS域名,不需要加h
JaneYork
2023/10/11
5810
微信公众号开发 —— 自定义分享
Web前端学习 第11章 微信开发4 JS-SDK接口
微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。例如我们网页中希望实现扫一扫、获取本地相册、位置信息、分享功能等,都可以使用JS-SDK来实现。
学习猿地
2020/07/09
2.4K0
Web前端学习 第11章 微信开发4 JS-SDK接口
Java企业微信开发_07_JSSDK多图上传
 所有的JS接口只能在企业微信应用的可信域名下调用(包括子域名),可在企业微信的管理后台“我的应用”里设置应用可信域名。这个域名必须要通过ICP备案,不然jssdk会配置失败
shirayner
2018/08/10
3.6K0
Java企业微信开发_07_JSSDK多图上传
网站搜索框使用微信扫码
客户要求可以直接识别标签二维码对某些仪器设备进行管理,类似于淘宝搜索框可以直接拍照搜索商品一样。前面已经做了一个网页调用摄像头识别二维码的功能,此功能有两个缺陷:
用户6362579
2019/09/29
1.9K0
网站搜索框使用微信扫码
Yii2.0实现微信公众号后台开发
1.用户授权接口:获取access_token、openid等;获取并保存用户资料到数据库
botkenni
2019/09/02
9910
微信公众号开发之授权获取用户信息
测试号:找到 网页授权获取用户基本信息>点击修改>设置域名 服务号:找到 开发>接口权限>网页授权获取用户基本信息>>点击修改>设置域名
Javen
2018/08/21
3.7K1
微信公众号开发之授权获取用户信息
关于微信二次分享,描述变链接的解决方法(一)----文档说明
声明: 本篇博文只是个人工作中的分享总结,仅代表个人观点,虽然解决了不少网友的问题,但同时也引来了一些网友的不满,所以特此声明,当您遇到本博文解决不了的问题,可以尝试重新进行其他搜索或者一起交流,相信总归能解决,而不是言语攻击!该博文的解决方案毕竟不是万金油,解决不了所有问题! 前言: 最近工作中遇到了使用微信二次分享的时候,标题被截短,描述也变成了链接,图片也没有,运营人员半夜还在嚷嚷,无奈只好硬着头皮去百度,去google,但是悲催的是没有详细的解决方法,最终只能自己去研究,还好最终搞出来了,决定分享一
joshua317
2018/04/16
4.4K0
关于微信二次分享,描述变链接的解决方法(一)----文档说明
Java微信公众平台开发_07_JSSDK图片上传
(2)对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式 (即 key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
shirayner
2018/08/10
2.5K0
Java微信公众平台开发_07_JSSDK图片上传
微信分享等设置 -- 缩略图等
debug:测试各绑定事件传入的测试(PC端打开,控制台console能看到各传入参数),上线改为false appId:公众号的唯一标识,为了安全考虑,后端传过来 timestamp:签名时间戳,例如:1414587457 nonceStr:签名随机字符串,例如:Wm3WZYTPz0wzccnW signature:签名 -- 通过appId请求到access_token,然后通过access_token请求到jsapi_ticket,通过jsapi_ticket、timestamp、nonceStr、url用sha1()加密生成signature; 为了安全考虑,这四个参数都由后台请求或者生成,然后前端请求使用。参考:微信公众平台JS-SDK说明文档附录1-JS-SDK使用权限签名算法
Rattenking
2021/01/29
1.3K0
微信公众平台开发[2] —— 微信端分享功能
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/details/51870790
泥豆芽儿 MT
2018/09/11
5.7K0
微信公众平台开发[2] —— 微信端分享功能
推荐阅读
相关推荐
微信公众号是html页面吗,微信公众号网页开发
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档