简介
- Bloom Filter(布隆过滤器)是一种多哈希函数映射的快速查找算法。通常应用在需要快速判断一个元素是否属于集合,但是并不是严格要求100%正确的场合。
- 即Bloom Filter是会误判的,但是它只会把不存在于集合中的元素误判成存在于集合中,而不会把存在于集合中的元素误判成不存在集合中。
场景
- 我最初使用Bloom Filter的场景是爬虫的链接去重。如果我们采用最笨的方法,保存所有抓取过的url,那么当数据越来越大,去重判断的速度当然会降低,内存消耗也会越来越大,即使加入摘要算法、采用hash存储,也仅仅是减缓这个趋势而已。
- 我需要寻找一种,即使在url很多的时候,依然速度快,内存消耗小的方法。由此采用Bloom Filter,并且Bloom Filter的错判的代价,对我这个应用场景而言,仅仅是少抓取几个页面而已,完全可以接受。
原理
- Bloom Filter仅仅维护一个m位的BitArray(位数组),最开始m位全部为零。不断记录元素(如已经抓取的url),也仅仅是m位的BitSet中有些位置由0置成1的过程。
- 此外,Bloom Filter需要K个不同的hash函数,并且每个hash函数的结果要是在0~m-1范围的,因为我们要把每一个hash函数的结果i映射到位数租的第i位上去。
记录元素
- 下面我们看一下向Bloom Filter插入字符串的具体过,就是把这个字符串str经过K个不同的hash函数计算得到的结果h1、h2、、、hK。然后在BitArrray的第h1、h2、、、hK的位置上置1。
- 如图所示
判断元素
- 那么如何判断一个字符串str是存在呢,这个过程你应该是可以自己想到的。
- 把这个字符串经过K个hash函数计算得到h1、h2、、、hK,然后逐个判断BitArray的第h1、h2、、、hK个位置是否是1:
- 只要有任何一位不是1,那说明这个字符串一定没被Bloom Filter记录过。
- 如果全部是1,这个字符串很可能被Bloom Filter记录过,(为什么不能100%肯定,你一定也想到了),这就是Bloom Filter错判的由来。
Bloom Filter的原理就是这么简单,你可以自己完成编程一个BloomFilter。只是问题在于如何降低错判率
影响误判率因素
- 只要降低Bloom Filter误判率,让它达到你可以接受的程度。BloomFilter当然就是你的利器了。影响它的因素有哪些呢?
- BitArray的位数M
- hash函数的数量K
- 每一个不同的hash函数的质量
-
至于M、K、已经将要记录的元素的个数N之间的关系如何才能使得误判率最小,这里暂时不说了。
-
利用上面所说的,我们已经可以实现自己的BloomFilter了。
-
python的BloomFilter库
当然万能的Python 已经有了Bloom Filter的库,pip安装即可。
from pybloom import BloomFilter
dir(BloomFilter)
['FILE_FMT', '__and__', '__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getstate__', '__hash__', '__init__', '__len__', '__module__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_setup', 'add', 'copy', 'fromfile', 'intersection', 'tofile', 'union']
- 我们看看 __init__的用法
print (BloomFilter.__init__.__doc__)
Implements a space-efficient probabilistic data structure
capacity:
this BloomFilter must be able to store at least *capacity* elements
while maintaining no more than *error_rate* chance of false positives
error_rate:
the error_rate of the filter returning false positives. This
determines the filters capacity. Inserting more than capacity
elements greatly increases the chance of false positives.
b = BloomFilter(capacity=100000, error_rate=0.001)
print(b.add("test")) # False
print("test" in b) # True
- 两个参数:capacity、error_rate
- capacity是布隆过滤器的容积,最多可以记录多少元素
- error_rate是错判率
- 给定了这两个参数可以初始化过滤器。同时,他还给了一个实例。
- 简单的使用demo,为了方便观察
b = BloomFilter(capacity=10, error_rate=0.1)
print(b.bitarray)
# 结果:
# bitarray('000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
print(b.num_bits)
# 结果:
# 96
s = "http://blog.csdn.net/TENLIU2099/article/details/78288912"
b.add(s)
print(b.bitarray)
结果:
# bitarray('010000000000000000000000000100000000000000000000000010000000000000000000000010000000000000000000')
print(s in b) # True