1. 程式人生 > >淺談BloomFilter【上】基本概念和實現原理

淺談BloomFilter【上】基本概念和實現原理

pty 是否 的人 它的 構建 網絡爬蟲 ace head filters

? ??在日常生活中。包括在設計計算機軟件時,我們常常要推斷一個元素是否在一個集合中。

? ? 比方在字處理軟件中,須要檢查一個英語單詞是否拼寫正確(也就是要推斷 它是否在已知的字典中)。在 FBI。一個嫌疑人的名字是否已經在嫌疑名單上;在網絡爬蟲裏。一個網址是否被訪問過等等。最直接的方法就是將集合中所有的元素存在計算機中,遇到一個新 元素時,將它和集合中的元素直接比較就可以。一般來講。計算機中的集合是用哈希表(hash table)來存儲的。

它的長處是高速準確。缺點是費存儲空間。當集合比較小時。這個問題不顯著。可是當集合巨大時,哈希表存儲效率低的問題就顯現出來 了。比方說。一個象 Yahoo,Hotmail 和 Gmai 那樣的公眾電子郵件(email)提供商。總是須要過濾來自發送垃圾郵件的人(spamer)的垃圾郵件。一個辦法就是記錄下那些發垃圾郵件的 email 地址。

由於那些發送者不停地在註冊新的地址,全世界少說也有幾十億個發垃圾郵件的地址,將他們都存起來則須要大量的網絡server。假設用哈希表,每存儲一億 個 email 地址, 就須要 1.6GB 的內存(用哈希表實現的詳細辦法是將每一個 email 地址相應成一個八字節的信息指紋(詳見:googlechinablog.com/2006/08/blog-post.html)。 然後將這些信息指紋存入哈希表。由於哈希表的存儲效率一般僅僅有 50%,因此一個 email 地址須要占用十六個字節。一億個地址大約要 1.6GB。 即十六億字節的內存)。

