布隆过滤器
布隆过滤器
声明:引用请注明出处http://blog.csdn.net/lg1259156776/
引言
在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中);在FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新元素时,将它和集合中的元素直接比较即可。[摘自吴军数学之美]。
实际上上面描述的功能就是查找算法的功能,关于查找可以参看我的博文《查找searching》,里面对查找的效率做了很好的说明。就单纯论查找的效率,我认为没有能超过哈希表(散列表)的了,因为它是通过散列函数直接映射到对应的存储位置,如果该位置上有它,则查找到。在我的博文《查找searching》和《散列表》中有着精彩论述。
但今天讲的这个布隆过滤器是从实际出发,兼顾查找效率和存储效率,因为实际上哈希表的存储效率是很低的,因为总是有一部分空间是浪费掉的,哈希函数再选取的时候的一个标准是尽量让数据均匀分布到数据表中。所以,布隆过滤器当然也是借助哈希函数以及随机数的原理兼顾查找效率和存储效率。
垃圾邮件的记录查询
公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。如果用哈希表,每存储一亿个 email 地址, 就需要 1.6GB 的内存(用哈希表实现的具体办法是将每一个 email 地址对应成一个八字节的信息指纹, 然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email 地址需要占用十六个字节。一亿个地址大约要1.6GB, 即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB 的内存。除非是超级计算机,一般服务器是无法存储的。[摘自吴军数学之美]。
当数据表比较小时,哈希表的存储效率低的问题不明显,哈希表是一个不错的选择;但当数据表比较大时,类似上面的垃圾邮件的存储与查询,哈希表的存储效率低下问题就很明显。
布隆过滤器的近似完美解决
布隆过滤器只需要哈希表 1/8 到 1/4 的大小就能解决垃圾邮件记与录查询的问题。
布隆过滤器(Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出的。它实际上是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。
构建布隆过滤器
仍然用垃圾邮件记录与查询为例,假定我们存储一亿个电子邮件地址,我们先建立一个十六亿二进制(比特),即两亿字节的向量,然后将这十六亿个二进制全部设置为零。对于每一个电子邮件地址
使用布隆过滤器
现在,让我们看看如何用布隆过滤器来检测一个可疑的电子邮件地址
布隆过滤器的不足
布隆过滤器决不会漏掉任何一个在黑名单中的可疑地址。但是,它有一条不足之处。也就是它有极小的可能将一个不在黑名单中的电子邮件地址判定为在黑名单中,因为有可能某个好的邮件地址正巧对应个八个都被设置成一的二进制位。好在这种可能性很小。我们把它称为误识概率。在上面的例子中,误识概率在万分之一以下。
布隆过滤器的误识识别问题
假设 Hash 函数以等概率条件选择并设置 Bit Array 中的某一位,m 是该位数组的大小,k 是 Hash 函数的个数,那么位数组中某一特定的位在进行元素插入时的 Hash 操作中没有被置位的概率是:
假定一个元素用16比特,
总结
布隆过滤器的好处在于快速,省空间。但是有一定的误识别率。常见的补救办法是在建立一个小的白名单,存储那些可能别误判的邮件地址。
布隆过滤器背后的数学原理在于两个完全随机的数字相冲突的概率很小,因此,可以在很小的误差识别率条件下,用很少的空间存储大量信息。
2015-9-24 艺少