【算法】布隆过滤器

 

题目描述面试

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

题目解析数据库

这是一道常常在面试中出现的算法题。凭借着题目极其容易描述,电面的时候也出现过。网页爬虫

不考虑细节的话,此题就是一个简单的查找问题。对于查找问题而言,使用散列表来处理每每是一种效率比较高的方案。数组

可是,若是你在面试中回答使用散列表,接下来面试官确定会问你:而后呢?若是你不能回答个因此然,面试官就会面无表情的通知你:今天的面试到此结束,咱们会在一周内给你答复。缓存

为何不能用散列表服务器

100亿是一个很大的数量级,这里每条url平均64字节,所有存储的话须要640G的内存空间。又由于使用了散列表这种数据结构,而散列表是会出现散列冲突的。为了让散列表维持较小的装载因子,避免出现过多的散列冲突,须要使用链表法来处理,这里就要存储链表指针。所以最后的内存空间可能超过1000G了。数据结构

只是存储个url就须要1000G的空间,老板确定不能忍!函数

位图(BitMap)性能

这个时候就须要拓展一下思路。首先,先来考虑一个相似但更简单的问题:如今有一个很是庞大的数据,好比有1千万个整数,而且整数的范围在1到1亿之间。那么如何快速查找某个整数是否在这1千万个整数中呢?

须要判断该数是否存在,也就是说这个数存在两种状态:存在(True)或者不存在(False)。

所以这里可使用一个存储了状态的数组来处理。这个数组特色是大小为1亿,而且数据类型为布尔类型(True或者False)。而后将这1千万个整数做为数组下标,将对应的数组值设置成True,好比,整数233对应下标为233的数组值设置为True,也就是array[233]=True。

这种操做就是位图法:就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是不少的状况。

另外,位图法有一个优点就是空间不随集合内元素个数的增长而增长。它的存储空间计算方式是找到全部元素里面最大的元素(假设为N),所以所占空间为:

 S=N/8  byte

所以,当N为1亿的时候须要12MB的存储空间。当N为10亿的时候须要120MB的存储空间了。当N的数量大到必定量级的时候,好比N为2^64这个海量级别的时候,须要消耗2048PB的存储空间,这个量级的BitMap,目前硬件上是支持不了的。

也就是说:位图法的所占空间随集合内最大元素的增大而增大。这就会带来一个问题,若是查找的元素数量少但其中某个元素的值很大,好比数字范围是1到1000亿,那消耗的空间不容乐观。

这个就是位图的一个不容忽视的缺点:空间复杂度随集合内最大元素增大而线性增大。对于开头的题目而言,使用位图进行处理,实际上内存消耗也是很多的。

所以,出于性能和内存占用的考虑,在这里使用布隆过滤器才是最好的解决方案:布隆过滤器是对位图的一种改进。

布隆过滤器

布隆过滤器(英语:BloomFilter)是1970年由Burton Bloom提出的。

它其实是一个很长的二进制矢量和一系列随机映射函数。

它能够用来判断一个元素是否在一个集合中。它的优点是只须要占用很小的内存空间以及有着高效的查询效率。

对于布隆过滤器而言,它的本质是一个位数组:位数组就是数组的每一个元素都只占用1bit,而且每一个元素只能是0或者1。

一开始,布隆过滤器的位数组全部位都初始化为0。好比,数组长度为m,那么将长度为m个位数组的全部的位都初始化为0。

0 0 0 0 0 0 0 0 0 0 0 0 1 。 。 。 。 。 m-2 m-1 

在数组中的每一位都是二进制位。

布隆过滤器除了一个位数组,还有K个哈希函数。当一个元素加入布隆过滤器中的时候,会进行以下操做:

•使用K个哈希函数对元素值进行K次计算,获得K个哈希值。•根据获得的哈希值,在位数组中把对应下标的值置为1。

举个例子,假设布隆过滤器有3个哈希函数:f1,f2,f3和一个位数组arr。如今要把2333插入布隆过滤器中:

•对值进行三次哈希计算,获得三个值n1,n2,n3。•把位数组中三个元素arr[n1],arr[n2],arr[3]都置为1。

当要判断一个值是否在布隆过滤器中,对元素进行三次哈希计算,获得值以后判断位数组中的每一个元素是否都为1,若是值都为1,那么说明这个值在布隆过滤器中,若是存在一个值不为1,说明该元素不在布隆过滤器中。

很明显,数组的容量即便再大,也是有限的。那么随着元素的增长,插入的元素就会越多,位数组中被置为1的位置所以也越多,这就会形成一种状况:当一个不在布隆过滤器中的元素,通过一样规则的哈希计算以后,获得的值在位数组中查询,有可能这些位置由于以前其它元素的操做先被置为 1 了。

如图1所示,假设某个元素经过映射对应下标为4,5,6这3个点。虽然这3个点都为1,可是很明显这3个点是不一样元素通过哈希获得的位置,所以这种状况说明这个元素虽然不在集合中,也可能对应的都是1,这是误判率存在的缘由。

因此,有可能一个不存在布隆过滤器中的会被误判成在布隆过滤器中。

这就是布隆过滤器的一个缺陷:存在误判。

可是,若是布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就必定不在布隆过滤器中。总结就是:

•布隆过滤器说某个元素在,可能会被误判•布隆过滤器说某个元素不在,那么必定不在

用英文说就是:Falseisalwaysfalse.Trueismaybetrue。

误判率

布隆过滤器能够插入元素,但不能够删除已有元素。其中的元素越多,falsepositiverate(误报率)越大,可是falsenegative(漏报)是不可能的。

因为公众号内对于数学公式的排版不太友好,小吴就不在这贴出来了,具体的计算公式能够在网上查找到。

补救方法

布隆过滤器存在必定的误识别率。常见的补救办法是在创建白名单,存储那些可能被误判的元素。好比你苦等的offer可能被系统丢在邮件垃圾箱(白名单)了。

使用场景

布隆过滤器的最大的用处就是,可以迅速判断一个元素是否在一个集合中。所以它有以下三个使用场景:

•网页爬虫对 URL 的去重,避免爬取相同的 URL 地址•进行垃圾邮件过滤:反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱(同理,垃圾短信)•有的黑客为了让服务宕机,他们会构建大量不存在于缓存中的key向服务器发起请求,在数据量足够大的状况下,频繁的数据库查询可能致使DB挂掉。布隆过滤器很好的解决了缓存击穿的问题。

回到问题

回到一开始的问题,若是面试官问你如何在海量数据中快速判断该url是否在黑名单中时,你应该回答使用布隆过滤器进行处理,而后说明一下为何不使用hash和bitmap,以及布隆过滤器的基本原理,最后你再谈谈它的使用场景那就更好了。

相关文章
相关标签/搜索