深度解析布谷鸟过滤器

0 引言

布隆过滤器(Bloom Filter),诞生于UNIX元年(1970年)的一个老牛逼的过滤器,与时间戳同寿,经久不衰老而弥坚,查重性能至今令人非常满意。美中不足的是有一点误判率并且支持删除元素比较困难。44年后,卡内基梅隆大学的Bin Fan等人发了篇文章,标题是《布谷鸟过滤器:雀食吊过布隆》,号称有更好的空间利用率、更高的性能、更低的误判率、对删除操作更好的支持。听起来有点东西,深入文章研究下。

1 相关研究(又名:全靠同行承托)

1.1 布隆过滤器和它的各路变种

1.1.1 标准布隆过滤器

标准布隆过滤器仅支持插入查找两个操作,并且存在一个假阳率ε,如果希望假阳率更低,那么就需要付出更高的空间代价。

通俗的翻译一下假阳率,这个概念后文可能还会出现。我向布隆过滤器查询,a是否存在,如果返回不存在,那就100%不存在,不接受反驳。如果返回存在,那就要小心了,因为它有ε的概率是错的,实际上a并不存在。当然,我实际工作中使用一般会让ε0.000001这样很小很小,1亿次错个1百1千次之类的,可以接受。

布隆过滤器的工作原理非常简单,k个随机哈希函数和1个长长的bit数组(初始为全0),插入一个元素时,使用k个哈希函数进行计算,并根据计算结果把bit数组中对应的k个比特位置为1。查询的时候也是同理,进行相应的计算后,查询对应的k个位置是不是都为1,如果都是1,那么说明已存在,否则说明不存在。想必读到这里,已经能领悟到假阳率出现的根源了吧。

在实际生产环境中,我们首先选取一个ε值,例如我用的是0.000001,即百万分之一,与之对应的哈希函数个数k的选取,则需要一点小小的计算:

log ⁡ 2 1 ε \log_2 \frac1 ε log2​ε1​

通过一系列的概率极限偏微分方程的计算可以得到这个值,是空间最优的一个解,这里就不做推导了。根据我的ε值可以计算得到,k=20,即我们需要设置20个哈希函数。在最优解下,每个元素需要的存储空间为:

1 ln ⁡ 2 ∗ log ⁡ 2 1 ε \frac1 {\ln2}*\log_2 \frac1 ε ln21​∗log2​ε1​
(注:原论文中采用的系数1.44为近似值,实际公示推导结果为 1 ln ⁡ 2 \frac 1 {\ln2} ln21​)

则如果需要对n个元素做查重需要的空间如下:

n ∗ 1 ln ⁡ 2 ∗ log ⁡ 2 1 ε n*\frac1 {\ln2}*\log_2 \frac1 ε n∗ln21​∗log2​ε1​

显然,单个元素的存储空间只与ε有关,而与元素本身的大小并无关系。根据信息论原理单个元素需要的最小空间为 log ⁡ 2 1 ε \log_2 \frac1 ε log2​ε1​,布隆过滤器需要的空间仅比信息论最小值高约44%,这样的空间利用率,不可谓不高效。

标准布隆过滤器优点突出,缺点也非常显著,那就是它不支持删除操作。为了解决这一点,有人提出了一种布隆过滤器的扩展,Counting Bloom filters ,我也不知道怎么翻译,就叫计数布隆过滤器吧。

1.1.2 计数布隆过滤器(CBF)

首先思考下为什么标准布隆过滤器不支持删除操作,插入操作是把对应的k位bit置为1,那删除的时候我置为0不就行了?显然是不行的,万一元素B有某一位bit[x]和元素A重复了,那在删除A的过程中,bit[x]就置为0了,那么我再去查找B,就会发现bit[x]=0,B不存在,那就完犊子了,因为我们并没有删除过B。

要解决这一问题也非常简单,无非是因为一个bit位能包含的信息太少了,这个问题加钱就能解决。把每个bit位改成一个计数器,本来bit[x]只能0 ⇒ \rArr ⇒ 1,现在有了计数器,就可以bit[x]+1了,删除的时候bit[x]-1。对于上述A, B元素,bit[x]=2,删除A元素bit[x]=1了,丝毫不会影响到B元素后续的查找。

关于计数器的位数的计算,有点高深,有一步什么斯特林公式的变换完全没看懂,反正4位就很够用了。1个bit位需要对应成一个4位的计数器,所以CBF的空间开销差不多是标准布隆的4倍。

这种计数器的方法可以说是简单粗暴,在空间的使用上也有些奢侈了,显然还有进一步的优化空间。

1.1.3 Blocked Bloom filters

来自卡尔斯鲁厄大学的FELIX PUTZE等人在2007年的研究《Cache-, Hash- and Space-Efficient Bloom Filters》,这个我也没找到啥中文资料,冒昧翻译为分块布隆过滤器,这是标准布隆过滤器的又一变种,它提升的方向是进一步的提高性能。布隆过滤器本身性能已经非常优越了,但仍有某些场景对性能有更极致的追求,例如阿里云对RuntimeFilter进行性能优化的时候就把标准布隆过滤器替换成了Blocked Bloom filters。

