Hash(哈希/散列)和Bloom Filter(布隆过滤器)
文章目录
- Hash(函数/表)
- Bloom Filter
- 布隆过滤器的误识别问题
- 总结
- 参考
Hash(函数/表)
Hash (中译为哈希,或者散列)函数在计算机领域,尤其是数据快速查找领域,加密领域用的极广。其作用是将一个大的数据集映射到一个小的数据集上面(这些小的数据集叫做哈希值,或者散列值)。Hash table(散列表,也叫哈希表),是根据哈希值(Key value)而直接进行访问的数据结构。也就是说,它通过把哈希值映射到表中一个位置来访问记录,以加快查找的速度。下面是一个典型的hash函数/表示意图:
哈希函数有以下两个特点:
- 如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的。
- 散列函数的输入和输出不是唯一对应关系的,如果两个散列值相同,两个输入值很可能是相同的。但也可能不同,这种情况称为“散列碰撞”(或者“散列冲突”)。上图中,John Smith和Sandra Dee就存在hash冲突。
Hash一个应用就是对数据集分类,比如上图,Hash值为0的表示可能在A集合中,Hash值为2的表示B集合中,依次类推,值为15的表示F集合中。但Hash冲突会在这里会导致严重的问题,对于一个未知的新值,其可能不属于上面任何一个集合,但由于冲突,其Hash值和上面的某一个相同,导致误报(因为事先我们不可能做一个含有无限多项输入的完整的Hash表,也就是原来的Hash函数不可能是完美的)。并且,hash冲突也会导致查找效率低下。
Bloom Filter
Bloom Filter是1970年由Bloom提出的。它实际上是一个很长的二进制向量和一系列随机映射函数(Hash函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。Bloom Filter广泛的应用于各种需要查询的场合中,如Oracle的数据库,Google的BitTable也用了此技术。
如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等数据结构都是这种思路. 但是随着集合中元素的增加,我们需要的存储空间越来越大,检索速度也越来越慢 ( O ( n ) , O ( l o g n ) , O ( 1 ) ) (O(n),O(logn),O(1)) (O(n),O(logn),O(1))。
这时候就可以利用哈希表这个数据结构(它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit array)中的一个点)。这样一来,我们只要看看这个点是不是1就知道可以集合中有没有它了。这就是Bloom Filter的基本思想。
但这时,哈希冲突会是一个问题:假设Hash函数是良好的,如果我们的位阵列长度为m个点,那么如果我们想将冲突率降低到例如 1%, 这个散列表就只能容纳 m / 100 m/100 m/100个元素。显然这就不叫空间效率了(Space-efficient)了。解决方法也简单,就是使用多个Hash,如果它们有一个说元素不在集合中,那肯定就不在。如果它们都说在,虽然也有一定可能性它们都在说谎,不过直觉上判断这种事情的概率是比较低的。这种多个Hash组成的数据结构就叫Bloom Filter。
一个Bloom Filter是基于一个m位的位向量 ( b 1 , … , b m ) (b_1,…,b_m) (b1,…,bm),这些位向量的初始值为0。另外,还有一系列的hash函数 ( h 1 , … , h k ) (h_1,…, h_k) (h1,…,hk),这些hash函数的值域属于1-m。下图是一个bloom filter插入x,y,z 并判断某个值w是否在该数据集的示意图:
上图中,m=18,k=3;插入x是,三个hash函数分别得到蓝线对应的三个值,并将对应的位向量改为1,插入y,z时,类似的,分别将红线,紫线对应的位向量改为1。查找时,当查找x时,三个hash值对应的位向量都为1,因此判断x在此数据集中。y,z也是如此。但是查找w时,w有个hash值对应的位向量为0,因此可以判断不在此集合中。但是,假如w的最后那个hash值比上图中的大1,这是就会认为w在此集合中,而事实上,w可能不在此集合中,因此可能出现误报。显然的,插入数据越多,1的位数越多,误报的概率越大。
Wiki的Bloom Filter词条有关于误报的概率的详细分析:Probability of false positives。从分析可以看出,当k比较大时,误报概率还是比较小的,因此这存储还是很空间有效滴。
Bloom Filter有以下几个特点:
- 不存在漏报(False Negative),即某个元素在某个集合中,肯定能报出来。
- 可能存在误报(False Positive),即某个元素不在某个集合中,可能也被爆出来。
- 确定某个元素是否在某个集合中的代价和总的元素数目无关。
优点:
相比于其它的数据结构,Bloom Filter在空间和时间方面都有巨大的优势。Bloom Filter存储空间和插入/查询时间都是常数。另外, Hash函数相互之间没有关系,方便由硬件并行实现。Bloom Filter不需要存储元素本身,在某些对保密要求非常严格的场合有优势。
缺点:
另外,一般情况下不能从Bloom Filter中删除元素. 我们很容易想到把位列阵变成整数数组,每插入一个元素相应的计数器加1, 这样删除元素时将计数器减掉就可以了。然而要保证安全的删除元素并非如此简单。首先我们必须保证删除的元素的确在Bloom Filter里面. 这一点单凭这个过滤器是无法保证的。另外计数器回绕也会造成问题。
布隆过滤器的误识别问题
上一节中提到,布隆过滤器的一个不足之处就是它可能把不在集合中的元素错判成集合中的元素,这在检验上被称为“假阳性”。这个概率很小,但是究竟有多小,是否可以忽略。
估算假阳性的概率并不难。假定布隆过滤器有m比特,里面有n个元素,每个元素对应k个信息指纹的哈希函数,当然这m比特里有些是1,有些是0。先来看看某个比特为零的概率。比如,在这个布隆过滤器中插入一个元素,它的第一个哈希函数会把过滤器中的某个比特置成1,因此,任何一个比特被置成1的概率是 1 m \frac{1}{m} m1,它依然是0的概率则是 1 − 1 m 1-\frac{1}{m} 1−m1。
对于过滤器中一个特定的位置,如果这个元素的k个哈希函数都没有把它设置成1, 其概率是 ( 1 − 1 m ) k \left(1-\frac{1}{m}\right)^k (1−m1)k。如果过滤器中插人的第二个元素,某个特定的位置依然没有被设置成1,其概率为 ( 1 − 1 m ) 2 k \left(1-\frac{1}{m}\right)^{2k} (1−m1)2k。如果插入了n个元素还没有把某个位置设置成1,其概率是 ( 1 − 1 m ) k n \left(1-\frac{1}{m}\right)^{kn} (1−m1)kn。
反过来,一个比特在插人了n个元素后,被置成1的概率则是 1 − ( 1 − 1 m ) k n 1-\left(1-\frac{1}{m}\right)^{k n} 1−(1−m1)kn。
现在假定这n个元素都放到布隆过滤器中了,新来一个不在集合中的元素,由于它的信息指纹的哈希函数都是随机的,因此,它的第一个哈希函数正好命中某个值为1的比特的概率就是上述概率。一个不在集合中的元素被误识别为在集合中,需要所有的哈希函数对应的比特值均为1, 其概率为
( 1 − [ 1 − 1 m ] k n ) k ≈ ( 1 − e − k n m ) k \left(1-\left[1-\frac{1}{m}\right]^{k n}\right)^k \approx\left(1-e^{-\frac{k n}{m}}\right)^k (1−[1−m1]kn)k≈(1−e−mkn)k
化简后为
p = ( 1 − e − ( m n ln 2 ) n m ) ( m n ln 2 ) \mathrm{p}=\left(1-e^{-\frac{\left(\frac{m}{n} \ln 2\right) n}{m}}\right)^{\left(\frac{m}{n} \ln 2\right)} p=(1−e−m(nmln2)n)(nmln2)
如果n比较大,可以近似为
( 1 − e − k ( n + 0.5 ) / ( m − 1 ) ) k ≈ ( 1 − e − k n m ) k \left(1-e^{-k(n+0.5) /(m-1)}\right)^k \approx\left(1-e^{-\frac{k n}{m}}\right)^k (1−e−k(n+0.5)/(m−1))k≈(1−e−mkn)k
假定一个元素用16比特,k=8,那么假阳性的概率是万分之五。在大部分应用中是可以忍受的。下表是不同的m/n比例,以及k情况下的假阳性概率(下表由原麦迪逊威斯康星大学曹培(Pei Cao)教授提供,她目前在Facebook任职)。
表23.1 不同 m/n 和 k 情况下,布隆过滤器的误识别概率
m/n | k | k=1 | k=2 | k=3 | k=4 | k=5 | k=6 | k=7 | k=8 |
---|---|---|---|---|---|---|---|---|---|
2 | 1.39 | 0.393 | 0.400 | ||||||
3 | 2.08 | 0.283 | 0.237 | 0.253 | |||||
4 | 2.77 | 0.221 | 0.155 | 0.147 | 0.160 | ||||
5 | 3.46 | 0.181 | 0.109 | 0.092 | 0.092 | 0.101 | |||
6 | 4.16 | 0.154 | 0.0804 | 0.0609 | 0.0561 | 0.0578 | 0.0638 | ||
7 | 4.85 | 0.133 | 0.0618 | 0.0423 | 0.0359 | 0.0347 | 0.0364 | ||
8 | 5.55 | 0.118 | 0.0489 | 0.0306 | 0.024 | 0.0217 | 0.0216 | 0.0229 | |
9 | 6.24 | 0.105 | 0.0397 | 0.0228 | 0.0166 | 0.0141 | 0.0133 | 0.0135 | 0.0145 |
10 | 6.93 | 0.0952 | 0.0329 | 0.0174 | 0.0118 | 0.00943 | 0.00844 | 0.00819 | 0.00846 |
11 | 7.62 | 0.0869 | 0.0276 | 0.0136 | 0.00864 | 0.0065 | 0.00552 | 0.00513 | 0.00509 |
12 | 8.32 | 0.08 | 0.0236 | 0.0108 | 0.00646 | 0.00459 | 0.00371 | 0.00329 | 0.00314 |
13 | 9.01 | 0.074 | 0.0203 | 0.00875 | 0.00492 | 0.00332 | 0.00255 | 0.00217 | 0.00199 |
14 | 9.7 | 0.0689 | 0.0177 | 0.00718 | 0.00381 | 0.00244 | 0.00179 | 0.00146 | 0.00129 |
15 | 10.4 | 0.0645 | 0.0156 | 0.00596 | 0.003 | 0.00183 | 0.00128 | 0.001 | 0.000852 |
16 | 11.1 | 0.0606 | 0.0138 | 0.005 | 0.00239 | 0.00139 | 0.000935 | 0.000702 | 0.000574 |
17 | 11.8 | 0.0571 | 0.0123 | 0.00423 | 0.00193 | 0.00107 | 0.000692 | 0.000499 | 0.000394 |
18 | 12.5 | 0.054 | 0.0111 | 0.00362 | 0.00158 | 0.000839 | 0.000519 | 0.00036 | 0.000275 |
19 | 13.2 | 0.0513 | 0.00998 | 0.00312 | 0.0013 | 0.000663 | 0.000394 | 0.000264 | 0.000194 |
20 | 13.9 | 0.0488 | 0.00906 | 0.0027 | 0.00108 | 0.00053 | 0.000303 | 0.000196 | 0.00014 |
21 | 14.6 | 0.0465 | 0.00825 | 0.00236 | 0.000905 | 0.000427 | 0.000236 | 0.000147 | 0.000101 |
22 | 15.2 | 0.0444 | 0.00755 | 0.00207 | 0.000764 | 0.000347 | 0.000185 | 0.000112 | 7.46e-05 |
23 | 15.9 | 0.0425 | 0.00694 | 0.00183 | 0.000649 | 0.000285 | 0.000147 | 8.56e-05 | 5.55e-05 |
24 | 16.6 | 0.0408 | 0.00639 | 0.00162 | 0.000555 | 0.000235 | 0.000117 | 6.63e-05 | 4.17e-05 |
25 | 17.3 | 0.0392 | 0.00591 | 0.00145 | 0.000478 | 0.000196 | 9.44e-05 | 5.18e-05 | 3.16e-05 |
26 | 18 | 0.0377 | 0.00548 | 0.00129 | 0.000413 | 0.000164 | 7.66e-05 | 4.08e-05 | 2.42e-05 |
27 | 18.7 | 0.0364 | 0.0051 | 0.00116 | 0.000359 | 0.000138 | 6.26e-05 | 3.24e-05 | 1.87e-05 |
28 | 19.4 | 0.0351 | 0.00475 | 0.00105 | 0.000314 | 0.000117 | 5.15e-05 | 2.59e-05 | 1.46e-05 |
29 | 20.1 | 0.0339 | 0.00444 | 0.000949 | 0.000276 | 9.96e-05 | 4.26e-05 | 2.09e-05 | 1.14e-05 |
30 | 20.8 | 0.0328 | 0.00416 | 0.000862 | 0.000243 | 8.53e-05 | 3.55e-05 | 1.69e-05 | 9.01e-06 |
31 | 21.5 | 0.0317 | 0.0039 | 0.000785 | 0.000215 | 7.33e-05 | 2.97e-05 | 1.38e-05 | 7.16e-06 |
32 | 22.2 | 0.0308 | 0.00367 | 0.000717 | 0.000191 | 6.33e-05 | 2.5e-05 | 1.13e-05 | 5.73e-06 |
总结
布隆过滤器背后的数学原理在于两个完全随机的数字冲突的概率很小,因此,可以在很小的误识别率条件下,用很少的空间存储大量信息。常见的补救误识别的办法是再在建立一个小的白名单,存储那些可能被误判的信息。由于布隆过滤器中只有简单的算术运算,因此它的速度很快,使用方便。
参考
吴军. 数学之美 : Beauty of mathematics[M]. 人民邮电出版社, 2014.
http://www.sigma.me/2011/09/13/hash-and-bloom-filter.html
Hash(哈希/散列)和Bloom Filter(布隆过滤器)相关推荐
- Bloom Filter 布隆过滤器
目录 Bloom Filter简介 布隆过滤器的原理 布隆过滤器的实现 使用guava实现 使用redis实现 Bloom Filter简介 Bloom Filter 布隆过滤器,由一个叫布隆的小伙子 ...
- 布隆过滤器速度_高并发系统一定要考虑的 Bloom Filter 布隆过滤器
开篇思考 你能想到哪些方式判断一个元素是否存在集合中? 布隆过滤器并不存储数据本身,那么是怎么做到过滤的? 布隆过滤器实现?参数配置? 一般我们用来判断一个元素是否存在,会想到用 List,Map,S ...
- Bloom Filter(布隆过滤器)的概念和原理
Bloom filter 适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集 基本原理及要点: 对于原理来说很简单,位数组+k个独立hash函数.将hash函数对应的值的位数组置1,查找时 ...
- Bloom Filter(布隆过滤器)的概念和原理(转)
Bloom filter 适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集 基本原理及要点: 对于原理来说很简单,位数组+k个独立hash函数.将hash函数对应的值的位数组置1,查找时 ...
- Bloom filter(布隆过滤器)学习与使用总结
一.简介 当我们使用主流数据结构如 Lists, Maps, Sets, Trees等等时,我可以得到确切的结果,无论这个数据存在或是不存在.概率数据结构能够提供一种基于内存的,快速的查找出一种可能而 ...
- Bloom Filter(布隆过滤器)
一.介绍 Bloom Filter是一个有m bits的bit array,每一个bit位都初始化为0.并且定义有k个不同的hash function,每个都以uniform random distr ...
- Bloom Filter布隆过滤器(解决redis缓存穿透)
目录 1.什么是布隆过滤器: 2.用BitSet手写简单的布隆过滤器 3.redis中的缓存穿透 4.Redis中的布隆过滤器 4.1 RedisBloom 4.1.1直接编译进行安装 4.1.2使用 ...
- Redis缓存击穿解决办法之bloom filter布隆过滤器
转载地址:http://blog.jobbole.com/113396/ 布隆过滤器:Google Guava类库源码分析及基于Redis Bitmaps的重构 2017/12/30 · 开发 · B ...
- hash table(完全散列实现的哈希表)
hash table(完全散列实现的哈希表) 完全散列 特点:静态的,创建时候完成了散列表的生成. 不可以删,也不可以增加数据.只可以修改数据. 内部用全域散列生成 #ifndef C11LEARN_ ...
最新文章
- 开发者需要了解的WebKit
- 在JavaScript里写类层次结构?别那么做!
- can差分线阻抗_CAN总线冷知识—边沿台阶是怎么来的?
- 9 [面向对象]-内置方法
- MySQL 如何查看表的存储引擎
- python教材答案第四章_第四章-习题答案
- 基于Web在线考试系统的设计与实现
- win10应用商店linux_解决win10应用商店“由于公司策略 此应用已被阻止”的方法...
- java语音实现_用JAVA实现语音交互的功能(即语音聊天室的功能)
- Cortana搜索框怎么在任务栏显示?
- 香港驾驶执照免试换领的官方收取费用是多少?可以在那些国家与地方使用。
- Method isEmpty in android.text.TextUtils not mocked
- 首款搭载HarmonyOS,分布式“智慧眼”!华为智选首款搭载HarmonyOS的智能摄像头正式发布...
- Spring Security,没有看起来那么复杂(附源码)
- 加速Pytorch安装的速度
- HTML+CSS梦幻西游动画
- van-search自动聚焦
- 《数据结构(C语言版)》严巍敏课件~第一章:绪论
- linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)
- golang计算任意两点间的方位角
热门文章
- 3375:弱哥德巴赫猜想
- 针对中国政府机构的准APT攻击样本Power Shell的ShellCode分析
- IDataParameter[]的用法
- 生物信息_MAF_Minor_Allele_Frequency
- wms分析系列文章 老罗
- 没想到 Hash 冲突还能这么玩,你的服务器中招了吗?
- Oracle rman备份级别,RMAN备份等级详解
- 在福州参加全国电子口岸学习
- 2020互联网数据分析师教程视频 统计学分析与数据实战 r语言数据分析实战 python数据分析实战 excel自动化报表分析实战 excel数据分析处理实战
- java merkle树,Java实战手写区块链中的Merkle树