布隆过滤器 (Bloom Filter)是由Burton Howard Bloom于1970年提出,它是一种space efficient的几率型数据结构,用于判断一个元素是否在集合中。html
看看下面几个问题:算法
以上这些场景有个共同的问题:如何查看一个东西是否在有大量数据的池子里面。数组
一般作法有如下几种思路:网络
问题:数据结构
能够明显的看到,原始数据通过哈希函数的映射后称为了一个个的哈希编码,数据获得压缩。哈希函数是实现哈希表和布隆过滤器的基础。 dom
布隆过滤器(Bloom Filter)的核心实现是一个超大的位数组和几个哈希函数。假设位数组的长度为m,哈希函数的个数为k函数
以上图为例,具体的操做流程:假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每一个位都设置位0。对于集合里面的每个元素,将元素依次经过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,而后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候,一样的方法将W经过哈希映射到位数组上的3个点。若是3个点的其中有一个点不为1,则能够判断该元素必定不存在集合中。反之,若是3个点都为1,则该元素可能存在集合中。注意:此处不能判断该元素是否必定存在集合中,可能存在必定的误判率。能够从图中能够看到:假设某个元素经过映射对应下标为4,5,6这3个点。虽然这3个点都为1,可是很明显这3个点是不一样元素通过哈希获得的位置,所以这种状况说明元素虽然不在集合中,也可能对应的都是1,这是误判率存在的缘由。编码
一个empty bloom filter是一个有m bits的bit array,每个bit位都初始化为0。而且定义有k个不一样的hash function,每一个都以uniform random distribution将元素hash到m个不一样位置中的一个。在下面的介绍中n为元素数,m为布隆过滤器或哈希表的slot数,k为布隆过滤器重hash function数。spa
为了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性。
具体算法推导和证实请参看详细连接:布隆过滤器详解