性能提升付出的代价是更高的假阳率,多用了一点空间,同时它依然不支持删除操作。

这个变种并不符合我的工作需要,所以没有进行更深入的学习研究,1.1.2提到了CBF对空间的浪费,下面来看下如何对其进行优化提升。

1.1.4 d-left Counting Bloom filters

翻译这活真不是人干的,我绞尽脑汁给它起了个名字:基于多子表均衡左优先存储哈希表的计数布隆过滤器。

要理解这个变种,首先要理解d-left hashing,我自认为翻译的还是到位的,多子表均衡(d)左优先存储(left)哈希表(hashing)。把整个哈希表分成d个从左到右连着的子表,每个子表对应一个不同的哈希函数,当加入一个新元素时,分别计算d个哈希函数,得到d个不同的位置,然后将新元素加入到负载最轻的位置,如果有多个子表负载相同且均为最轻,则默认加入到最左边的子表。同理,进行查找操作时自然也就需要分别进行d次计算和查找。

虽然这种过滤器的名字里依旧包含Counting,但这只是表示它是CBF的变种,实际它已经抛弃了计数器,转而为每个元素存储了一个指纹,而这个指纹,正是使用了d-left hashing进行存储的。需要进行删除操作时,直接从d-left hashing中移除对应的指纹即可。

通过d-left hashing存储指纹的方式,d-left CBF可以比CBF节省约50%的存储空间,亦即标准布隆过滤器的1.5~2倍左右。

d-left CBF和本文将重点介绍的布谷鸟过滤器有很多相似之处,这里暂时按下不表,先看另一种非常流行的过滤器——Quotient filters

1.1.5 Quotient filters

商过滤器,中文资料也是乏善可陈,因此我辛苦一下,在这里做一个最通俗易懂的中文讲解。

据说商过滤器是诞生于《计算机程序设计艺术(第3卷)》6.4节的习题13,我特地去看了下原题,嗯,劳资题目都看不懂啊!我要有这么难的作业必不可能拿到毕业证书啊!

言归正传,商过滤器只进行一次哈希函数计算,显然比上述的k次d次计算来的效率要更高,另外商过滤器也支持删除操作。这两点就是他相较于标准布隆过滤器的主要优点,没错,标准布隆过滤器就是战斗力计算单位。

首先我们构造一个 3 ∗ 2 r 3*2^r 3∗2rbit位长度的哈希表,给每3位bit对应分配一个槽,即有 2 r 2^r 2r个槽,构造好之后我们暂且把他放在一边,等会儿再说怎么用。

然后我们来对一个元素x进行以下3次运算:

① 对元素x进行一次哈希函数的运算,这里记为 f ( x ) f(x) f(x);
② 对 f ( x ) f(x) f(x)做一次除法运算,取其商 f q ( x ) = ⌊ f ( x ) / 2 r ⌋ f_q(x)=\lfloor f(x)/2^r\rfloor fq​(x)=⌊f(x)/2r⌋;
③ 对 f ( x ) f(x) f(x)做一次模运算,得到余数 f r ( x ) = f ( x ) m o d f q ( x ) f_r(x)=f(x) \mod {f_q(x)} fr​(x)=f(x)modfq​(x);

假定8个元素,分别进行上述运算后,得到下面这样一组值,接下来我们把这组值填入到之前构造的哈希表中。

f f f f q f_q fq​ f r f_r fr​
A 1 a
B 1 b
C 3 c
D 3 d
E 3 e
F 4 f
G 6 g
H 6 h

填入结果如下图所示

表格上方的0~9数字,用于表示每个槽的索引,根据商 f q f_q fq​的值,将 f r f_r fr​填入与 f q f_q fq​对应的索引中。如第一个放入的A,商为1,则把a填入到索引为1的槽内,第二个放入B的时候,发现商也是1,而索引1的槽已经被A占用了,那就往后顺延一格,存入索引为2的槽内。C的商为3,则存入索引为3的槽内,DEFGH同理往后顺延。

前文我们说过,给每3位bit对应分配一个槽,槽存储了 f r f_r fr​的值,3位bit则另有他用。这3位bit分别表示:

  • is_occupied: 是否被正确的占据了。重点不是这个槽有没有被占据,而是有没有被正确的占据,即有没有与槽位索引对应的商值。如A的商是1,那么槽位1就被正确的占据了。再看槽位6,G的商是6,而这个槽位已经被F占了,但槽位6仍然是拥有一个与它对应的商值的,虽然G不在槽位6,槽位6的is_occupied依然是1;
  • is_continuation: 是否连续的。以DE为例,他们的商值都是3,因为槽位3已经被C占据,他们被迫往后顺延,这种情况我们称DE对于C而言是连续,因此DE的is_continuation值均为1。而F的商值是6,和CDE就不再连续了,所以F这个槽位的is_continuation值为0;
  • is_shifted: 是否被移动了。主语是当前槽位内的值。如B,根据商值它应该放在槽位1,但被迫往后顺延到了槽位2,因此它的is_shifted值为1。C则原本就在槽位3,is_shifted为0,DEFGH都是同理,被迫往后顺延了,因此is_shifted都是1;

