布隆過濾器認知

  布隆過濾器 (Bloom Filter)是由Burton Howard Bloom於1970年提出,它是一種space efficient的機率型數據結構,用於判斷一個元素是否在集合中。html

看看下面幾個問題:算法

  • 字處理軟件中,須要檢查一個英語單詞是否拼寫正確
  • 在 FBI,一個嫌疑人的名字是否已經在嫌疑名單上
  • 在網絡爬蟲裏,一個網址是否被訪問過
  • 郵箱垃圾郵件過濾功能

  以上這些場景有個共同的問題:如何查看一個東西是否在有大量數據的池子裏面。數組

一般作法有如下幾種思路:網絡

  • 數組
  • 鏈表
  • 樹、平衡二叉樹、Trie
  • Map (紅黑樹)
  • 哈希表

問題:數據結構

  上面這幾種數據結構配合一些搜索算法是能夠解決數據量不大的問題的,若是當集合裏面的數據量很是大的時候,就會有問題。好比:
  有500萬條記錄甚至1億條記錄?這個時候常規的數據結構的問題就凸顯出來了。數組、鏈表、樹等數據結構會存儲元素的內容,一旦數據量過大,消耗的內存也會呈現線性增加,最終達到瓶頸。哈希表查詢效率能夠達到O(1)。可是哈希表須要消耗的內存依然很高。使用哈希表存儲一億 個垃圾 email 地址的消耗?哈希表的作法:首先,哈希函數將一個email地址映射成8字節信息指紋;考慮到哈希表存儲效率一般小於50%(哈希衝突);所以消耗的內存:8 * 2 * 1億 字節 = 1.6G 內存,普通計算機是沒法提供如此大的內存。這個時候,布隆過濾器(Bloom Filter)就應運而生。

1、哈希函數

  哈希函數的概念是:將任意大小的數據轉換成特定大小的數據的函數,轉換後的數據稱爲哈希值或哈希編碼。下面是一幅示意圖:
    

  能夠明顯的看到,原始數據通過哈希函數的映射後稱爲了一個個的哈希編碼,數據獲得壓縮。哈希函數是實現哈希表和布隆過濾器的基礎。 dom

2、布隆過濾器介紹

  • 巴頓.布隆於一九七零年提出
  • 一個很長的二進制向量 (位數組)
  • 一系列隨機函數 (哈希)
  • 空間效率和查詢效率高
  • 不會漏判,可是有必定的誤判率(哈希表是精確匹配)

3、布隆過濾器原理

  布隆過濾器(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,這是誤判率存在的緣由。編碼

添加元素

  • 將要添加的元素給k個哈希函數
  • 獲得對應於位數組上的k個位置
  • 將這k個位置設爲1

查詢元素

  • 將要查詢的元素給k個哈希函數
  • 獲得對應於位數組上的k個位置
  • 若是k個位置有一個爲0,則確定不在集合中
  • 若是k個位置所有爲1,則可能在集合中

4、算法描述

  一個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,但這種狀況相對少見。

5、時間和空間上的優點

  當能夠承受一些誤報時,布隆過濾器比其它表示集合的數據結構有着很大的空間優點。例如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性。

 

具體算法推導和證實請參看詳細連接:布隆過濾器詳解

相關文章
相關標籤/搜索