BloomFilter(布隆过滤器)原理和python支持库

简介

  • 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. 只要有任何一位不是1,那说明这个字符串一定没被Bloom Filter记录过。
  2. 如果全部是1,这个字符串很可能被Bloom Filter记录过,(为什么不能100%肯定,你一定也想到了),这就是Bloom Filter错判的由来。
    Bloom Filter的原理就是这么简单,你可以自己完成编程一个BloomFilter。只是问题在于如何降低错判率

影响误判率因素

  • 只要降低Bloom Filter误判率,让它达到你可以接受的程度。BloomFilter当然就是你的利器了。影响它的因素有哪些呢?
  1. BitArray的位数M
  2. hash函数的数量K
  3. 每一个不同的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
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
布隆过滤器是一种非常高效的数据结构,用于判断某个元素是否存在于一个集合中。它的基本原理是使用多个哈希函数对元素进行哈希,然后将哈希结果映射到一个位数组中的若干个位置,将这些位置标记为1。当需要查询某个元素是否在集合中时,将该元素进行哈希,判断哈希结果映射到的位数组上的值是否都为1,如果都为1,则说明该元素可能存在于集合中,但如果有任何一个位置为0,则说明该元素一定不存在于集合中。 布隆过滤器的应用场景非常广泛,例如网络爬虫中的URL去重、拼写检查、垃圾邮件过滤等。它的主要优点是占用空间非常小,而且查询速度非常快。 下面是一个简单的布隆过滤器的实现示例: ```python import hashlib class BloomFilter: def __init__(self, m, k): self.m = m # 位数组的长度 self.k = k # 哈希函数的个数 self.bit_array = [0] * m # 初始化位数组 def add(self, key): for i in range(self.k): # 使用不同的哈希函数进行哈希 hash_val = int(hashlib.md5(str(key).encode('utf-8') + str(i).encode('utf-8')).hexdigest(), 16) # 将哈希结果映射到位数组上的若干个位置 pos = hash_val % self.m self.bit_array[pos] = 1 def contains(self, key): for i in range(self.k): hash_val = int(hashlib.md5(str(key).encode('utf-8') + str(i).encode('utf-8')).hexdigest(), 16) pos = hash_val % self.m if self.bit_array[pos] == 0: return False return True ``` 在上述代码中,我们使用了MD5哈希函数对字符串进行哈希,产生一个128位的哈希值,并将其转换为一个整数。然后,我们将这个整数对位数组的长度取模,得到一个在0到`m-1`之间的整数,将位数组上对应的位置标记为1。在查询元素是否存在于集合中时,我们同样对该元素进行k次哈希,并检查位数组上对应的位置是否都为1。如果有任何一个位置为0,则说明该元素一定不存在于集合中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值