Python中的现代,高性能Bloom过滤器? [关闭]

问题描述 投票:50回答:6

我正在寻找Python中的生产质量Bloom过滤器实现,以处理相当多的项目(例如100M到1B的项目,其误报率为0.01%)。

Pybloom是一个选项,但是它似乎正在显示它的年龄,因为它会定期在Python 2.5上引发DeprecationWarning错误。乔·格雷戈里奥(Joe Gregorio)也有an implementation

要求是快速查找性能和稳定性。我也愿意为特别好的c / c ++实现创建Python接口,如果有很好的Java实现,甚至可以对Jython开放。

缺少这一点,关于可以处理约16E9位的位阵列/位向量表示形式的任何建议吗?

python jython bloom-filter
6个回答
28
投票

我最近也走这条路;虽然听起来我的应用程序略有不同。我对近似大量字符串的set操作很感兴趣。

您确实观察到需要fast位向量。根据您要在Bloom过滤器中放置的内容,您可能还需要考虑使用的哈希算法的速度。您可能会发现此library有用。您可能还想修改下面使用的随机数技术,该技术只会对密钥进行一次哈希处理。

就非Java位数组实现而言:

我使用BitVector构建了我的Bloom过滤器。我花了一些时间来分析和优化库,然后将补丁发布回Avi。转到该BitVector链接,然后向下滚动到v1.5中的确认以查看详细信息。最后,我意识到性能不是该项目的目标,因此决定不使用它。

这里有一些我所躺在的代码。我可能会把它放在python-bloom的Google代码上。欢迎提出建议。

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


#
# [email protected] / 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]

25
投票

对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(或任何加密哈希)。


10
投票

最终我找到了pybloomfiltermap。我没有用过,但是看起来很合适。


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代替。这[[may可能会导致速度稍有提高,但有可能会造成混淆。

此外,在大多数硬件上,将'B'8更改为'L'32应该更快。 [在某些硬件上,更改为'H'和16可能会更快,但这值得怀疑。]

2
投票
我在http://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/处放置了python Bloom过滤器实现

它在纯python中,具有良好的哈希函数,良好的自动化测试,可选的后端(磁盘,数组,mmap等),以及__init__方法的更直观的参数,因此您可以指定理想数量的元素并所需的最大错误率,而不是有些空洞的,特定于数据结构的可调参数。


0
投票
距此最新答案已近十年了。时间会改变。

看起来像2019年底最受欢迎的

maintained Bloom过滤器包,现在是这个:https://github.com/joseph-fox/python-bloomfilter,可以在PyPi上以pybloom_live的形式获得:https://pypi.org/project/pybloom_live/


-1
投票
我对Bloom过滤器变体,它们的性能以及对它们的用例很感兴趣。关于Bloom过滤器变体的研究工作被引用很多(包括在SIGCOMM,SIGMETRICS等顶级会议上发表的研究),但我认为主流语言库中它们的存在并不强。您为什么认为是这种情况?

尽管我的兴趣与语言无关,但我想分享我写的关于Bloom过滤器变体以及Bloom过滤器应用的文章。

http://appolo85.wordpress.com/2010/08/03/bloom-filter/

我很想了解更多有关Bloom过滤器变体的用例,其设计/实现以及其他语言的库的信息。

您是否认为大多数出版物以及Bloom过滤器变体上的(代码?)仅用于增加博士学位毕业生的已发表论文数量?还是大多数人不希望使用“可以正常工作”的可用于生产的标准布隆过滤器实现,:D

© www.soinside.com 2019 - 2024. All rights reserved.