BloomFilter 與 Cuckoo Filter


BloomFilter 與 CuckooFilter

 

Bloom Filter 原理

Bloom Filter是一種空間效率很高的隨機數據結構,它的原理是,當一個元素被加入集合時,通過K個相互獨立的Hash函數將這個元素映射成一個位陣列(Bit array)中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了;如果這些點有任何一個0,則被檢索元素一定不在;如果都是1,則被檢索元素很可能在。

Bloom Filter的這種高效是有一定代價的,在判斷一個元素是否屬於某個集合時,有可能會把不屬於這個集合的元素誤認為屬於這個集合(false positive)。因此,並不適合那些“零錯誤”的應用場合。而在能容忍低錯誤率的應用場合下,Bloom Filter通過極少的錯誤換取了存儲空間的極大節省。

 

假設要你寫一個網絡爬蟲程序(web crawler)。由於網絡間的鏈接錯綜復雜,爬蟲在網絡間爬行很可能會形成“環”。為了避免形成“環”,就需要知道爬蟲程序已經訪問過那些URL。給一個URL,怎樣知道爬蟲程序是否已經訪問過呢?稍微想想,就會有如下幾種方案:

  1. 將訪問過的URL保存到數據庫。
  2. 用HashSet將訪問過的URL保存起來。那只需接近O(1)的代價就可以查到一個URL是否被訪問過了。
  3. URL經過MD5或SHA-1等單向哈希后再保存到HashSet或數據庫。
  4. Bit-Map方法。建立一個BitSet,將每個URL經過一個哈希函數映射到某一位。

其中,方法1~3都是將訪問過的URL完整保存,方法4則只標記URL的一個映射位。以上方法在數據量較小的情況下都能完美解決問題,但是當數據量變得非常龐大時問題就來了:

方法1:數據量變得非常龐大后關系型數據庫查詢的效率會變得很低。而且每來一個URL就啟動一次數據庫查詢是不是太小題大做了?

方法2:太消耗內存。隨着URL的增多,占用的內存會越來越多。就算只有1億個URL,每個URL只算50個字符,就需要5GB內存。

方法3:由於字符串經過MD5處理后的信息摘要長度只有128Bit,SHA-1處理后也只有160Bit,因此方法3比方法2節省了好幾倍的內存。

方法4:消耗內存是相對較少的,但缺點是單一哈希函數發生沖突的概率太高。還記得數據結構課上學過的Hash表沖突的各種解決方法么?若要降低沖突發生的概率到1%,就要將BitSet的長度設置為URL個數的100倍。Bloom Filter 與單哈希函數Bit-Map不同之處在於:Bloom Filter使用了k個哈希函數,每個字符串跟k個bit對應。從而降低了沖突的概率。

 

創建一個m位BitSet,先將所有位初始化為0,然后選擇k個不同的哈希函數。第 i 個哈希函數對字符串str哈希的結果記為Hi(str),並且滿足:

0 <= Hi(str) < m     (1<=i<=k) 

(1) 將字符串 str 映射到BitSet中的過程:分別計算H1(str),H2(str),…,Hk(str),然后在BitSet中將對應的位置1。

(2) 檢查字符串str是否被BitSet記錄過的過程:分別計算H1(str),H2(str),…,Hk(str),然后在BitSet中對應的位檢查是否為1。若其中任何一位不為1則可以判定str一定沒有被記錄過。若全部位都是1,則認為字符串str存在。注意:這里也可能存在誤判,因為有可能該字符串的所有位都剛好是被其他字符串所對應,這種將該字符串划分錯的情況稱為false positive

 

(3) 刪除字符串過程,字符串加入了就被不能刪除了,因為刪除會影響到其他字符串。

實在需要刪除字符串的可以使用Counting Bloom Filter (CBF),這是一種基本Bloom Filter的變體,CBF將基本Bloom Filter每一個Bit改為一個計數器,這樣就可以實現刪除字符串的功能了。

 


Bloom Filter 參數選擇

 

問題:m(bit-map位數), n(待處理的字符串個數), k(哈希函數個數)值,我們該如何取值呢?

 

當hash函數個數 k = (ln2) * (m/n) 時錯誤率最小。

在錯誤率不大於e的情況下,則m >= n*log2(1/e)*log2e

這里直接給出了結論,如果對上述公式推導過程感興趣,可以參考這里

舉個例子我們假設錯誤率為0.001,則此時m應大概是n的14倍。這樣k大概是4個。 

 

 


 

Bloom Filter 應用

最后,總結下Bloom Filter 的優點:

  • 節約緩存空間(空值的映射),不再需要空值映射;
  • 減少數據庫或緩存的請求次數;
  • 提升業務的處理效率以及業務隔離性。

缺點:

  • 存在誤判的概率;
  • 傳統的Bloom Filter不能作刪除操作(可以使用CBF來支持刪除功能)。

 

Bloom Filter 可以用來實現數據字典,進行數據的判重,或者集合求交集 。

 

 


 

Cuckoo 布谷鳥哈希

前面提到,Bloom Filter 可能存在誤報,並且無法刪除元素,而Cuckoo哈希就是解決這兩個問題的。

Cuckoo的哈希函數是成對的(具體的實現可以根據需求設計),每一個元素都是兩個,分別映射到兩個位置,一個是記錄的位置,另一個是備用位置,這個備用位置是處理碰撞時用的。

如下圖,使用hashA 和hashB 計算對應key x的位置a和b :

  1. 當兩個哈希位置有一個為空時,則插入該空位置;
  2. 當兩個哈希位置均不為空時,隨機選擇兩者之一的位置上key y 踢出,並計算踢出的key y在另一個哈希值對應的位置,若為空直接插入,不為空踢出原元素插入,再對被踢出的元素重新計算,重復該過程,直到有空位置為止。

 

 

Cockoo hashing 有兩種變形:一種通過增加哈希函數進一步提高空間利用率;另一種是增加哈希表,每個哈希函數對應一個哈希表,每次選擇多個張表中空余位置進行放置,三個哈希表可以達到80% 的空間利用率。

Cockoo hashing 的過程可能因為反復踢出無限循環下去,這時候就需要進行一次循環踢出的限制,超過限制則認為需要添加新的哈希函數。

 

 

 

 

 

 

 

 

 

 

 

參考文檔:

http://blog.csdn.net/v_july_v/article/details/6685894/

http://blog.csdn.net/v_july_v/article/details/7382693

http://www.dbafree.net/?p=36

https://github.com/jaybaird/python-bloomfilter/blob/master/pybloom/pybloom.py

http://coolshell.cn/articles/17225.html

 


免責聲明!

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



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