布隆过滤器
布隆过滤器是一种概率空间高效的数据结构。它与hashmap非常相似,用于检索一个元素是否在一个集合中。它在检索元素是否存在时,能很好地取舍空间使用率与误报比例。正是由于这个特性,它被称作概率性数据结构(probabilistic
data structure)。
空间效率
我们来仔细地看看它的空间效率。如果你想在集合中存储一系列的元素,有很多种不同的做法。你可以把数据存储在hashmap,随后在hashmap中检索元素是否存在,hashmap的插入和查询的效率都非常高。但是,由于hashmap直接存储内容,所以空间利用率并不高。
如果希望提高空间利用率,我们可以在元素插入集合之前做一次哈希变换。还有其它方法呢?我们可以用位数组来存储元素的哈希值。还有吗,还有吗?我们也允许在位数组中存在哈希冲突。这正是布隆过滤器的工作原理,它们就是基于允许哈希冲突的位数组,可能会造成一些误报。在布隆过滤器的设计阶段就允许哈希冲突的存在,否则空间使用就不够紧凑了。
当使用列表或者集合时,空间效率都是重要且显著的,那么布隆过滤器就应当被考虑。
布隆过滤器基础
布隆过滤器是 N
位的位数组,其中 N
是位数组的大小。它还有另一个参数 k
,表示使用哈希函数的个数。这些哈希函数用来设置位数组的值。当往过滤器中插入元素 x
时, h1(x)
, h2(x)
, …,
hk(x)
所对应索引位置的值被置“1”,索引值由各个哈希函数计算得到。注意,如果我们增加哈希函数的数量,误报的概率会趋近于0.但是,插入和查找的时间开销更大,布隆过滤器的容量也会减小。
为了用布隆过滤器检验元素是否存在,我们需要校验是否所有的位置都被置“1”,与我们插入元素的过程非常相似。如果所有位置都被置“1”,那也就意味着该元素 很有可能
存在于布隆过滤器中。若有位置未被置“1”,那该元素一定不存在。
简 单的python实现
如果想实现一个简单的布隆过滤器,我们可以这样做:
from bitarray import bitarray
# 3rd party
import mmh3
class BloomFilter(set):
def __init__(self, size, hash_count):
super(BloomFilter, self).__init__()
self.bit_array = bitarray(size)
self.bit_array.setall(0)
self.size = size
self.hash_count = hash_count
def __len__(self):
return self.size
def __iter__(self):
return iter(self.bit_array)
def add(self, item):
for ii in range(self.hash_count):
index = mmh3.hash(item, ii) % self.size
self.bit_array[index] = 1