1. 程式人生 > >大資料演算法——布隆過濾器

大資料演算法——布隆過濾器

本文始發於個人公眾號:TechFlow,原創不易,求個關注


今天的文章和大家一起來學習大資料領域一個經常用到的演算法——布隆過濾器。如果看過《數學之美》的同學對它應該並不陌生,它經常用在集合的判斷上,在海量資料的場景當中用來快速地判斷某個元素在不在一個龐大的集合當中。它的原理不難,但是設計非常巧妙,老實講在看《數學之美》之前,我也沒有聽說過這個資料結構,所以這篇文章也是我自己學習的筆記。


原理


在我之前的理解當中,如果想要判斷某個元素在不在集合當中,經典的結構應該是平衡樹和hash table。但是無論是哪一種方法,都逃不開一點,都需要儲存原值。

比如在爬蟲場景當中,我們需要記錄下之前爬過的網站。我們要將之前的網址全部都儲存在容器裡,然後在遇到新網站的時候去判斷是否已經爬過了。在這個問題當中,我們並不關心之前爬過的網站有哪些,我們只關心現在的網站有沒有在之前出現過。也就是說之前出現過什麼不重要,現在的有沒有出現過才重要。

我們利用平衡樹或者是Trie或者是AC自動機等資料結構和演算法可以實現高效的查詢,但是都離不開儲存下所有的字串。想象一下,一個網址大概上百個字元,大約0.1KB,如果是一億個網址,就需要10GB了,如果是一百億一千億呢?顯然這麼大的規模就很麻煩了,今天要介紹的布隆過濾器就可以解決這個問題,而且不需要儲存下原值,這是一個非常巧妙的做法,讓我們一起來看下它的原理。

布隆過濾器本身的結構非常簡單,就是一個一維的bool型的陣列,也就是說每一位只有0或者1,是一個bit,這個陣列的長度是m。對於每個新增的項,我們使用K種不同的hash演算法對它計算hash值。所以我們可以得到K個hash值,我們用hash值對m取模,假設是x。剛開始的時候陣列內全部都是0,我們把所有x對應的位置標記為1。

舉個例子,假設我們一開始m是10,K是3。我們遇到第一個插入的值是”線性代數“,我們對它hash之後得到1,3,5,那麼我們將對應的位置標記成1.

然後我們又遇到了一個值是”高等數學“,hash之後得到1,8,9,我們還是將對應位置賦值成1,會發現1這個位置對應的值已經是1了,我們忽略就好。

如果這個時候我們想要判斷”概率統計”有沒有出現過,怎麼辦?很簡單,我們對“概率統計”再計算hash值。假設得到1,4,5,我們去遍歷一下對應的位置,發現4這個位置是0,說明之前沒有新增過“概率統計”,顯然“概率統計”沒有出現過。

但是如果“概率統計”hash之後的結果是1,3,8呢?我們判斷它出現過就錯了,答案很簡單,因為雖然1,3,8這個hash組合之前沒有出現過,但是對應的位置都在其他元素中出現過了,這樣就出現誤差了。所以我們可以知道,布隆過濾器對於不存在的判斷是準確的,但是對於存在的判斷是有可能有錯誤的。


程式碼


布隆過濾器的原理很簡單,明白了之後,我們很容易寫出程式碼:

# 插入元素
def BloomFilter(filter, value, hash_functions):
    m = len(filter)
    for func in hash_functions:
        idx = func(value) % m
        filter[idx] = True
    return filter
    
# 判斷元素
def MemberInFilter(filter, value, hash_functions):
    m = len(filter)
    for func in hash_functions:
        idx = func(value) % m
        if not filter[idx]:
            return False
    return True


錯誤率計算


之前的例子當中應該展示得很明白了,布隆過濾器雖然好用,但是會存在bad case,也就是判斷錯誤的情況。那麼,這種錯誤判斷髮生的概率有多大呢?