因此存貯幾十億個郵件地址可能須要上百 GB 的內存。除非是超級計算機。一般server是無法存儲的。(該段引用谷歌數學之美:http://www.google.com.hk/ggblog/googlechinablog/2007/07/bloom-filter_7469.html)


一、基本概念

? ??布隆過濾器(Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出的。它實際上是由一個非常長的二進制向量和一系列隨機映射函數組成,布隆過濾器能夠用於檢索一個元素是否在一個集合中。它的長處是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率(假正例False positives,即Bloom Filter報告某一元素存在於某集合中,可是實際上該元素並不在集合中)和刪除困難,可是沒有識別錯誤的情形(即假反例False negatives,假設某個元素確實沒有在該集合中,那麽Bloom Filter 是不會報告該元素存在於集合中的,所以不會漏報)。

? ? 假設想推斷一個元素是不是在一個集合裏。一般想到的是將所有元素保存起來。然後通過比較確定。

鏈表,樹等等數據結構都是這樣的思路. 可是隨著集合中元素的添加,我們須要的存儲空間越來越大,檢索速度也越來越慢。只是世界上另一種叫作散列表(又叫哈希表,Hash table)的數據結構。它能夠通過一個Hash函數將一個元素映射成一個位陣列(Bit Array)中的一個點。

這樣一來。我們僅僅要看看這個點是不是 1 就知道能夠集合中有沒有它了。這就是布隆過濾器的基本思想。

Hash面臨的問題就是沖突。

假設 Hash 函數是良好的,假設我們的位陣列長度為 m 個點,那麽假設我們想將沖突率減少到比如 1%, 這個散列表就僅僅能容納 m/100 個元素。顯然這就不叫空間有效了(Space-efficient)。

解決方法也簡單,就是使用多個 Hash,假設它們有一個說元素不在集合中,那肯定就不在。假設它們都說在,盡管也有一定可能性它們在說謊。只是直覺上推斷這樣的事情的概率是比較低的。

長處

? ??相比於其他的數據結構。布隆過濾器在空間和時間方面都有巨大的優勢。布隆過濾器存儲空間和插入/查詢時間都是常數。另外, Hash 函數相互之間沒有關系,方便由硬件並行實現。布隆過濾器不須要存儲元素本身,在某些對保密要求非常嚴格的場合有優勢。

? ??布隆過濾器能夠表示全集。其他不論什麽數據結構都不能;

? ??k 和 m 同樣,使用同一組 Hash 函數的兩個布隆過濾器的交並差運算能夠使用位操作進行。

缺點

? ??可是布隆過濾器的缺點和長處一樣明顯。誤算率(False Positive)是當中之中的一個。隨著存入的元素數量添加,誤算率隨之添加。

可是假設元素數量太少,則使用散列表足矣。

? ??另外,普通情況下不能從布隆過濾器中刪除元素. 我們非常easy想到把位列陣變成整數數組。每插入一個元素相應的計數器加1, 這樣刪除元素時將計數器減掉就能夠了。

然而要保證安全的刪除元素並非如此簡單。首先我們必須保證刪除的元素的確在布隆過濾器裏面. 這一點單憑這個過濾器是無法保證的。另外計數器回繞也會造成問題。


二、算法描寫敘述

? ??一個empty bloom filter是一個有m bits的bit array。每一個bit位都初始化為0。

而且定義有k個不同的hash function,每一個都以uniform random distribution將元素hash到m個不同位置中的一個。

在以下的介紹中n為元素數,m為布隆過濾器或哈希表的slot數,k為布隆過濾器重hash function數。

? ??為了add一個元素,用k個hash function將它hash得到bloom filter中k個bit位,將這k個bit位置1。

? ??為了query一個元素。即推斷它是否在集合中。用k個hash function將它hash得到k個bit位。若這k bits全為1,則此元素在集合中。若當中任一位不為1,則此元素比不在集合中(由於假設在,則在add時已經把相應的k個bits位置為1)。

? ??不同意remove元素,由於那樣的話會把相應的k個bits位置為0。而當中非常有可能有其他元素相應的位。因此remove會引入false negative,這是絕對不被同意的。

? ??當k非常大時。設計k個獨立的hash function是不現實而且困難的。對於一個輸出範圍非常大的hash function(比如MD5產生的128 bits數)。假設不同bit位的相關性非常小,則可把此輸出切割為k份。

或者可將k個不同的初始值(比如0,1,2, … ,k-1)結合元素,feed給一個hash function從而產生k個不同的數。

? ??當add的元素過多時,即n/m過大時(n是元素數,m是bloom filter的bits數),會導致false positive過高,此時就須要又一次組建filter。但這樣的情況相對少見。


三、 時間和空間上的優勢

? ? 當能夠承受一些誤報時,布隆過濾器比其他表示集合的數據結構有著非常大的空間優勢。比如self-balance BST, tries, hash table或者array, chain,它們中大多數至少都要存儲元素本身。對於小整數須要少量的bits,對於字符串則須要隨意多的bits(tries是個例外。由於對於有同樣prefixes的元素能夠共享存儲空間);而chain結構還須要為存儲指針付出額外的代價。對於一個有1%誤報率和一個最優k值的布隆過濾器來說。不管元素的類型及大小,每一個元素僅僅須要9.6 bits來存儲。這個長處一部分繼承自array的緊湊性。一部分來源於它的概率性。

假設你覺得1%的誤報率太高,那麽對每一個元素每添加4.8 bits。我們就可將誤報率減少為原來的1/10。

add和query的時間復雜度都為O(k)。與集合中元素的多少無關,這是其他數據結構都不能完畢的。

? ??假設可能元素範圍不是非常大,而且大多數都在集合中,則使用確定性的bit array遠遠勝過使用布隆過濾器。由於bit array對於每一個可能的元素空間上僅僅須要1 bit,add和query的時間復雜度僅僅有O(1)。註意到這樣一個哈希表(bit array)僅僅有在忽略collision而且僅僅存儲元素是否在當中的二進制信息時,才會獲得空間和時間上的優勢,而在此情況下。它就有效地稱為了k=1的布隆過濾器。

? ??而當考慮到collision時,對於有m個slot的bit array或者其他哈希表(即k=1的布隆過濾器)。假設想要保證1%的誤判率,則這個bit array僅僅能存儲m/100個元素。因而有大量的空間被浪費,同一時候也會使得空間復雜度急劇上升,這顯然不是space efficient的。

解決辦法非常簡單,使用k>1的布隆過濾器。即k個hash function將每一個元素改為相應於k個bits。由於誤判度會減少非常多。而且假設參數k和m選取得好,一半的m可被置為為1,這充分說明了布隆過濾器的space efficient性。


四、 舉例說明

? ??以垃圾郵件過濾中黑白名單為例:現有1億個email的黑名單,每一個都擁有8 bytes的指紋信息,則可能的元素範圍為技術分享圖片? 。對於bit array來說是根本不可能的範圍,而且元素的數量(即email列表)為 ?技術分享圖片。相比於元素範圍過於稀疏,而且還沒有考慮到哈希表中的collision問題。

? ??若採用哈希表,由於大多數採用open addressing來解決collision。而此時的search時間復雜度為技術分享圖片?。

即若哈希表半滿(n/m = 1/2)。則每次search須要probe 2次,因此在保證效率的情況下哈希表的存儲效率最好不超過50%。此時每一個元素占8 bytes,總空間為:?技術分享圖片?。若採用Perfect hashing(這裏能夠採用Perfect hashing是由於主要操作是search/query,而並非add和remove)。盡管保證worst-case也僅僅有一次probe,可是空間利用率更低,普通情況下為50%。worst-case時有不到一半的概率為25%。

若採用布隆過濾器,取k=8。

由於n為1億,所以總共須要 技術分享圖片 被置位為1。又由於在保證誤判率低且k和m選取合適時,空間利用率為50%(後面會解釋),所以總空間為:技術分享圖片

所需空間比上述哈希結構小得多,而且誤判率在萬分之中的一個以下。


五、誤判概率的證明和計算

假設布隆過濾器中的hash function滿足simple uniform hashing假設:每一個元素都等概率地hash到m個slot中的不論什麽一個。與其他元素被hash到哪個slot無關。

若m為bit數,則對某一特定bit位在一個元素由某特定hash function插入時沒有被置位為1的概率為:

技術分享圖片

則k個hash function中沒有一個對其置位的概率為:

技術分享圖片

假設插入了n個元素,但都未將其置位的概率為:

技術分享圖片

則此位被置位的概率為:

技術分享圖片

如今考慮query階段,若相應某個待query元素的k bits所有置位為1。則可判定其在集合中。因此將某元素誤判的概率為:

技術分享圖片

由於?技術分享圖片,而且?技術分享圖片? 當m非常大時趨近於0,所以

技術分享圖片

從上式中能夠看出,當m增大或n減小時。都會使得誤判率減小,這也符合直覺。

如今計算對於給定的m和n。k為何值時能夠使得誤判率最低。

設誤判率為k的函數為:

技術分享圖片

設??技術分享圖片?, 則簡化為

技術分享圖片,兩邊取對數

技術分享圖片? , 兩邊對k求導

技術分享圖片

以下求最值

技術分享圖片

技術分享圖片?技術分享圖片

技術分享圖片?技術分享圖片

技術分享圖片?技術分享圖片

技術分享圖片?技術分享圖片

技術分享圖片?技術分享圖片

技術分享圖片?技術分享圖片

技術分享圖片?技術分享圖片

因此,即當?技術分享圖片? 時誤判率最低,此時誤判率為:

技術分享圖片

能夠看出若要使得誤判率≤1/2。則:

技術分享圖片

這說明了若想保持某固定誤判率不變。布隆過濾器的bit數m與被add的元素數n應該是線性同步添加的。


六、設計和應用布隆過濾器的方法

? ??應用時首先要先由用戶決定要add的元素數n和希望的誤差率P。這也是一個設計完整的布隆過濾器須要用戶輸入的僅有的兩個參數,之後的所有參數將由系統計算。並由此建立布隆過濾器。

系統首先要計算須要的內存大小m bits:

技術分享圖片

再由m。n得到hash function的個數:

技術分享圖片

至此系統所需的參數已經備齊,接下來add n個元素至布隆過濾器中。再進行query。

依據公式。當k最優時:

技術分享圖片

技術分享圖片

因此可驗證當P=1%時,存儲每一個元素須要9.6 bits:

技術分享圖片

而每當想將誤判率減少為原來的1/10。則存儲每一個元素須要添加4.8 bits:

技術分享圖片

這裏須要特別註意的是。9.6 bits/element不僅包括了被置為1的k位,還把包括了沒有被置為1的一些位數。此時的

技術分享圖片

才是每一個元素相應的為1的bit位數。

技術分享圖片?? 從而使得P(error)最小時。我們註意到:

技術分享圖片?中的?技術分享圖片? ,即

技術分享圖片

此概率為某bit位在插入n個元素後未被置位的概率。因此,想保持錯誤率低。布隆過濾器的空間使用率需為50%。

技術分享圖片


七、Bloom Filter 用例

? ??Google 著名的分布式數據庫 Bigtable 使用了布隆過濾器來查找不存在的行或列,以減少磁盤查找的IO次數[3]。

? ??Squid 網頁代理緩存server在?cache digests?中使用了也布隆過濾器[4]。

? ??Venti 文檔存儲系統也採用布隆過濾器來檢測先前存儲的數據[5]。

? ??SPIN 模型檢測器也使用布隆過濾器在大規模驗證問題時跟蹤可達狀態空間[6]。

? ??Google Chrome瀏覽器使用了布隆過濾器加速安全瀏覽服務[7]。

? ??在非常多Key-Value系統中也使用了布隆過濾器來加快查詢過程,如 Hbase。Accumulo,Leveldb,一般而言,Value 保存在磁盤中。訪問磁盤須要花費大量時間。然而使用布隆過濾器能夠高速推斷某個Key相應的Value是否存在,因此能夠避免非常多不必要的磁盤IO操作。僅僅是引入布隆過濾器會帶來一定的內存消耗,下圖是在Key-Value系統中布隆過濾器的典型使用:

技術分享圖片


八、布隆過濾器相關擴展

Counting filters

? ??主要的布隆過濾器不支持刪除(Deletion)操作,可是 Counting filters 提供了一種能夠不用又一次構建布隆過濾器但卻支持元素刪除操作的方法。在Counting filters中原來的位數組中的每一位由 bit 擴展為 n-bit 計數器。實際上,主要的布隆過濾器能夠看作是僅僅有一位的計數器的Counting filters。原來的插入操作也被擴展為把 n-bit 的位計數器加1,查找操作即檢查位數組非零就可以。而刪除操作定義為把位數組的相應位減1。可是該方法也有位的算術溢出問題,即某一位在多次刪除操作後可能變成負值,所以位數組大小 m 須要充分大。另外一個問題是Counting filters不具備伸縮性,由於Counting filters不能擴展,所以須要保存的最大的元素個數須要提前知道。

否則一旦插入的元素個數超過了位數組的容量。false positive的發生概率將會急劇添加。當然也有人提出了一種基於 D-left Hash 方法實現支持刪除操作的布隆過濾器。同一時候空間效率也比Counting filters高。


Data synchronization

? ??Byers等人提出了使用布隆過濾器近似數據同步[9]。

Bloomier filters

? ??Chazelle 等人提出了一個通用的布隆過濾器,該布隆過濾器能夠將某一值與每一個已經插入的元素關聯起來。並實現了一個關聯數組Map[10]。

與普通的布隆過濾器一樣。Chazelle實現的布隆過濾器也能夠達到較低的空間消耗,但同一時候也會產生false positive。只是,在Bloomier filter中。某 key 假設不在 map 中,false positive在會返回時會被定義出的。

該Map 結構不會返回與 key 相關的在 map 中的錯誤的值。

在下一節。我們將會用Java 實現一個簡單的 BloomFilter.

Java實現?BloomFilter:http://blog.csdn.net/zq602316498/article/details/40660695

本文圖片和內容文字來源與兩篇文章,原文地址:

http://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html

http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html


淺談BloomFilter【上】基本概念和實現原理