Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。它是一个判断元素是否存在集合的快速的几率算法。Bloom Filter有可能会出现错误判断,但不会漏掉判断。也就是Bloom Filter判断元素再也不集合,那确定不在。若是判断元素存在集合中,有必定的几率判断错误。所以,Bloom Filter”不适合那些“零错误的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter比其余常见的算法(如hash,折半查找)极大节省了空间。 php
它的优势是空间效率和查询时间都远远超过通常的算法,缺点是有必定的误识别率和删除困难。ios
Bloom Filter的详细介绍:Bloom Filterweb
计算某元素x是否在一个集合中,首先能想到的方法就是将全部的已知元素保存起来构成一个集合R,而后用元素x跟这些R中的元素一一比较来判断是否存在于集合R中;咱们能够采用链表等数据结构来实现。可是,随着集合R中元素的增长,其占用的内存将愈来愈大。试想,若是有几千万个不一样网页须要下载,所需的内存将足以占用掉整个进程的内存地址空间。即便用MD5,UUID这些方法将URL转成固定的短小的字符串,内存占用也是至关巨大的。算法
因而,咱们会想到用Hash table的数据结构,运用一个足够好的Hash函数将一个URL映射到二进制位数组(位图数组)中的某一位。若是该位已经被置为1,那么表示该URL已经存在。数据库
Hash存在一个冲突(碰撞)的问题,用同一个Hash获得的两个URL的值有可能相同。为了减小冲突,咱们能够多引入几个Hash,若是经过其中的一个Hash值咱们得出某元素不在集合中,那么该元素确定不在集合中。只有在全部的Hash函数告诉咱们该元素在集合中时,才能肯定该元素存在于集合中。这即是Bloom-Filter的基本思想。数组
原理要点:一是位数组, 而是k个独立hash函数。服务器
1)位数组:网络
假设Bloom Filter使用一个m比特的数组来保存信息,初始状态时,Bloom Filter是一个包含m位的位数组,每一位都置为0,即BF整个数组的元素都设置为0。数据结构
2)添加元素,k个独立hash函数ide
为了表达S={x1, x2,…,xn}这样一个n个元素的集合,Bloom Filter使用k个相互独立的哈希函数(Hash Function),它们分别将集合中的每一个元素映射到{1,…,m}的范围中。
当咱们往Bloom Filter中增长任意一个元素x时候,咱们使用k个哈希函数获得k个哈希值,而后将数组中对应的比特位设置为1。即第i个哈希函数映射的位置hashi(x)就会被置为1(1≤i≤k)。
注意,若是一个位置屡次被置为1,那么只有第一次会起做用,后面几回将没有任何效果。在下图中,k=3,且有两个哈希函数选中同一个位置(从左边数第五位,即第二个“1“处)。
3)判断元素是否存在集合
在判断y是否属于这个集合时,咱们只须要对y使用k个哈希函数获得k个哈希值,若是全部hashi(y)的位置都是1(1≤i≤k),即k个位置都被设置为1了,那么咱们就认为y是集合中的元素,不然就认为y不是集合中的元素。下图中y1就不是集合中的元素(由于y1有一处指向了“0”位)。y2或者属于这个集合,或者恰好是一个false positive。
Bloom Filter的缺点:
1)Bloom Filter没法从Bloom Filter集合中删除一个元素。由于该元素对应的位会牵动到其余的元素。因此一个简单的改进就是 counting Bloom filter,用一个counter数组代替位数组,就能够支持删除了。 此外,Bloom Filter的hash函数选择会影响算法的效果。
2)还有一个比较重要的问题,如何根据输入元素个数n,肯定位数组m的大小及hash函数个数,即hash函数选择会影响算法的效果。当hash函数个数k=(ln2)*(m/n)时错误率最小。在错误率不大于E的状况 下,m至少要等于n*lg(1/E) 才能表示任意n个元素的集合。但m还应该更大些,由于还要保证bit数组里至少一半为0,则m应 该>=nlg(1/E)*lge ,大概就是nlg(1/E)1.44倍(lg表示以2为底的对数)。
举个例子咱们假设错误率为0.01,则此时m应大概是n的13倍。这样k大概是8个。
注意:
这里m与n的单位不一样,m是bit为单位,而n则是以元素个数为单位(准确的说是不一样元素的个数)。一般单个元素的长度都是有不少bit的。因此使用bloom filter内存上一般都是节省的。
通常BF能够与一些key-value的数据库一块儿使用,来加快查询。因为BF所用的空间很是小,全部BF能够常驻内存。这样子的话,对于大部分不存在的元素,咱们只须要访问内存中的BF就能够判断出来了,只有一小部分,咱们须要访问在硬盘上的key-value数据库。从而大大地提升了效率。
一个Bloom Filter有如下参数:
m | bit数组的宽度(bit数) |
n | 加入其中的key的数量 |
k | 使用的hash函数的个数 |
f | False Positive的比率 |
Bloom Filter的f知足下列公式:
在给定m和n时,可以使f最小化的k值为:
此时给出的f为:
根据以上公式,对于任意给定的f,咱们有:
BloomFilter有个缺点,就是不支持删除操做,由于它不知道某一个位从属于哪些向量。那咱们能够给Bloom Filter加上计数器,添加时增长计数器,删除时减小计数器。
为了能在服务器之间更快地经过网络传输Bloom Filter,咱们有方法能在已完成Bloom Filter以后,获得一些实际参数的状况下进行压缩。
通常Bloom-Filter能够与一些key-value的数据库一块儿使用,来加快查询。
Google的BigTable也使用了Bloom Filter,以减小不存在的行或列在磁盘上的查询,大大提升了数据库的查询操做的性能。
在Internet Cache Protocol中的Proxy-Cache不少都是使用Bloom Filter存储URLs,除了高效的查询外,还能很方便得传输交换Cache信息。
1)P2P网络中查找资源操做,能够对每条网络通路保存Bloom Filter,当命中时,则选择该通路访问。
3)检测广播消息包的环路,将Bloom Filter保存在包里,每一个节点将本身添加入Bloom Filter。
4)信息队列管理,使用Counter Bloom Filter管理信息流量。
像网易,QQ这样的公众电子邮件(email)提供商,老是须要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。
一个办法就是记录下那些发垃圾邮件的 email地址。因为那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则须要大量的网络服务器。
而Bloom Filter只须要哈希表 1/8到 1/4 的大小就能解决一样的问题。
BloomFilter决不会漏掉任何一个在黑名单中的可疑地址。而至于误判问题,常见的补救办法是在创建一个小的白名单,存储那些可能别误判的邮件地址。
问题实例】 给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。若是是三个乃至n个文件呢?
根据这个问题咱们来计算下内存的占用,4G=2^32大概是40亿*8大概是340亿bit,n=50亿,若是按出错率0.01算须要的大概是650亿个bit。 如今可用的是340亿,相差并很少,这样可能会使出错率上升些。另外若是这些urlip是一一对应的,就能够转换成ip,则大大简单了。