Python+Redis实现布隆过滤器
布隆过滤器是什么
布隆过滤器(BloomFilter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。
布隆过滤器的基本思想
通过一种叫作散列表(又叫哈希表,Hashtable)的数据结构。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bitarray)中的一个点。这样一来,我们只要看看这个点是不是1就可以知道集合中有没有它了
布隆过滤器的优缺点
优点:
1.布隆过滤器的存储空间和插入/查询时间都是常数
2.Hash函数相互之间没有关系,方便由硬件并行实现
3.布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势
4.布隆过滤器可以表示全集,其它任何数据结构都不能
缺点:
1.存在一定的误算率,随着存入的元素数量增加,误算率随之增加
(常见的补救办法是建立一个小的白名单,存储那些可能被误判的元素。但是如果元素数量太少,则使用散列表足矣)
2.一般情况下不能从布隆过滤器中删除元素
首先我们必须保证删除的元素的确在布隆过滤器里面.这一点单凭这个过滤器是无法保证的。另外计数器回绕也会造成问题。这就导致删除元素需要很高的成本。
正文
简单的python实现
pipinstallmmh3
对于安装报错,c++编译错误问题:可以安装 MicrosoftVisualC++BuildTools()
例子转载(https://www.nhooo.com/article/175929.htm)
frombitarrayimportbitarray #3rdparty importmmh3 classBloomFilter(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): returnself.size def__iter__(self): returniter(self.bit_array) defadd(self,item): foriiinrange(self.hash_count): index=mmh3.hash(item,ii)%self.size self.bit_array[index]=1 returnself def__contains__(self,item): out=True foriiinrange(self.hash_count): index=mmh3.hash(item,ii)%self.size ifself.bit_array[index]==0: out=False returnout defmain(): bloom=BloomFilter(10000,10) animals=['dog','cat','giraffe','fly','mosquito','horse','eagle', 'bird','bison','boar','butterfly','ant','anaconda','bear', 'chicken','dolphin','donkey','crow','crocodile'] #Firstinsertionofanimalsintothebloomfilter foranimalinanimals: bloom.add(animal) #Membershipexistenceforalreadyinsertedanimals #Thereshouldnotbeanyfalsenegatives foranimalinanimals: ifanimalinbloom: print('{}isinbloomfilterasexpected'.format(animal)) else: print('Somethingisterriblywentwrongfor{}'.format(animal)) print('FALSENEGATIVE!') #Membershipexistencefornotinsertedanimals #Therecouldbefalsepositives other_animals=['badger','cow','pig','sheep','bee','wolf','fox', 'whale','shark','fish','turkey','duck','dove', 'deer','elephant','frog','falcon','goat','gorilla', 'hawk'] forother_animalinother_animals: ifother_animalinbloom: print('{}isnotinthebloom,butafalsepositive'.format(other_animal)) else: print('{}isnotinthebloomfilterasexpected'.format(other_animal)) if__name__=='__main__': main()
运行结果
dogisinbloomfilterasexpected
catisinbloomfilterasexpected
giraffeisinbloomfilterasexpected
flyisinbloomfilterasexpected
mosquitoisinbloomfilterasexpected
horseisinbloomfilterasexpected
eagleisinbloomfilterasexpected
birdisinbloomfilterasexpected
bisonisinbloomfilterasexpected
boarisinbloomfilterasexpected
butterflyisinbloomfilterasexpected
antisinbloomfilterasexpected
anacondaisinbloomfilterasexpected
bearisinbloomfilterasexpected
chickenisinbloomfilterasexpected
dolphinisinbloomfilterasexpected
donkeyisinbloomfilterasexpected
crowisinbloomfilterasexpected
crocodileisinbloomfilterasexpected
badgerisnotinthebloomfilterasexpected
cowisnotinthebloomfilterasexpected
pigisnotinthebloomfilterasexpected
sheepisnotinthebloom,butafalsepositive
beeisnotinthebloomfilterasexpected
wolfisnotinthebloomfilterasexpected
foxisnotinthebloomfilterasexpected
whaleisnotinthebloomfilterasexpected
sharkisnotinthebloom,butafalsepositive
fishisnotinthebloom,butafalsepositive
turkeyisnotinthebloomfilterasexpected
duckisnotinthebloomfilterasexpected
doveisnotinthebloom误报filterasexpected
deerisnotinthebloomfilterasexpected
elephantisnotinthebloom,butafalsepositive
frogisnotinthebloomfilterasexpected
falconisnotinthebloomfilterasexpected
goatisnotinthebloomfilterasexpected
gorillaisnotinthebloomfilterasexpected
hawkisnotinthebloomfilterasexpected
从输出结果可以发现,存在不少误报样本,但是并不存在假阴性。
不同于这段布隆过滤器的实现代码,其它语言的多个实现版本并不提供哈希函数的参数。这是因为在实际应用中误报比例这个指标比哈希函数更重要,用户可以根据误报比例的需求来调整哈希函数的个数。通常来说,size和error_rate是布隆过滤器的真正误报比例。如果你在初始化阶段减小了error_rate,它们会调整哈希函数的数量。
误报
布隆过滤器能够拍着胸脯说某个元素“肯定不存在”,但是对于一些元素它们会说“可能存在”。针对不同的应用场景,这有可能会是一个巨大的缺陷,亦或是无关紧要的问题。如果在检索元素是否存在时不介意引入误报情况,那么你就应当考虑用布隆过滤器。
另外,如果随意地减小了误报比率,哈希函数的数量相应地就要增加,在插入和查询时的延时也会相应地增加。本节的另一个要点是,如果哈希函数是相互独立的,并且输入元素在空间中均匀的分布,那么理论上真实误报率就不会超过理论值。否则,由于哈希函数的相关性和更频繁的哈希冲突,布隆过滤器的真实误报比例会高于理论值。
在使用布隆过滤器时,需要考虑误报的潜在影响。
确定性
当你使用相同大小和数量的哈希函数时,某个元素通过布隆过滤器得到的是正反馈还是负反馈的结果是确定的。对于某个元素x,如果它现在可能存在,那五分钟之后、一小时之后、一天之后、甚至一周之后的状态都是可能存在。当我得知这一特性时有一点点惊讶。因为布隆过滤器是概率性的,那其结果显然应该存在某种随机因素,难道不是吗?确实不是。它的概率性体现在我们无法判断究竟哪些元素的状态是可能存在。
换句话说,过滤器一旦做出可能存在的结论后,结论不会发生变化。
python基于redis实现的bloomfilter(布隆过滤器),BloomFilter_imooc
BloomFilter_imooc下载
下载地址:https://github.com/liyaopinner/BloomFilter_imooc
py_bloomfilter.py(布隆过滤器)源码:
importmmh3 importredis importmath importtime classPyBloomFilter(): #内置100个随机种子 SEEDS=[543,460,171,876,796,607,650,81,837,545,591,946,846,521,913,636,878,735,414,372, 344,324,223,180,327,891,798,933,493,293,836,10,6,544,924,849,438,41,862,648,338, 465,562,693,979,52,763,103,387,374,349,94,384,680,574,480,307,580,71,535,300,53, 481,519,644,219,686,236,424,326,244,212,909,202,951,56,812,901,926,250,507,739,371, 63,584,154,7,284,617,332,472,140,605,262,355,526,647,923,199,518] #capacity是预先估计要去重的数量 #error_rate表示错误率 #conn表示redis的连接客户端 #key表示在redis中的键的名字前缀 def__init__(self,capacity=1000000000,error_rate=0.00000001,conn=None,key='BloomFilter'): self.m=math.ceil(capacity*math.log2(math.e)*math.log2(1/error_rate))#需要的总bit位数 self.k=math.ceil(math.log1p(2)*self.m/capacity)#需要最少的hash次数 self.mem=math.ceil(self.m/8/1024/1024)#需要的多少M内存 self.blocknum=math.ceil(self.mem/512)#需要多少个512M的内存块,value的第一个字符必须是ascii码,所有最多有256个内存块 self.seeds=self.SEEDS[0:self.k] self.key=key self.N=2**31-1 self.redis=conn #print(self.mem) #print(self.k) defadd(self,value): name=self.key+"_"+str(ord(value[0])%self.blocknum) hashs=self.get_hashs(value) forhashinhashs: self.redis.setbit(name,hash,1) defis_exist(self,value): name=self.key+"_"+str(ord(value[0])%self.blocknum) hashs=self.get_hashs(value) exist=True forhashinhashs: exist=exist&self.redis.getbit(name,hash) returnexist defget_hashs(self,value): hashs=list() forseedinself.seeds: hash=mmh3.hash(value,seed) ifhash>=0: hashs.append(hash) else: hashs.append(self.N-hash) returnhashs pool=redis.ConnectionPool(host='127.0.0.1',port=6379,db=0) conn=redis.StrictRedis(connection_pool=pool) #使用方法 #if__name__=="__main__": #bf=PyBloomFilter(conn=conn)#利用连接池连接Redis #bf.add('www.jobbole.com')#向Redis默认的通道添加一个域名 #bf.add('www.luyin.org')#向Redis默认的通道添加一个域名 #print(bf.is_exist('www.zhihu.com'))#打印此域名在通道里是否存在,存在返回1,不存在返回0 #print(bf.is_exist('www.luyin.org'))#打印此域名在通道里是否存在,存在返回1,不存在返回0
总结
以上所述是小编给大家介绍的Python+Redis实现布隆过滤器,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。