布隆過濾器 (Bloom Filter)是由Burton Howard Bloom於1970年提出,它是一種space efficient的機率型數據結構,用於判斷一個元素是否在集合中。html
看看下面幾個問題:算法
以上這些場景有個共同的問題:如何查看一個東西是否在有大量數據的池子裏面。數組
一般作法有如下幾種思路:網絡
問題:數據結構
能夠明顯的看到,原始數據通過哈希函數的映射後稱爲了一個個的哈希編碼,數據獲得壓縮。哈希函數是實現哈希表和布隆過濾器的基礎。 dom
布隆過濾器(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,這是誤判率存在的緣由。編碼
一個empty bloom filter是一個有m bits的bit array,每個bit位都初始化爲0。而且定義有k個不一樣的hash function,每一個都以uniform random distribution將元素hash到m個不一樣位置中的一個。在下面的介紹中n爲元素數,m爲布隆過濾器或哈希表的slot數,k爲布隆過濾器重hash function數。spa
爲了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性。
具體算法推導和證實請參看詳細連接:布隆過濾器詳解