認識布隆過濾器(Bloom Filter)

摘錄自《程序員代碼面試指南》

如果遇到網頁黑名單系統、垃圾郵件過濾系統、爬蟲的網址判重等題目,又看到系統容忍一定程度的失誤率,但是對空間要求比較嚴格,那麼很有可能是需要關於布隆過濾器的知識。一個布隆過濾器精確地代表一個集合,並可以精確判斷一個元素是否在集合中。注意,只是精確代表和精確判斷,到底有多精確呢?則完全在於你具體的設計,但想做到完全正確是不可能的。布隆過濾器的優勢就在於使用很少的空間就可以將準確率做到很高的程度,該結構由 Burton Howard Bloom 於 1970 年提出。

首先介紹哈希函數(散列函數)的概念。哈希函數的輸入域可以是非常大的範圍,比如,任意一個字符串,但是輸入域是固定的範圍,假設爲 S,並具有如下性質:

  • 典型的哈希函數都有無限的輸入值域;
  • 當給哈希函數傳入相同的輸入值時,返回值一樣;
  • 當給哈希函數傳入不同的輸入值時,返回值可能一樣,也可能不一樣,這是當然的,因爲輸出域統一是 S,所以會有不同的輸入值對應在 S 中的一個元素上;
  • 最重要的是性質是很多不同的輸入值所得到的返回值會均勻分佈在 S 上;

第 1~3 點性質是哈希函數的基礎,第 4 性質是評價一個哈希函數優劣的關鍵,不同輸入值所得到所有返回值越均勻地分佈到 S 上,哈希函數越優秀,並且這種均勻分佈與輸入值出現的規律無關。比如,“aaa1”、“aaa2”、“aaa3”三個輸入值比較類似,但經過優秀的哈希函數計算後的結果應該相差非常大。一些哈希函數經典的實現,比如 MD5 和 SHA1 算法。如果一個優秀的哈希函數能夠做到很多不同的輸入值所得到的返回值非常均勻地分佈在 S 上,那麼將所有的返回值對 m 取餘(%m),可以認爲所有的返回值也會均勻地分佈在 0~m-1的空間上。

接下來介紹什麼是布隆過濾器。假設有一個長度爲 m 的 bit 類型的數組,即數組中的每一個位置只佔一個 bit,每一個 bit 只有 0 和 1 兩種狀態,如下圖所示:
在這裏插入圖片描述
再假設一共有 k 個哈希函數,這些函數的輸出域 S 都大於或等於 m,並且這些哈希函數都足夠優秀,彼此之間也完全獨立。那麼對同一個輸入對象(假設是一個字符串記爲 URL),經過 k 個哈希函數算出來的結果也是獨立的,可能相同,也可能不同,但彼此獨立。對算出來的每一個結果都對 m 取餘(%m),然後在 bit array 上把對應的位置設置爲 1(塗黑),如下圖所示:
在這裏插入圖片描述
把 bit 類型的數組記爲 bitMap。至此,一個輸入對象對 bitMap 的影響過程就結束了,也就是 bitMap 中的一些位置被塗黑。接下來按照該方法處理所有塗黑的位置,遇到已經塗黑的位置讓其繼續爲黑即可。處理完所有的輸入對象後,可能 bitMap 中已經有相當多的位置被塗黑。至此,一個布隆過濾器生成完畢,這個布隆過濾器代表之前所有輸入對象組成的集合。

那麼在檢查階段時,如何檢查某一個對象是否是之前的某一個輸入對象呢?假設一個對象爲 a,想檢查它是否是之前的輸入對象,就把 a 通過 k 個哈希函數算出 k 個值,然後把 k 個值取餘(%m),就得到 [0, m-1] 範圍上的 k 個值。接下來在 bitMap 上看這些位置是不是都爲黑。如果有一個不爲黑,說明 a 一定不在這個集合裏。如果都爲黑,說明 a 在這個集合裏,但可能有誤判。再解釋具體一點,如果 a 的確是輸入對象,那麼在生成布隆過濾器時,bitMap 中相應的 k 個位置一定已經塗黑了,所以在檢查階段,a 一定不會被漏過,這個不會產生誤判。會產生誤判的是,a 明明不是輸入對象,但如果在生成布隆過濾器的階段因爲輸入對象過多,而 bitMap 過小,則會導致bitMap 絕大多數的位置都已經變黑。那麼在檢查 a 時,可能 a 對應的 k 個位置都是黑的,從而錯誤地認爲 a 是輸入對象。通俗地說,布隆過濾器的失誤類型是“寧可錯殺三千,絕不放過一個”。

關於布隆過濾器的實現請參考《程序代碼面試指南》——左程雲著,或者 https://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章