python实现布隆过滤器

布隆过滤器Bloom Filter

布隆过滤器于1970年由布隆提出,它是一个空间效率高的概率型数据结构,可以用来告诉你:一个元素一定不存在或者可能存在。
优点:空间效率和查询时间都远远超过一般的算法(使用哈希表将占用大量的内存空间)。
缺点:有一定的误判率、删除困难。
它实质上是一个很长的二进制向量和一系列随机映射函数(Hash函数)组成,常用于网页黑名单系统、垃圾邮件过滤系统、爬虫的网址判重系统、解决缓存穿透问题。

原理

布隆过滤器中,二进制数组的长度和哈希函数的个数由问题的数量规模、要求的错误率决定。假设图示中大小为20的二进制数组与3个哈希函数满足了问题需求,那么向布隆过滤器添加元素时,将每一个哈希函数生成的索引位置都设为 1。查询元素是否存在时,如果有一个哈希函数生成的索引位置不为 1,就代表不存在(100%准确);如果每一个哈希函数生成的索引位置都为 1,就代表存在(存在一定的误判率)。
在这里插入图片描述
布隆过滤器添加、查询的时间复杂度都是:O(k) ,k 是哈希函数的个数。空间复杂度是:O(m) ,m 是二进制位的个数。

数值计算

已知误判率 p、数据规模 n,求二进制位的个数 m、哈希函数的个数 k,较为合理的计算公式如下,公式由科学家给出。
在这里插入图片描述

代码实现

'''
布隆过滤器,在大量的数据中,判断某个数据是否存在时经常使用,有非常高效的空间效率与查询效率
缺点:存在一定的误判率
n:数据规模 p:要求的误判率
二进制数据位数 m=-n*lnp/(ln2)^2
哈希函数个数 k=m/n*ln2
'''
import ctypes
import math

class BloomFilter():
    def __init__(self,n:int,p:float):
        '''
        :param n:数据规模
        :param p:误判率
        '''
        #计算二进制数组规模与hash函数数量
        self.bitSize=int(-n*math.log(p)/math.pow(math.log(2),2))
        self.hashFuncSize=int(self.bitSize*math.log(2)/n)
        self.bitArray=[0]*(int((self.bitSize+32-1)/32))

    def put(self,value):
        '''
        :param value:存入的数据
        '''
        self.valueCheck(value)
        #哈希值的设置参考google布隆过滤器源码
        hash1=value.__hash__()
        hash2=self.unsigned_right_shitf(hash1,16)
        for i in range(self.hashFuncSize):
            combinedHash=hash1+i*hash2
            if combinedHash<0:
                combinedHash=~combinedHash
            combinedHash=combinedHash%self.bitSize
            index=int(combinedHash/32)#位于第index个int元素
            position=combinedHash-index*32#在int中的位置
            self.bitArray[index]=self.bitArray[index]|(1<<position)

    def contains(self,value):
        '''
        :param value:判断是否存在的数据
        :return:True or False
        '''
        self.valueCheck(value)
        hash1 = value.__hash__()
        hash2 = self.unsigned_right_shitf(hash1,16)
        for i in range(self.hashFuncSize):
            combinedHash = hash1 + i * hash2
            if combinedHash < 0:
                combinedHash = ~combinedHash
            combinedHash = combinedHash % self.bitSize
            index = int(combinedHash / 32)  # 位于第index个int元素
            position = combinedHash - index * 32  # 在int中的位置
            result= self.bitArray[index] & (1 << position)
            if result==0:
                return False
        return True

    def valueCheck(self, value):
        if value != 0 and not value:
            print('value can\'t be None')

    def int_overflow(self,val):
        maxint = 2147483647
        if not -maxint - 1 <= val <= maxint:
            val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1
        return val

    #无符号右移
    def unsigned_right_shitf(self,n, i):
        # 数字小于0,则转为32位无符号uint
        if n < 0:
            n = ctypes.c_uint32(n).value
        # 正常位移位数是为正数,但是为了兼容js之类的,负数就右移变成左移好了
        if i < 0:
            return -self.int_overflow(n << abs(i))
        # print(n)
        return self.int_overflow(n >> i)


if __name__=='__main__':
    n=100000000
    p=0.01
    bf=BloomFilter(n,p)
    total_size=100000
    error_count=0
    for i in range(total_size):
        bf.put(i)
    for i in range(total_size):
        if not bf.contains(i):
            error_count+=1
    print('error rate :',float(error_count/total_size) if error_count>0 else 0)
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,以下是一个简单的Python实现布隆过滤器的例子: ```python import mmh3 from bitarray import bitarray class BloomFilter: def __init__(self, size, hash_count): self.size = size self.hash_count = hash_count self.bit_array = bitarray(size) self.bit_array.setall(0) def add(self, string): for seed in range(self.hash_count): result = mmh3.hash(string, seed) % self.size self.bit_array[result] = 1 def lookup(self, string): for seed in range(self.hash_count): result = mmh3.hash(string, seed) % self.size if self.bit_array[result] == 0: return "Nope" return "Probably" ``` 上面的代码中,我们用到了 `mmh3` 和 `bitarray` 两个包。 `mmh3` 包用来生成hash值, `bitarray` 包用来创建位数组。在 `__init__` 方法中,我们传入两个参数 `size` 和 `hash_count`,分别代表位数组大小和hash函数个数。在 `add` 方法中,我们为每个字符串生成 `hash_count` 个hash值,并将对应的位数组位置设为1。在 `lookup` 方法中,我们同样为字符串生成 `hash_count` 个hash值,并检查对应的位数组位置是否都为1,如果有任何一个位置为0,就说明该字符串不在集合中。 下面是一个例子,演示如何使用布隆过滤器: ```python bf = BloomFilter(500000, 7) words = ['hello', 'world', 'foo', 'bar', 'baz'] for word in words: bf.add(word) print(bf.lookup('hello')) # Probably print(bf.lookup('foobar')) # Nope ``` 在上面的例子中,我们创建了一个布隆过滤器,设置位数组大小为500000,hash函数个数为7。然后,我们将一些单词添加到集合中,并使用 `lookup` 方法检查某些单词是否在集合中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值