初探布隆过滤器

前言

若是想判断一个元素是否是在一个集合里,通常想到的是将集合中全部元素保存起来,而后经过比较肯定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路,通常来说,计算机中的集合是用哈希表(Hash table)来存储的。html

可是随着集合中元素的增长,咱们须要的存储空间愈来愈大。同时检索速度也愈来愈慢,上述三种结构的检索时间复杂度分别为 O(n),O(logn),O(1)。其中时间复杂度最低的hash table的空间复杂度是O(N),在面对数以亿记的数据时,这种实现方式的存储成本会比较大。面试

好比说,一个像 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,老是须要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。因为那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则须要大量的网络服务器。若是用哈希表,每存储一亿 个 email 地址, 就须要 1.6GB 的内存(用哈希表实现的具体办法是将每个 email 地址对应成一个八字节的信息指纹(详见:china.googleblog.com/2006/08/blo… ), 而后将这些信息指纹存入哈希表,因为哈希表的存储效率通常只有 50%,所以一个 email 地址须要占用十六个字节。一亿个地址大约要 1.6GB, 即十六亿字节的内存)。所以存贮几十亿个邮件地址可能须要上百 GB 的内存。除非是超级计算机,通常服务器是没法存储的 -- Google黑板报 china.googleblog.com/2007/07/blo…算法

那么有没有其余的方式来实现一样的事呢?本文介绍一下布隆过滤器及其原理和应用。数据库

若是面试官问你,一个网站有 100 亿 url 存在一个黑名单中,每条 url 平均 64 字节。问这个黑名单要怎么存?若此时随便输入一个 url,如何判断该 url 是否在这个黑名单中?数组

正文

布隆过滤器(bloom filter)能够用于检索一个元素是否在一个集合中。它的优势是空间效率和查询时间都远远超过通常的算法,缺点是有必定的误识别率和删除元素困难缓存

通常的布隆过滤器会提供两个方法:TestAdd服务器

Test用来确认某个元素是否在集合内。若是它返回:网络

  1. false,那么这个元素必定不在集合内。
  2. true,那么这个元素只是有可能在集合里面,部分不在集合内的元素会被误判在集合内,布隆过滤器的假正率(False positive rate)用来描述这一律率,其随着数据的增大而增大,同时也和所使用的hash函数有关

假正率就是实际数据为false,预测数据(布隆过滤器的判断)为true,的几率。 数据结构

Add用来添加元素到集合内。并发

这里没有删除,在讲到原理部分时会比较清楚的讲解为何布隆过滤器删除元素困难。

布隆过滤器原理

布隆过滤器的原理是,当一个元素被加入集合时,经过K个hash函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,咱们只要看看这些点是否是都是1就(大约)知道集合中有没有它了:若是这些点有任何一个0,则被检元素必定不在;若是都是1,则被检元素极可能在。这就是布隆过滤器的基本思想。

数据结构

布隆过滤器是一个 bit 向量,长这样:

往布隆过滤器中添加一个元素时,咱们将这个值传入 k 个hash函数,而后将结果位置bit置为1,在图中例子向量或者说数组的长度为50,使用3个hash函数。

当咱们要判断一个元素是否在布隆过滤器中时,咱们把这个值传入k个hash函数中得到映射的k个点。这一次咱们确认下是否全部的点都被置为1了,若是有某一位没有置为1则这个元素确定不在集合中。若是都在那这个元素就有可能在集合中

看完原理后咱们就知道了为何布隆过滤器中有可能误判以及元素越多假正率(误判概率)越大,由于随着增长的值愈来愈多,被置为 1 的 bit 位也会愈来愈多,这样某个值即便没有被存储过,可是有可能元素的hash函数返回的k个 bit 位都被其余值置位了 1 ,那么程序仍是会判断这个值存在。

The false positive probability p as a function of number of elements n in the filter and the filter size m.

同时hash函数的个数也须要权衡,个数越多则布隆过滤器 bit 位置位 1 的速度越快,且布隆过滤器的效率越低;可是若是太少的话,那咱们的误报率会变高。

关于如何选择合适的hash函数个数k和布隆过滤器长度m,有人推导出了公式以下

详情可在 Probabilistic Data structures: Bloom filter中了解,这里不赘述。

删除困难

了解了布隆过滤器的原理后咱们就知道在布隆过滤器中删除元素几乎是不可能的了,不过其实有一种叫作counting bloom filters的数据结构

使用场景

利用布隆过滤器减小磁盘IO或者网络请求

比较场景的例子是用布隆过滤器减小磁盘IO或者网络请求(都是代价很高的操做)查找不存在的key的时候。

布隆过滤器返回false那么这个值确定不在

由于一旦一个值一定不存在的话,咱们能够不用进行后续昂贵的查询请求。若是它在,那么咱们就去作查找,因为误判率不会过高因此这种代价通常也能承受。

  • Google 著名的分布式数据库 Bigtable 使用了布隆过滤器来查找不存在的行或列,以减小磁盘查找的IO次数
  • 在不少Key-Value系统中也使用了布隆过滤器来加快查询过程,如 Hbase,Accumulo,Leveldb,通常而言,Value 保存在磁盘中,访问磁盘须要花费大量时间,然而使用布隆过滤器能够快速判断某个Key对应的Value是否存在,所以能够避免不少没必要要的磁盘IO操做,
  • 好比高并发秒杀系统中抢红包系统中判断用户是否今天已领取红包
  • 在爬虫系统中,咱们须要对URL进行去重,已经爬过的网页就能够不用爬了。可是URL太多了,几千万几个亿,若是用一个集合装下这些URL地址那是很是浪费空间的。这时候就能够考虑使用布隆过滤器。它能够大幅下降去重存储消耗,只不过也会使得爬虫系统错过少许的页面。
  • 邮箱系统的垃圾邮件过滤功能也广泛用到了布隆过滤器,由于用了这个过滤器,因此平时也会遇到某些正常的邮件被放进了垃圾邮件目录中,这个就是误判所致,几率很低。
  • Redis防雪崩(缓存穿透)

后记

参考资料

www.sigma.me/2011/09/13/…

hackernoon.com/probabilist…

www.jasondavies.com/bloomfilter…

相关文章
相关标签/搜索