2008-11-22 34 views
43

Tôi đang tìm một bộ lọc sản xuất bộ lọc hoa chất lượng cao trong Python để xử lý số lượng khá lớn các mục (nói 100M đến 1B mục có tỷ lệ 0,01% dương tính giả).Bộ lọc nở hiện đại, hiệu năng cao trong Python?

Pybloom là một tùy chọn nhưng có vẻ như đang hiển thị tuổi của nó khi nó ném Khử haoWarning lỗi trên Python 2.5 một cách thường xuyên. Joe Gregorio cũng có an implementation.

Yêu cầu là hiệu suất tra cứu nhanh và ổn định. Tôi cũng mở để tạo ra các giao diện Python để triển khai c/C++ đặc biệt tốt, hoặc thậm chí đến Jython nếu có một thực thi Java tốt.

Thiếu điều đó, bất kỳ đề xuất nào về biểu diễn bit bit/bit có thể xử lý ~ 16E9 bit?

+0

Không quan tâm, bạn có thể giải thích điều gì sai với các triển khai hiện có (đặc biệt là PyBloom) không? Nó có thể là "dài trong răng", nhưng nếu nó hoạt động và không cần sửa chữa, mà âm thanh như một cộng. – Oddthinking

+0

Oddthinking, cập nhật với một số lời giải thích. – Parand

Trả lời

8

Cuối cùng tôi tìm thấy pybloomfiltermap. Tôi đã không sử dụng nó, nhưng có vẻ như nó sẽ phù hợp với dự luật.

+0

cho tôi biết nếu thư viện có ích cho bạn! –

6

Nhìn vào mô-đun 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, tất cả các hoạt động //8% 8 có thể được thay thế bằng >>3&0x07. Điều này có thể dẫn đến tốc độ hơi tốt hơn ở nguy cơ một số tối tăm.

Ngoài ra, thay đổi 'B'8 thành 'L'32 sẽ nhanh hơn trên hầu hết phần cứng. [Thay đổi thành 'H' và 16 có thể nhanh hơn trên một số phần cứng, nhưng nó đáng ngờ.]

+0

Thật đáng yêu! +1 –

26

Gần đây tôi cũng đã đi xuống con đường này; mặc dù có vẻ như ứng dụng của tôi hơi khác một chút. Tôi đã quan tâm đến việc xấp xỉ các hoạt động thiết lập trên một số lượng lớn các chuỗi.

Bạn thực hiện quan sát chính rằng cần có tốc độ bit nhanh bit. Tùy thuộc vào những gì bạn muốn đưa vào bộ lọc nở của bạn, bạn cũng có thể cần phải suy nghĩ về tốc độ của thuật toán băm được sử dụng. Bạn có thể tìm thấy điều này library hữu ích. Bạn cũng có thể muốn tinker với kỹ thuật số ngẫu nhiên được sử dụng dưới đây mà chỉ băm khóa của bạn một lần duy nhất.

Về-Java không triển khai mảng bit:

tôi đã xây dựng bộ lọc nở của tôi sử dụng BitVector. Tôi đã dành một chút thời gian để lập hồ sơ và tối ưu hóa thư viện và đóng góp các bản vá của mình cho Avi. Đi đến liên kết BitVector đó và cuộn xuống để xác nhận trong v1.5 để xem chi tiết. Cuối cùng, tôi nhận ra rằng hiệu suất không phải là mục tiêu của dự án này và quyết định không sử dụng nó.

Đây là một số mã tôi đã nói dối. Tôi có thể đặt điều này lên trên mã google tại python nở. Đề nghị chào đón.

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 

Ngoài ra, trong trường hợp của tôi, tôi thấy hữu ích khi có hàm count_bits nhanh hơn cho BitVector. Thả mã này vào BitVector 1.5 và nó sẽ cung cấp cho bạn phương pháp đếm bit hiệu quả hơn:

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] 
+0

Cảm ơn Ryan, rất thông tin. Về hiệu suất của BitVector, bạn có tìm được giải pháp thay thế nhanh hơn không? Ngoài ra, tôi nhận thấy bạn chỉ sử dụng 4 băm, có vẻ hơi thấp. Bất kỳ suy nghĩ về điều đó? Một thực tế phổ biến có vẻ là sử dụng một cái gì đó như SHA1 và chia nhỏ các bit để tạo thành nhiều băm. – Parand

+2

Hashcount tùy thuộc vào: # yếu tố và tỷ lệ dương tính giả chấp nhận được. Tôi có một phiên bản cải tiến ở trên mà tôi sẽ kiểm tra. Đã không tìm thấy bất cứ điều gì nhanh hơn (mặc dù tôi tưởng tượng rằng nó sẽ là một thực hiện bản địa). –

0

