布隆過濾器原理及使用


 什么是布隆過濾器

1970年,由布隆提出來的一個用於判斷元素是否在集合中的高效的算法,集合中的元素可以增加,但是要刪除一個元素比較困難,同時還有少量的誤報率。

在數據量比較小的時候,我們可以使用 Hash 來判斷元素是否命中,但是當元素增加起來后,Hash 算法需要的空間就會急速增長,查找時間也會增加。布隆過濾器主要用在樣本集合量大但是很少有刪除元素,不要求 100%100% 正確率的場景下。例如:網頁黑名單垃圾郵件過濾爬蟲URL去重 等。

 

布隆過濾器原理

爬蟲URL去重

初始條件

  • 設數據集合 A=a1,a2,.,anA=a1,a2,….,an,含 nn 個 urlurl 記為 ai(i[1,n])ai(i∈[1,n]),作為待操作的集合。

  • Bloom Filter 用一個長度為 mm 的位向量 bitarraybitarray 表示的集合中的元素,位向量初始值全為 00。

  • kk 個優秀且各自獨立的哈希函數 H1,H2,.,HkH1,H2,….,Hk,且輸出域應 m≥m。

加入url的處理

  • 首先經過 kk 個散列函數產生 kk 個隨機數 h1,h2,hk,接着對 mm 取模得到 hihi‘,使向量 bitarraybitarray 的相應位置 h1‘,h2‘,……hk‘ 均置為 11。集合中其他 urlurl 也通過類似的操作,將向量 bitarraybitarray 的若干位置為 11。

檢查是否重復

  • 首先將該元素經過上步中類似操作,獲得 kk 個隨機數 h1‘,h2‘,……hk‘ ,然后查看向量 bitarraybitarray 的相應位置上的值,若全為 11,則該元素已經在之前的集合中;若至少有一個 00 存在,表明,此元素不在之前的集合中,為新元素。

執行示意圖

                                                                                  

 

算法特點

  • 對於已經在集合中的元素,通過上述中的查找方法,一定可以判定該元素在集合中。
  • 對於不在集合中的元素,可能會被誤判在集合中。

布隆過濾器的選擇與質量評估

確定布隆過濾器的長度 mm

設樣本個數為 nn,允許的錯誤率為 pp,則,

 

 

確定哈希函數的個數 kk

根據已求得的 mm,可得,

 

 

計算真實失誤率

根據向上取整的 mnkm、n、k,可求得,

 

 

 

Python實現布隆過濾器

安裝PyBloom

Python中有多個實現 BloomFilter 的包詳情可以自己搜索Pypi,本文中主要介紹 PyBloom,可以通過 pip 進行安裝。

pip install pybloom

 

也可以直接去作者的github上下載源碼編譯安裝。

python setup.py install

 

PyBloom源碼解析

pybloom主要包括兩個類:BloomFilterScalableBloomFilter

BloomFilter 是一個定容的過濾器,errorrateerrorrate 是指最大的誤報率是 0.1%,而 ScalableBloomFilter是一個不定容量的布隆過濾器,它可以不斷添加元素。add 方法是添加元素,如果元素已經在布隆過濾器中,就返回 True,如果不在返回 Fasle 並將該元素添加到過濾器中。判斷一個元素是否在過濾器中,只需要使用 in運算符即可。

ScalableBloomFilter類

ScalableBloomFilter的 add 方法中可以看到:

其本質依舊是創建了一個BloomFilter類。

BloomFilter類

BloomFilter的 __init__ 函數中:

可以看到它引用了Python的bitarray庫來實現布隆過濾器。

BloomFilter的 add 方法中:

可以看到,我們可以通過設置 skipcheckskipcheck 的值來手動選擇是否過濾當前元素,否則就根據算出的 kk 個 Hash 函數的值所對應的位是否都為 11 來確定元素是否存在,存在則返回 True,否則返回 False

PyBloom的使用

使用BloomFilter

from pybloom import BloomFilter
bf = BloomFilter(capacity=10000, error_rate=0.001)
bf.add('test-bf')
print 'test-bf' in bf

True

 

使用ScalableBloomFilter

from pybloom import ScalableBloomFilter
sbf = ScalableBloomFilter(mode=ScalableBloomFilter.SMALL_SET_GROWTH)
sbf.add('test-sbf')
print 'sbf' in sbf

False

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM