Bloom Filter

Bloom是我的名。html

相關資源:

【原】布隆過濾器 (Bloom Filter) 詳解

布隆過濾器的原理和實現

公司的一道考試題算法分析——大數據量整數排序

數學之美系列二十一 - 布隆過濾器(Bloom Filter)

https://llimllib.github.io/bloomfilter-tutorial/

https://en.wikipedia.org/wiki/Bloom_filter

布隆過濾器 -- 空間效率很高的數據結構

Bloom Filter(布隆過濾器)的概念和原理

經典算法系(6)-布隆過濾器(Bloom Filter)和哈希函數(Hash Function)

[1] A. Broder and M. Mitzenmacher. Network applications of bloom filters: A survey. Internet Mathematics, 1(4):485–509, 2005.

[2] M. Mitzenmacher. Compressed Bloom Filters. IEEE/ACM Transactions on Networking 10:5 (2002), 604—612.

[3] www.cs.jhu.edu/~fabian/courses/CS600.624/slides/bloomslides.pdf

[4] http://166.111.248.20/seminar/2006_11_23/hash_2_yaxuan.ppt

Bloom Filter概念和原理

1: Network Applications of Bloom Filters: A Survey, Broder and Mitzenmacher. An excellent overview.

2: Wikipedia, which has an excellent and comprehensive page on Bloom filters

3: Less Hashing, Same Performance, Kirsch and Mitzenmacher

4: Scalable Bloom Filters, Almeida et al

學習Bloom Filter

一、概述

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

 

Bloom filter 是一個數據結構,它能夠用來判斷某個元素是否在集合內,具備運行快速,內存佔用小的特色。python

而高效插入和查詢的代價就是,Bloom Filter 是一個基於機率的數據結構:它只能告訴咱們一個元素絕對不在集合內或可能在集合內
git

 

判斷一個元素是否在集合中可用的方法有:github

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

既然已經有了這麼多的方法,爲啥還要用布隆過濾器這種會產生誤判的方法呢?算法

 

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

 

假定咱們存儲一億個電子郵件地址,咱們先創建一個十六億二進制(比特),即兩億字節的向量,而後將這十六億個二進制所有設置爲零。對於每個電子郵件地址 X,咱們用八個不一樣的隨機數產生器(F1,F2, ...,F8) 產生八個信息指紋(f1, f2, ..., f8)。再用一個隨機數產生器 G 把這八個信息指紋映射到 1 到十六億中的八個天然數 g1, g2, ...,g8。如今咱們把這八個位置的二進制(這裏沒太明白,八個位置的二進制的意思是,這八個位置的意思每一個位置表明了若干個字節?)所有設置爲一。當咱們對這一億個 email 地址都進行這樣的處理後。一個針對這些 email 地址的布隆過濾器就建成了。(見下圖)segmentfault

 

image

二、應用場景:

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

 

