閱讀目錄:html
Bloom filter(後面簡稱BF)是Bloom在1970年提出的二進制向量數據結構。通俗來講就是在大數據集合下高效判斷某個成員是否屬於這個集合。BF其優勢在於:算法
像Yahoo這類的公共郵件服務提供商,老是須要過濾垃圾郵件。 假設有50億個郵件地址,須要存儲過濾的方法有:數據庫
而使用BF能夠最大限度避免上述缺點,使其能夠在更小空間上,進行高效插入和查詢。數組
常用緩存的確定知道,命中率是個永遠的話題。 特別是在分佈式緩存中,每次不命中就意味着一次跨網絡通訊的浪費,無端增長緩存服務器壓力。使用BF能夠在很大程度上提升緩存命中率。緩存
BF很合適解決相似上面的問題。 BF和例子1中的第三種方法很是相似了。不一樣的是,BF對同一個郵件地址使用多個不一樣的Hash函數,再去映射位數組的中對應位置。 服務器
以函數個數k=8來算,50億個郵件地址只須要5G內存足夠了,比例子1中方法2節省32倍空間。網絡
當查詢成員a時是否在垃圾郵件集合m中時,使用一樣k個hash函數進行計算,若是k個結果在位數組中的位值都是1,則判斷a屬於m集合中,即a郵件地址屬於垃圾郵件地址集合m(a∈m)。 數據結構
關於例子2,能夠將全部key存儲到本地內存中,每次遠程獲取緩存時,優先在內存集合中判斷是否存在。分佈式
這樣能極大提升緩存命中率,由於BF存在誤判率,全部並不能達到100%(在key的數量級不高時,用其餘方法全存下來也能夠)。如圖:函數
由於BF使用Hash函數來取得成員的特徵(可理解爲成員的指紋信息),並無在位數組中存儲集合內的實際數據內容,因此空間利用率極高,但存在個潛在問題,就是查詢某個成員是否屬於集合時,會發生誤判(False positive)。 也就是說,某個成員實際不在集合中,但BF會得出在集中的結論。 因此BF適用於容許發生必定誤判的場景,如例子一、2中少許過濾失敗或去服務器拿都是能夠接受的。
假定有一個長度12的位數組,使用3個hash函數,根據算法計算成員a得出三、七、11位置,並在位數組中設置爲1。 另外個成員b根據算法也計算得出三、七、11,去位數組檢查其位值時,就發現三、七、11都爲1是存在的,而實際不存在(1是成員a設置的),此時就發生了誤判現象。
BF會發生誤判,但不會發生漏判(False Negative),即成員實際在集合中,那麼BF必定能判斷出在集合中,由於成員對應的位置都設置爲1了。
根據其數組長度m、集合大小n、hash函數個數k、誤判率p,簡單得出下:
hash函數個數取值公式 k = ln 2 * m/n 。
其餘它關係公式見wiki。
基本的BF在使用時有個缺點:沒法刪除集合成員a,只能增長其成員並對其查詢。 有一個很容易想到但錯誤的方法是:若是要刪除成員a,那麼先用k個hash函數對其計算,由於a已是集合成員,那麼其對應的位數組的位置必定被設置爲1,因此只要將對應位置從新設置爲0便可。 緣由就是位數組的位置不但只提供給a使用,也給其餘成員使用,一旦設置爲0就會影響其餘成員的使用。
好比上面中提升緩存命中率的例子,不能刪除成員意味着實際緩存也不能刪除。若是實際緩存刪除了,而在集合中的數據沒法刪除,就會發生漏判現象。 這樣的話就會大大限制BF的使用場景。
計數BF是對基本BF的改進,使BF能夠支持刪除成員。 由於BF的基本單位是1個bit,只能表達2種狀態,即存在、不存在。 若是把基本單位1bit拓展成多個bit,這樣就能增長更多信息,表達出多種狀態。
計數BF的基本單元由多個bit表示,通常狀況爲三、4個bit。 這樣在添加時,在數組位置上的數值上加1便可,刪除成員時-1便可。 查詢集合成員時保持不變,只要數值不爲0即認爲成員是存在的。
計數BF使基本BF有了更多應用場景。 一樣因爲用了多個bit來表示,對應數組大小也相應增長,若是用3bit做爲基本單位,那麼數組大小對應增長了3倍。
BF是大數據處理的利器,其使用場景很是多:
基本BF的具體實現可參考 http://bloomfilter.codeplex.com。
[1] http://en.wikipedia.org/wiki/Bloom_filter
[2] http://www.cnblogs.com/heaad/archive/2011/01/02/1924195.html