我正在寻找Python中的生产质量bloom过滤器实现来处理相当多的项目(例如100M到1B项目,误报率为0.01%)。
Pybloom是一个选项,但它似乎显示了它的年龄,因为它会定期抛出Python 2.5上的DeprecationWarning错误。乔格雷戈里奥也有an implementation。
要求是快速查找性能和稳定性。我也愿意为特别好的c / c ++实现创建Python接口,如果有一个很好的Java实现,甚至可以创建Jython。
缺乏对位数组/位向量表示可以处理~16E9位的任何建议吗?
答案 0 :(得分:28)
我最近也走了这条路;虽然听起来我的应用程序略有不同。我对在大量字符串上逼近集合操作感兴趣。
您确实需要进行关键观察,即需要快速位向量。根据您要在布隆过滤器中放置的内容,您可能还需要考虑所使用的散列算法的速度。您可能会发现此library有用。您可能还想修改下面使用的随机数技术,它只会一次哈希您的密钥。
就非Java位阵列实现而言:
我使用BitVector制作了布隆过滤器。我花了一些时间来分析和优化库并将我的补丁贡献给Avi。转到该BitVector链接并向下滚动到v1.5中的确认以查看详细信息。最后,我意识到性能不是这个项目的目标,并决定不使用它。
这是我躺在身边的一些代码。我可以把它放在python-bloom的谷歌代码上。建议欢迎。
from BitVector import BitVector
from random import Random
# get hashes from http://www.partow.net/programming/hashfunctions/index.html
from hashes import RSHash, JSHash, PJWHash, ELFHash, DJBHash
#
# ryan.a.cox@gmail.com / www.asciiarmor.com
#
# copyright (c) 2008, ryan cox
# all rights reserved
# BSD license: http://www.opensource.org/licenses/bsd-license.php
#
class BloomFilter(object):
def __init__(self, n=None, m=None, k=None, p=None, bits=None ):
self.m = m
if k > 4 or k < 1:
raise Exception('Must specify value of k between 1 and 4')
self.k = k
if bits:
self.bits = bits
else:
self.bits = BitVector( size=m )
self.rand = Random()
self.hashes = []
self.hashes.append(RSHash)
self.hashes.append(JSHash)
self.hashes.append(PJWHash)
self.hashes.append(DJBHash)
# switch between hashing techniques
self._indexes = self._rand_indexes
#self._indexes = self._hash_indexes
def __contains__(self, key):
for i in self._indexes(key):
if not self.bits[i]:
return False
return True
def add(self, key):
dupe = True
bits = []
for i in self._indexes(key):
if dupe and not self.bits[i]:
dupe = False
self.bits[i] = 1
bits.append(i)
return dupe
def __and__(self, filter):
if (self.k != filter.k) or (self.m != filter.m):
raise Exception('Must use bloom filters created with equal k / m paramters for bitwise AND')
return BloomFilter(m=self.m,k=self.k,bits=(self.bits & filter.bits))
def __or__(self, filter):
if (self.k != filter.k) or (self.m != filter.m):
raise Exception('Must use bloom filters created with equal k / m paramters for bitwise OR')
return BloomFilter(m=self.m,k=self.k,bits=(self.bits | filter.bits))
def _hash_indexes(self,key):
ret = []
for i in range(self.k):
ret.append(self.hashes[i](key) % self.m)
return ret
def _rand_indexes(self,key):
self.rand.seed(hash(key))
ret = []
for i in range(self.k):
ret.append(self.rand.randint(0,self.m-1))
return ret
if __name__ == '__main__':
e = BloomFilter(m=100, k=4)
e.add('one')
e.add('two')
e.add('three')
e.add('four')
e.add('five')
f = BloomFilter(m=100, k=4)
f.add('three')
f.add('four')
f.add('five')
f.add('six')
f.add('seven')
f.add('eight')
f.add('nine')
f.add("ten")
# test check for dupe on add
assert not f.add('eleven')
assert f.add('eleven')
# test membership operations
assert 'ten' in f
assert 'one' in e
assert 'ten' not in e
assert 'one' not in f
# test set based operations
union = f | e
intersection = f & e
assert 'ten' in union
assert 'one' in union
assert 'three' in intersection
assert 'ten' not in intersection
assert 'one' not in intersection
另外,在我的情况下,我发现为BitVector提供更快的count_bits函数很有用。将此代码放入BitVector 1.5中,它应该为您提供更高性能的计数方法:
def fast_count_bits( self, v ):
bits = (
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 )
return bits[v & 0xff] + bits[(v >> 8) & 0xff] + bits[(v >> 16) & 0xff] + bits[v >> 24]
答案 1 :(得分:24)
对Parand的反应,说“普通的做法似乎是使用类似SHA1的东西并将这些位分开形成多个哈希”,而这可能是正确的,因为它是常见的做法(PyBloom也使用它),它仍然不是说这是正确的事情; - )
对于Bloom过滤器,散列函数的唯一要求是,在给定预期输入的情况下,其输出空间必须均匀分布。虽然加密哈希确实满足了这个要求,但它也有点像用火箭筒拍摄苍蝇。
而是尝试FNV Hash每个输入字节仅使用一个XOR和一个乘法,我估计它比SHA1快几百倍:)
FNV哈希在加密方面不安全,但您不需要它。它略微imperfect avalanche behaviour,但您也没有使用它进行完整性检查。
关于一致性,请注意第二个链接仅对32位FNV哈希进行了卡方检验。最好使用更多的比特和FNV-1变体,它可以交换XOR和MUL步骤,以实现更好的比特色散。对于布隆过滤器,还有一些捕获,例如将输出均匀映射到位阵列的索引范围。如果可能的话,我会说将位阵列的大小向上舍入到最接近的2的幂并相应地调整 k 。这样你就可以获得更好的精确度,并且可以使用简单的XOR折叠来绘制范围。
此外,这里有一个参考,解释了当您需要a general purpose hash时不需要SHA1(或任何加密哈希)的原因。
答案 2 :(得分:10)
最终我找到了pybloomfiltermap。我没有使用它,但看起来它符合要求。
答案 3 :(得分:8)
查看array模块。
class Bit( object ):
def __init__( self, size ):
self.bits= array.array('B',[0 for i in range((size+7)//8)] )
def set( self, bit ):
b= self.bits[bit//8]
self.bits[bit//8] = b | 1 << (bit % 8)
def get( self, bit ):
b= self.bits[bit//8]
return (b >> (bit % 8)) & 1
FWIW,所有//8
和% 8
操作都可以替换为>>3
和&0x07
。这个可能导致速度略微提高,但存在一些模糊的风险。
此外,在大多数硬件上将'B'
和8
更改为'L'
和32
应该更快。 [在某些硬件上更改为'H'
和16可能会更快,但这是值得怀疑的。]
答案 4 :(得分:2)
我在http://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/
处设置了一个python bloom过滤器实现它是纯Python,具有良好的哈希函数,良好的自动化测试,后端(磁盘,数组,mmap等)的选择以及__init__
方法的更直观的参数,因此您可以指定理想的数字元素和期望的最大错误率,而不是一些空灵的数据结构特定的可调参数。
答案 5 :(得分:0)
我对Bloom过滤器变体,它们的性能和理解它们的用例非常感兴趣。 关于Bloom过滤器变体(包括在SIGCOMM,SIGMETRICS等顶级会议上发布的那些)有很多引用很多的研究工作,但我不认为它们在主流语言库中的存在性很强。为什么你认为是这种情况?
虽然我的兴趣与语言无关,但我想分享一篇我在Bloom过滤器变体上写的文章,以及Bloom过滤器的应用程序。
http://appolo85.wordpress.com/2010/08/03/bloom-filter/
我希望了解更多关于Bloom过滤器变体的使用案例,以及它们的设计/实现以及其他语言的库。
您是否认为Bloom过滤器变体的大多数出版物和(代码?)仅用于增加博士研究生的已发表论文数量? 或者是大多数人不想搞砸生产就绪的标准布隆过滤器实现“工作得很好”:D
答案 6 :(得分:0)
距此最新答案已近十年了。时间会改变。
看起来像2019年末最受欢迎的维护布卢姆过滤器软件包现在是这个:https://github.com/joseph-fox/python-bloomfilter,可以在pyPi上以pybloom_live的形式使用:https://pypi.org/project/pybloom_live/