布隆過濾器

背景

之前讀吳軍《數學之美》的時候提到布隆過濾器,覺得蠻有意思的,所以總結一下。 在計算機中,判斷一個元素是不是在一個集合中,通常是用hash來解決,這在數據量不大的時候是可以的,但是當數據量很大的時候存儲空間就會爆炸。

一個象 Yahoo,Hotmail 和 Gmai 那樣的公衆電子郵件(email)提供商,總是需要過濾來自發送垃圾郵件的人(spamer)的垃圾郵件。一個辦法就是記錄下那些發垃圾郵件的 email 地址。由於那些發送者不停地在註冊新的地址,全世界少說也有幾十億個發垃圾郵件的地址,將他們都存起來則需要大量的網絡服務器。如果用哈希表,每存儲一億個 email 地址, 就需要 1.6GB 的內存(用哈希表實現的具體辦法是將每一個 email 地址對應成一個八字節的信息指紋 googlechinablog.com/2006/08/blog-post.html,然後將這些信息指紋存入哈希表,由於哈希表的存儲效率一般只有 50%,因此一個 email 地址需要佔用十六個字節。一億個地址大約要 1.6GB, 即十六億字節的內存)。因此存貯幾十億個郵件地址可能需要上百 GB 的內存。除非是超級計算機,一般服務器是無法存儲的。

解決的問題

大數據量的時候, 判斷一個元素是否在一個集合中。

實現原理

布隆過濾器(Bloom Filter)的核心實現是一個超大的位數組和幾個哈希函數。假設位數組的長度爲m,哈希函數的個數爲k

布隆過濾器 以上圖爲例,具體的操作流程:假設集合裏面有3個元素{x, y, z},哈希函數的個數爲3。首先將位數組進行初始化,將裏面每個位都設置位0。

添加元素

對於集合裏面的每一個元素,將元素依次通過3個哈希函數進行映射,每次映射都會產生一個哈希值,這個值對應位數組上面的一個點,然後將位數組對應的位置標記爲1。

查詢元素

查詢W元素是否存在集合中的時候,同樣的方法將W通過哈希映射到位數組上的3個點。如果3個點的其中有一個點不爲1,則可以判斷該元素一定不存在集合中。反之,如果3個點都爲1,則該元素可能存在集合中。注意:此處不能判斷該元素是否一定存在集合中,可能存在一定的誤判率。可以從圖中可以看到:假設某個元素通過映射對應下標爲4,5,6這3個點。雖然這3個點都爲1,但是很明顯這3個點是不同元素經過哈希得到的位置,因此這種情況說明元素雖然不在集合中,也可能對應的都是1,這是誤判率存在的原因。

移除集合中的元素

這個在布隆過濾器中是不允許的,理解原理我們就知道,如果將是1的位置重置成0會影響其他元素是不是在集合中的判斷。對於關小黑屋再放出來這種需求,我們可以換一個思路,再加一個布隆過濾器————“被移除的元素”,當然現在公司都比較土豪,直接用redis存一個過期時間就可以,那就不在我們討論之列了,布隆過濾器的初衷是用少許的誤判來極大的節省空間。

錯誤率

假設 Hash 函數以等概率條件選擇並設置 Bit Array 中的某一位,假定由每個 Hash 計算出需要設置的位(bit) 的位置是相互獨立, m 是該位數組的大小,k 是 Hash 函數的個數. 位數組中某一特定的位在進行元素插入時的 Hash 操作中沒有被置位的概率是:

在所有 k 次 Hash 操作後該位都沒有被置 "1" 的概率是:

如果我們插入了 n 個元素,那麼某一位仍然爲 "0" 的概率是:

該位爲 "1"的概率是:

檢測某一元素是否在該集合中。標明某個元素是否在集合中所需的 k 個位置都按照如上的方法設置爲 "1",但是該方法可能會使算法錯誤的認爲某一原本不在集合中的元素卻被檢測爲在該集合中(False Positives),該概率由以下公式確定:

如何使得錯誤率最小,對於給定的m和n,當 k=m/n * ln2 的時候取值最小。關係如下圖所示:

應用

  • HBASE、Cassandra數據庫中用來判斷數據是不是在磁盤上
  • chrome用它來做釣魚網站監測
  • 在比特幣中用來判斷是不是屬於錢包
  • 垃圾郵件監測

參考資料

https://en.wikipedia.org/wiki/Bloom_filter http://blog.jobbole.com/113396/

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