1.2 对比总结

过滤器类型 空间消耗 查找开销 删除支持
标准布隆过滤器 1 k no
分块布隆过滤器 1x 1 no
计数布隆过滤器 3x ~ 4x k yes
d-left CBF 1.5x ~ 2x d yes
商过滤器 1x ~ 1.2x ⩾ \geqslant ⩾ 1 yes
布谷鸟过滤器 ⩽ \leqslant ⩽ 1x 2 yes

注:k和d在上文中都有提及,不再解释;1x表示比1多一点点,3x ~ 4x表示为1的3~4倍左右;

相关的一些过滤器变种在这里就介绍完了,关于布谷鸟过滤器的深入研究,将在下篇中继续。

深度解析布谷鸟过滤器(上篇)相关推荐

  1. 深度解析dubbo源码系列

    以下文章均基于dubbo v2.6.x 持续更新中- dubbo spi 扩展技术,框架基石 <深度解析dubbo扩展技术dubbo spi(注解)> <深度解析dubbo扩展技术d ...

  2. Kafka深度解析(如何在producer中指定partition)(转)

    原文链接:Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅的消息系统.主要设计目标如下: 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能 ...

  3. 深度解析数据湖存储方案Lakehouse架构

    简介:从数据仓库.数据湖的优劣势,湖仓一体架构的应用和优势等多方面深度解析Lakehouse架构. 作者:张泊 Databricks 软件工程师 Lakehouse由lake和house两个词组合而成 ...

  4. 深度解析 | K8S API Server之请求处理

    对Kubernetes API 请求流程进行解析.后续还将对API Server的存储和扩展点等主题进行介绍.本篇是Kubernetes API Server系列第三篇. 请求和处理流程    在介绍 ...

  5. Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN

    本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep learning简介 [2]Deep Learning训练过程 [3]Deep Learning模型之 ...

  6. [转]Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN

    Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN 原文地址:http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位 ...

  7. RedisBloom 插件布隆过滤器,布谷鸟过滤器,Count-Min Sketch,TOPK使用详解

    文章目录 前言 一.如何安装 二.布隆过滤器 1. 使用介绍 2. 命令详解 三.布谷鸟过滤器 1. 使用介绍 2. 命令详解 三.Count-Min Sketch 1. 使用介绍 2. 命令详解 四 ...

  8. 特别策划 | 5G最新进展深度解析2020版-技术应用篇(68页附下载)

    文章版权所有,未经授权请勿转载或使用 笔者在2019年发布了<5G最新进展深度解析>系列之<全球市场篇>.<国内市场篇>.<技术应用篇>.2020年,尽 ...

  9. 特别策划|5G最新进展深度解析2022版—技术篇(71页附下载)

    关注公号回复"220323"下载71页PDF版报告原文 2021年初,「5G行业应用」曾推出<5G最新进展深度解析>系列,包括技术应用篇.国内市场篇和全球市场篇,得到读 ...

最新文章

  1. MATLAB红色分量图如何合成,如何修改一张图片中红色分量的值?
  2. Servlet重定向的过程(二)
  3. Nginx和PHP-FPM的启动、重启、停止脚本分享
  4. 4 .2 .4 配置存储系统
  5. C#父类与子类(多态性)
  6. 5.剑指Offer --- 优化时间和空间效率
  7. Microsoft Office 2019 正式版 安装记录
  8. 什么是WBS分解法?
  9. 16. 二叉哥的二叉树
  10. 阿尔萨斯监控平台普罗米修斯监控平台对服务器资源的监控
  11. 如何用Python从海量文本抽取主题
  12. ps3能装linux上网,上百度聊QQ 装Linux让你的PS3无所不能
  13. 2021年中国数据安全行业发展现状及未来发展前景分析:数据安全市场快速增长[图]
  14. 正身以俟时,守己而律物
  15. c语言中03怎么表示成30,C语言入门篇-03
  16. matlab批量合并txt文件
  17. python获取职位信息
  18. Linux/Windos搭建安装Kaldi环境实现ASR语音识别
  19. 城市公交查询系统c语言,城市公交查询系统.doc
  20. 计算机毕业设计 SpringBoot+Vue党建管理系统 教育党建系统 智慧党建系统 党建信息管理系统Java Vue MySQL数据库 远程调试 代码讲解

热门文章

  1. Python Redis Stream 消息队列 消费组
  2. Linux下查看硬盘是固态硬盘还是机械硬盘
  3. 情人节拷问:恋爱都谈不好,还谈什么客户?
  4. Java字符串替换指定位置的字符
  5. Vue 项目快速入门
  6. SAP Marketing Cloud Restful API SDK 使用案例分享
  7. 【百家稷学】基于华为NAIE与Mindspore的视觉实训(东莞华为松山湖研究所实训)...
  8. LinqToObject(2)——自由自在
  9. java初学者最关心的五个问题
  10. 语音学习笔记1------matlab实现自相关函数法基音周期提取