什么是布隆過濾器
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 取模得到 h‘ihi‘,使向量 bitarraybitarray 的相應位置 h1‘,h2‘,……hk‘ 均置為 11。集合中其他 urlurl 也通過類似的操作,將向量 bitarraybitarray 的若干位置為 11。
檢查是否重復
- 首先將該元素經過上步中類似操作,獲得 kk 個隨機數 h1‘,h2‘,……hk‘ ,然后查看向量 bitarraybitarray 的相應位置上的值,若全為 11,則該元素已經在之前的集合中;若至少有一個 00 存在,表明,此元素不在之前的集合中,為新元素。
執行示意圖
算法特點
- 對於已經在集合中的元素,通過上述中的查找方法,一定可以判定該元素在集合中。
- 對於不在集合中的元素,可能會被誤判在集合中。
布隆過濾器的選擇與質量評估
確定布隆過濾器的長度 mm
設樣本個數為 nn,允許的錯誤率為 pp,則,
確定哈希函數的個數 kk
根據已求得的 mm,可得,
計算真實失誤率
根據向上取整的 m、n、km、n、k,可求得,
Python實現布隆過濾器
安裝PyBloom
Python中有多個實現 BloomFilter
的包詳情可以自己搜索Pypi,本文中主要介紹 PyBloom,可以通過 pip 進行安裝。
pip install pybloom
也可以直接去作者的github上下載源碼編譯安裝。
python setup.py install
PyBloom源碼解析
pybloom主要包括兩個類:BloomFilter
和ScalableBloomFilter
。
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