Tôi rất quan tâm đến các biến thể của bộ lọc Bloom, hiệu suất của chúng và hiểu các trường hợp sử dụng của chúng. Có rất nhiều công trình nghiên cứu được trích dẫn trên các biến thể của bộ lọc Bloom (bao gồm cả các phiên bản được xuất bản trong các hội nghị hàng đầu như SIGCOMM, SIGMETRICS) nhưng tôi không nghĩ sự hiện diện của chúng là mạnh mẽ trong các thư viện ngôn ngữ chính thống. Tại sao bạn nghĩ rằng đó là trường hợp?

Mặc dù sở thích của tôi là không thuyết phục về ngôn ngữ, tôi muốn chia sẻ một bài viết tôi đã viết trên các biến thể của bộ lọc Bloom và các ứng dụng của bộ lọc Bloom.

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

tôi rất thích tìm hiểu thêm về trường hợp sử dụng của họ về các biến thể lọc Bloom, và thiết kế của họ/thực hiện, và các thư viện bằng ngôn ngữ khác.

Bạn có nghĩ rằng hầu hết các ấn phẩm và (mã?) Trên các biến thể bộ lọc Bloom, chỉ phục vụ để tăng số lượng giấy đã xuất bản của một nghiên cứu sinh tiến sĩ? Hoặc là hầu hết mọi người không muốn gây rối với việc triển khai bộ lọc hoa tiêu chuẩn sẵn sàng sản xuất "hoạt động tốt": D

22

Phản ứng với Parand, nói "thực tế phổ biến dường như đang sử dụng một cái gì đó như SHA1 và chia nhỏ các bit để tạo thành nhiều băm ", trong khi điều đó có thể đúng theo nghĩa rằng nó là thực tế phổ biến (PyBloom cũng sử dụng nó), nó vẫn không có nghĩa là nó là điều đúng để làm ;-)

Cho một bộ lọc Bloom, yêu cầu duy nhất một hàm băm có là không gian đầu ra của nó phải được phân phối thống nhất cho đầu vào mong đợi. Trong khi một băm mật mã chắc chắn đáp ứng được yêu cầu này, nó cũng hơi giống như chụp một con ruồi với bazooka.

Thay vì thử FNV Hash trong đó sử dụng chỉ là một XOR và một nhân mỗi byte đầu vào, mà tôi ước tính là nhanh hơn so với SHA1 :)

Các FNV băm là không mã hóa an toàn một vài trăm lần, nhưng bạn không cần nó. Nó có một chút imperfect avalanche behaviour, nhưng bạn không sử dụng nó để kiểm tra tính toàn vẹn.

Giới thiệu về tính đồng nhất, lưu ý rằng liên kết thứ hai chỉ thực hiện kiểm tra Chi square cho băm FNV 32 bit. Tốt hơn là sử dụng nhiều bit hơn và biến thể FNV-1, thay đổi các bước XOR và MUL để phân tán bit tốt hơn. Đối với một bộ lọc Bloom, có một vài bắt hơn, chẳng hạn như ánh xạ đầu ra thống nhất đến phạm vi chỉ mục của mảng bit. Nếu có thể, tôi muốn nói lên kích thước của mảng bit với công suất gần nhất là 2 và điều chỉnh k tương ứng. Bằng cách đó bạn có được độ chính xác cao hơn và bạn có thể sử dụng XOR-fold đơn giản để lập bản đồ phạm vi.

Ngoài ra, đây là tài liệu tham khảo giải thích lý do bạn không muốn SHA1 (hoặc bất kỳ mã băm mật mã nào) khi bạn cần a general purpose hash.

+0

+1, câu trả lời hay. Và vâng, giới hạn về người dùng mới đăng liên kết là khá ngớ ngẩn. –

+0

Cảm ơn người đàn ông, tôi biết rằng việc giữ câu hỏi cũ hai năm này được yêu thích sẽ trả hết một số ngày! – drxzcl

+0

Cảm ơn câu trả lời hay. Tôi không sử dụng các bộ lọc nở hoa vào lúc này, nhưng nếu tôi đi xung quanh, tôi sẽ xem liệu tôi có thể trang bị thêm FNV thay vì SHA1 không. – Parand

2

Tôi đã đưa ra một thực hiện bộ lọc python nở tại http://stromberg.dnsalias.org/~strombrg/drs-bloom-filter/

Đó là trong python tinh khiết, có chức năng tốt băm, kiểm tra tự động tốt, sự lựa chọn của backends (đĩa, mảng, mmap, nhiều hơn nữa) và trực quan hơn đối số với phương thức __init__, vì vậy bạn có thể chỉ định số nguyên tố lý tưởng và tỷ lệ lỗi tối đa mong muốn, thay vì phần nào có thể điều chỉnh được, cụ thể về cấu trúc cơ sở dữ liệu.

Các vấn đề liên quan