哈希表也能用於判斷元素是否在集合中,可是布隆過濾器只須要哈希表的1/8或1/4的空間複雜度就能完成一樣的問題。(優勢:佔用空間小數組

布隆過濾器能夠插入元素,但不能夠刪除已有元素。(操做特色:不能刪除元素,由於你不知道你刪的是哪一個網絡

其中的元素越多,誤報率越大,可是漏報是不可能的。(查重特色:寧可錯殺三千,不會放過一個

三、算法描述

首先一個空的布隆過濾器是有m個bit的位數組,每一個bit位都被初始化爲0。

同時,還有須要定義k個不一樣的哈希函數,每一個都會將元素經過該哈希函數計算到m個不一樣位置中的一個。

 

下面描述的時候規定:n表示待判別的元素個數,m爲布隆過濾器或者哈希表的slot數,k爲布隆過濾器哈希函數的個數。

 

  • 增長元素:用k個哈希函數將它hash獲得bloom filter中k個bit位,將這k個bit位置1。
  • 查詢元素:爲了判斷一個元素是否在集合中,能夠用k個hash函數將它進行hash獲得k個bit位。若是這k個bit位全爲1,則此元素在集合中;若是其中任意一位不爲1,則此元素不在集合中。
  • 移除元素:一旦向布隆過濾器中添加了一個元素,那麼是不容許從布隆過濾器中移除的,由於不能保證你不會講其餘對應到這k個bit的元素同時移除了,這樣一來就會致使誤判。

 

布隆過濾器(Bloom Filter)的核心實現是一個超大的位數組和幾個哈希函數。

image

以上圖爲例,具體的操做流程:假設集合裏面有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個獨立的哈希函數比較困難;可供替換的方法有:利用輸出範圍很大的哈希函數(如MD5產生的128位),將輸出分爲k份,或者將k個不一樣的初始值結合元素,給哈希函數生成k個不一樣的數。

 

若是向布隆過濾器增長的元素過多,n/m過大,會致使誤判率升高,所以要麼從新創建布隆過濾器,要麼在開始預估一下須要布隆過濾器中會加入多少元素,而後選擇合適的m。

五、時間和空間上的優點

能夠當作集合來存儲元素的數據結構有:self-balance BST,tries(肯定沒寫錯),hash table或者array,chain;它們中的大多數至少須要存儲元素自己,對於小的整數須要少許的bits,對於字符串則須要任意多的bits(tries例外,由於元素能夠共享存儲空間);而chain結構還要爲存儲指針付出額外的代價。布隆過濾器的插入和查詢操做的複雜度都爲O(k),與集合中元素的多少無關,這是其餘的數據結構都沒法比擬的。

 

若是數據元素不是不少,而且大多都在集合中,則使用肯定性的bit array遠遠賽過使用布隆過濾器。由於bit array對於每一個可能的元素空間上只須要1bit。

 

當考慮到衝突時,對於有m個slot(槽)的bit array或者其餘哈希表,若是要保證1%的誤判率,則這個bit array只能存儲m/100個元素,於是有大量的空間被浪費,同時空間複雜度也會急劇上升。這裏可使用k>1的布隆過濾器,即k個哈希函數將每一個元素對應於k個bits,從而誤判率會下降不少,若是k和m選取合適,可使一半的m被置爲1,很是節省空間。

 

 

 

代碼實現

 

 

 

哈希函數簡單介紹

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

 

image

 

Bloom filter 裏的哈希函數須要是彼此獨立均勻分佈。同時,它們也須要儘量的快 (儘管 sha1 之類的加密哈希算法被普遍應用,可是在這一點上考慮並非一個很好的選擇).

這些都是快速,簡單且彼此獨立的哈希函數的例子: 包括 murmur, fnv 族哈希函數, 以及HashMix.

若是你但願瞭解一個比加密哈希函數快的哈希函數能夠達到什麼程度,能夠參考這個故事。當把 bloom filter 的實現從 md5 切換到 murmur 時,速度提高了 800%。

一個關於 Bloom filter 實現方式的簡單調查:

 

關於哈希函數更深刻介紹,能夠看這裏的:

哈希表之一初步原理了解

哈希表之二哈希函數的構造

哈希表之三衝突解決

哈希表之四查找及分析

 

高級話題

在寫下更過關於 Bloom filter 的內容以前,我須要聲明一點:我從未在生產環境使用過 Bloom filter(我擦,大家都不用,而後告訴別人這個好用,仍是沒有用到適用場景?)。因此不要不假思索的相信下面的內容,我想作的只是給你一個歸納式的介紹,同時告訴你能夠去哪裏尋找更多內容。

在下面的內容裏, 咱們假設在 Bloom filter 裏面有 k 個哈希函數, m 個比特, 以及 n 個已插入元素。

Bloom filter 應該設計爲多大?

Bloom filter 的一個優良特性就是能夠修改過濾器的錯誤率。一個大的過濾器會擁有比一個小的過濾器更低的錯誤率。

錯誤率會近似於 (1-e-kn/m)k, 因此你只須要先肯定可能插入的數據集的容量大小 n, 而後再調整 km 來爲你的應用配置過濾器。

而這帶來了一個顯而易見的問題:

應該使用多少個哈希函數?

Bloom filter 使用的哈希函數越多運行速度就會越慢。可是若是哈希函數過少,又會遇到誤判率高的問題。因此這個問題上須要認真考慮。

在建立一個 Bloom filter 的時候須要肯定 k 的值,也就是說你須要提早圈定 n 的變更範圍。而一旦你這樣作了,你依然須要肯定 m(總比特數)和 k (哈希函數的個數)的值。

彷佛這是一個十分困難的優化問題,但幸運的是,對於給定的 mn ,有一個函數能夠幫咱們肯定最優的 k 值: (m/n)ln(2)

因此能夠經過如下的步驟來肯定 Bloom filter 的大小:

  1. 肯定 n 的變更範圍
  2. 選定 m 的值
  3. 計算 k 的最優值
  4. 對於給定的n, m, and k計算錯誤率。若是這個錯誤率不能接收,那麼回到第二步,不然結束

Bloom filter 的時間複雜度和空間複雜度?

對於一個 mk 值肯定的 Bloom filter,插入和測試操做的時間複雜度都是 O(k)。這意味着每次你想要插入一個元素或者查詢一個元素是否在集合中,只須要使用 k 個哈希函數對這個元素求值,而後將對應的比特位標記或者檢查對應的比特位。

相比之下,Bloom filter 的空間複雜度更難以概述,它取決於你能夠忍受的錯誤率。同時也取決於輸入元素的範圍,若是這個範圍是有限的,那麼一個肯定的比特向量就能夠很好的解決問題。若是你甚至不能很好的估計輸入元素的範圍,那麼你最好選擇一個哈希表或者一個可拓展的 Bloom filter。

能夠用 Bloom filter 來作什麼?

我會將你引向 wiki而不是將它們的內容拷貝過來。 C. Titus Brown 的演講很好的闡述了 Bloom filter 在生物信息學中的應用。

 

總結

總結條毛啊!

相關文章
相關標籤/搜索