這個概率的計算也不難:由於陣列長度是\(m\),所以插入一個bit它被置為1的概率是\(\frac{1}{m}\),插入一個元素需要插入k個hash值,所以插入一個元素,某一位沒有被置為1的概率是\((1-\frac{1}{m})^k\)。插入n個元素之後,某一位依舊為0的概率是\((1-\frac{1}{m})^{nk}\),它變成1的概率是\(1-(1-\frac{1}{m})^{nk}\)。

如果在某次判斷當中,有一個沒有出現過的元素被認為已經在集合當中了,那麼也就是說它hash得到的位置均已經在之前被置為1了,這個時間發生的概率為:

\[\displaystyle\left[1-(1-\frac{1}{m})^{nk}\right]^k \approx (1-e^{-\frac{kn}{m}})^k\]

這裡用到了一個極限:

\[\displaystyle\lim_{x \to -\infty}(1-\frac{1}{x})^{-x}=e\]

我們來求一下衝突率最低時k的取值,為了方便計算,我們令\(b=e^{\frac{n}{m}}\),代入:

\[f(k) = (1-b^{-k})^k \\ \ln f(k) = k\ln(1-b^{-k})\]
兩邊求導:

\[ \begin{aligned} \frac{1}{f(k)}f'(k)&= ln(1-b^{-k}) + \frac{kb^{-k}\ln b}{1-b^{-k}} \end{aligned} \]

我們令導數等於0,來求它的極值:

\[ \begin{aligned} \ln(1-b^{-k})(1-b^{-k})&=-kb^{-k}\ln b\\ \ln(1-b^{-k})(1-b^{-k})&=b^{-k}\ln b^{-k}\\ 1-b^{-k} &=b^{-k}\\ b^{-k} &= \frac{1}{2} \end{aligned} \]

我們將\(b^{-k}=\frac{1}{2}\)代入,可以求出最值時的\(k=\ln2\cdot\frac{m}{n} \approx 0.7\frac{m}{n}\)

同理,我們也可以預設定集合元素n和錯判率p,來求解對應的n,同樣利用上面的公式推算,可以得到\(m=-\frac{n\ln p}{(\ln2)^2}\)

如果我們允許一定的容錯,並且能夠大概估計會出現的元素的個數,那麼完全可以使用布隆過濾器來代替傳統的容器判重的方法。這樣不僅效率極高,而且對於儲存的要求非常小。


靈魂拷問


原理也明白了,程式碼也看懂了,這個時候我們來思考一個問題:布隆過濾器可以刪除元素嗎?

很遺憾,布隆過濾器是不支援刪除的。

因為布隆過濾器的每一個bit並不是獨佔的,很有可能多個元素共享了某一位。如果我們直接刪除這一位的話,會影響其他的元素。

還是用上面的例子舉例:我們刪除線性代數,線性代數對應的位置是1,3,5,雖然我們並沒有刪除高等數學,但是由於我們移除了高等數學也用到的位置1,如果我們再去判斷高等數學是否存在就會得到錯誤的結果,雖然我們並沒有刪除它。

當然,在一些必須要有刪除功能的場景下,也是有辦法的。方法也很簡單,就是修改資料結構,將原本每一位一個bit改成一個int,當我們插入元素的時候,不再是將bit設定為true,而是讓對應的位置自增,而刪除的時候則是對應的位減一。這樣,我們刪除單個結果就不會影響其他元素了。

這種方法並不是完美的,由於布隆過濾器存在誤判的情況,很有可能我們會刪除原本就不存在的值,這同樣會對其他元素產生影響。

布隆過濾器是一個優缺點都非常明顯的資料結構,優點非常出色:速度足夠快,記憶體消耗小,程式碼實現簡單。但是缺點也很明顯:不支援刪除元素,會有誤判的情況。這樣特點鮮明的資料結構真的非常吸引人。

今天的文章就是這些,如果覺得有所收穫,請順手點個關注吧,你們的舉手之勞對我來說很重要。

相關推薦

資料演算法——過濾器

本文始發於個人公眾號:TechFlow,原創不易,求個關注 今天的文章和大家一起來學習大資料領域一個經常用到的演算法——布隆過濾器。如果看過《數學之美》的同學對它應該並不陌生,它經常用在集合的判斷上,在海量資料的場景當中用來快速地判斷某個元素在不在一個龐大的集合當中。它的原理不難,但是設計非常巧妙,老實講在

大量資料去重:Bitmap點陣圖演算法過濾器(Bloom Filter)

Bitmap演算法 與其說是演算法,不如說是一種緊湊的資料儲存結構。是用記憶體中連續的二進位制位(bit),用於對大量整型資料做去重和查詢。其實如果並非如此大量的資料,有很多排重方案可以使用,典型的就是雜湊表。 實際上,雜湊表為每一個可能出現的數字提供了一個一一對映的關係,每個元素都相當於有

[原創]資料:過濾器C#版簡單實現。

public class BloomFilter { public BitArray _BloomArray; public Int64 BloomArryLength { get; } public Int64 DataArray

資料排重演算法-演算法(BloomFilter)

前續:網頁上已經有很多布隆過濾器很全的資料了,由於博主最近在做網頁爬蟲,遇到url防重問題,所以認真分析了布隆濾波器原理,也參考了相關博文。旨在給出不同人對其不同的理解,好給大家更全面的參考。 BloomFilter演算法,是一種大資料排重演算法。在一個數據量

過濾器,你也可以處理十幾億的資料

>文章收錄在 GitHub [JavaKeeper](https://github.com/Jstarfish/JavaKeeper) ,N線網際網路開發必備技能兵器譜 ## 什麼是 BloomFilter **布隆過濾器**(英語:Bloom Filter)是 1970 年由布隆提出的。它實際上是

資料結構--雜湊擴充套件 ( 過濾器 )

布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實際上是一個很長的二進位制向量和一系列隨機對映函式。布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的演算法,缺點是有一定的誤識別率和刪除困難。 基本概念 : 如果想

過濾器(Bloom Filter)(給兩個檔案,分別有100億個字串,我們只要1g的記憶體,如何找到兩個檔案的交集?分別給出精確演算法和近似演算法?)

  給兩個檔案,分別有100億個字串,我們只要1g的記憶體,如何找到兩個檔案的交集?分別給出精確演算法和近似演算法? 精確演算法:   我們可以建立1000個檔案,運用雜湊函式先將檔案1的字串儲存在對應的檔案中,之後再檔案2中取元素,通過雜湊函式計算出雜湊地址

過濾器和海量資料面試題

雜湊切割topK問題 給一個超過100G大小的logfile,log中存著ip地址,設計演算法找到出現次數最多的ip地址,與上題條件相同,如何找到topK的ip?如何直接用Linux系統命令實現? (1)topK的ip 思路:使用堆 (2)尋找次數最多 思路:分割成

大白話 強大的過濾器演算法-極大降低儲存空間

     “寧可錯殺三千,絕不放過一個”,這是布隆過濾器的失誤型別金句。 1、什麼是布隆過濾器        瞭解熟悉布隆過濾器,先從瞭解hash函式開始。最簡單說,一個數據經過hash函式計算後,會得到另一個輸出值。hash函式能給你的保證就是,相同的輸入值,經過計算後

資料結構】點陣圖BitMap與過濾器BloomFilter

  首先先看一下下面這個騰訊的面試題:給40億個不重複的無符號整數,沒排過序。給一個無符號整數,如何快速判斷一個數是否在這40億個數中。 【騰訊】思路一:  最容易想到的解法就是遍歷所有的40多億個整數,然後一個一個判斷。但是這個需要花費的記憶體是多大呢?  大家可以去算一下

資料結構】過濾器——點陣圖擴充套件

本篇博文,旨在介紹一種可以快速檢索元素是否存在的資料結構 --- 布隆過濾器;本文從點陣圖和布隆過濾器的對比,討論了使用這兩種資料結構的不同情況;並介紹了布隆過濾器的幾種主要使用場景 布隆過濾器的引入 之前學習了點陣圖,可以快速的判斷一個整數是否存在於一個集合中 然而,現

過濾器(海量資料找重複)

1. 布隆過濾器 它實際上是一個很長的二進位制向量和一系列隨機對映函式。布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都比一般的演算法要好的多,缺點是有一定的誤識別率和刪除困難 布隆過濾器是與雜湊演算法是相關的,是工業實踐上常用的演算法,之前我們使用HashMa

演算法過濾器

應用場景: 網頁黑名單系統; 垃圾郵件過濾系統; 爬蟲的網址判斷重複系統; 容忍一定程度的失誤率; 對空間要求較嚴格; 概念: 布隆過濾器可以精確的代表一個集合,可以精確判斷某一元素是否在此集合裡。 精確程度由使用者的具體設計決定,做到100%的精確是不可能的。其

[算法系列之十]資料量處理利器:過濾器

【引言】 在日常生活中,包括在設計計算機軟體時,我們經常要判斷一個元素是否在一個集合中。比如在字處理軟體中,需要檢查一個英語單詞是否拼寫正確(也就是要判斷 它是否在已知的字典中);在 FBI,一個嫌疑人的名字是否已經在嫌疑名單上;在網路爬蟲裡,一個網址是否被訪問過等等。最直

過濾器Bloom Filter演算法的Java實現(用於去重)

在日常生活中,包括在設計計算機軟體時,我們經常要判斷一個元素是否在一個 集合中。比如在字處理軟體中,需要檢查一個英語單詞是否拼寫正確(也就是要判斷它是否在已知的字典中);在 FBI,一個嫌疑人的名字是否已經在嫌疑名單上;在網路爬蟲裡,一個網址是否被訪問過等等。最直接的方法就

刁肥宅資料結構課設“過濾器的實踐與應用”原始碼(v1.0,永不上交)

       程式碼很簡單,寫了一些註釋;加上註釋看就很清楚了。        檔案bloomfilter.cpp: #include "bloomfilter.h" // return a hash range from 0 to 79999 int hash(con

點陣圖&過濾器&雜湊表的應用——海量資料處理

1. 給定一個大小超過 100G 的檔案, 其中存著 IP 地址, 找到其中出現次數最多的 IP 地址 100G遠遠大於記憶體的大小,因此不能一次全部讀入到記憶體中進行統計。 進行雜湊切分,一般的記憶體是4G,但肯定不能一下子把4G填滿,記憶體還要放其他的東

過濾器、一致性雜湊演算法總結

認識布隆過濾器 不安全網頁的黑名單包含 100 億個黑名單網頁,每個網頁的 URL 最多佔用 64B。 現在想要實現一種網頁過濾系統,可以根據網頁的 URL 判斷該網頁是否在黑名單上,請設計該系統。 1.該系統允許有萬分之一以下的判斷失誤率。 2.使用的額外空間不要超過 3

大量資料去重:Bitmap和過濾器(Bloom Filter)

5TB的硬碟上放滿了資料,請寫一個演算法將這些資料進行排重。如果這些資料是一些32bit大小的資料該如何解決?如果是64bit的呢?在面試時遇到的問題,問題的解決方案十分典型,但對於海量資料處理接觸少的同學可能一時也想不到什麼好方案。介紹兩個演算法,對於空間的利用到達了一種極

演算法(3)---過濾器原理

演算法(3)---布隆過濾器原理 開發一個電商專案,因為資料量一直在增加(已達億級),所以需要重構之前開發好的秒殺功能,為了更好的支援高併發,在驗證使用者是否重複購買的環節,就考慮用布隆過濾器。 也順便更加深入的去了解下布隆過濾器的原理,感覺還是蠻有意思的,這一連串的公式不靜下心來思考,很容易被繞暈。 一、