拜託,面試官別問我「布隆」了

程式設計師吳師兄發表於2019-03-23

拜託,面試官別問我「布隆」了

題目描述

一個網站有 100 億 url 存在一個黑名單中,每條 url 平均 64 位元組。這個黑名單要怎麼存?若此時隨便輸入一個 url,你如何快速判斷該 url 是否在這個黑名單中

題目解析

這是一道經常在面試中出現的演算法題。憑藉著題目極其容易描述,電面的時候也出現過。

不考慮細節的話,此題就是一個簡單的查詢問題。對於查詢問題而言,使用雜湊表來處理往往是一種效率比較高的方案。

但是,如果你在面試中回答使用雜湊表,接下來面試官肯定會問你:然後呢?如果你不能回答個所以然,面試官就會面無表情的通知你:今天的面試到此結束,我們會在一週內給你答覆。

為什麼不能用雜湊表

100 億是一個很大的數量級,這裡每條 url 平均 64 位元組,全部儲存的話需要 640G 的記憶體空間。又因為使用了雜湊表這種資料結構,而雜湊表是會出現雜湊衝突的。為了讓雜湊表維持較小的裝載因子,避免出現過多的雜湊衝突,需要使用連結串列法來處理,這裡就要儲存連結串列指標。因此最後的記憶體空間可能超過 1000G 了。

只是儲存個 url 就需要 1000G 的空間,老闆肯定不能忍!

點陣圖(BitMap)

這個時候就需要擴充一下思路。首先,先來考慮一個類似但更簡單的問題:現在有一個非常龐大的資料,比如有 1 千萬個整數,並且整數的範圍在 1 到 1 億之間。那麼如何快速查詢某個整數是否在這 1 千萬個整數中呢?

需要判斷該數是否存在,也就是說這個數存在兩種狀態:存在( True )或者不存在(False)。

因此這裡可以使用一個儲存了狀態的陣列來處理。這個陣列特點是大小為 1 億,並且資料型別為布林型別( True 或者 False )。然後將這 1 千萬個整數作為陣列下標,將對應的陣列值設定成 True,比如,整數 233 對應下標為 233 的陣列值設定為 True,也就是 array[ 233 ] = True。

這種操作就是點陣圖法:就是用每一位來存放某種狀態,適用於大規模資料,但資料狀態又不是很多的情況。

另外,點陣圖法有一個優勢就是空間不隨集合內元素個數的增加而增加。它的儲存空間計算方式是找到所有元素裡面最大的元素(假設為 N ),因此所佔空間為:

計算公式

因此,當 N 為 1 億的時候需要 12MB 的儲存空間。當 N 為 10 億的時候需要 120MB 的儲存空間了。也就是說:點陣圖法的所佔空間隨集合內最大元素的增大而增大。這就會帶來一個問題,如果查詢的元素數量少但其中某個元素的值很大,比如數字範圍是 1 到 1000 億,那消耗的空間不容樂觀。

因此,出於效能和記憶體佔用的考慮,在這裡使用布隆過濾器才是最好的解決方案:布隆過濾器是對點陣圖的一種改進。

布隆過濾器

布隆過濾器(英語:Bloom Filter)是 1970 年由 Burton Bloom 提出的。

它實際上是一個很長的二進位制向量和一系列隨機對映函式。
複製程式碼

可以用來判斷一個元素是否在一個集合中。它的優勢是隻需要佔用很小的記憶體空間以及有著高效的查詢效率。

對於布隆過濾器而言,它的本質是一個位陣列:位陣列就是陣列的每個元素都只佔用 1 bit ,並且每個元素只能是 0 或者 1。

布隆過濾器除了一個位陣列,還有 K 個雜湊函式。當一個元素加入布隆過濾器中的時候,會進行如下操作:

  • 使用 K 個雜湊函式對元素值進行 K 次計算,得到 K 個雜湊值。
  • 根據得到的雜湊值,在位陣列中把對應下標的值置為 1。

舉個例子,假設布隆過濾器有 3 個雜湊函式:f1, f2, f3 和一個位陣列 arr。現在要把 2333 插入布隆過濾器中:

  • 對值進行三次雜湊計算,得到三個值 n1, n2, n3。
  • 把位陣列中三個元素 arr[n1], arr[n2], arr[3] 都置為 1。

當要判斷一個值是否在布隆過濾器中,對元素進行三次雜湊計算,得到值之後判斷位陣列中的每個元素是否都為 1,如果值都為 1,那麼說明這個值在布隆過濾器中,如果存在一個值不為 1,說明該元素不在布隆過濾器中。

布隆

很明顯,陣列的容量即使再大,也是有限的。那麼隨著元素的增加,插入的元素就會越多,位陣列中被置為 1 的位置因此也越多,這就會造成一種情況:當一個不在布隆過濾器中的元素,經過同樣規則的雜湊計算之後,得到的值在位陣列中查詢,有可能這些位置因為之前其它元素的操作先被置為 1 了

所以,有可能一個不存在布隆過濾器中的會被誤判成在布隆過濾器中。這就是布隆過濾器的一個缺陷。但是,如果布隆過濾器判斷某個元素不在布隆過濾器中,那麼這個值就一定不在布隆過濾器中。總結就是:

  • 布隆過濾器說某個元素在,可能會被誤判
  • 布隆過濾器說某個元素不在,那麼一定不在

用英文說就是:False is always false. True is maybe true。

使用場景

布隆過濾器的最大的用處就是,能夠迅速判斷一個元素是否在一個集合中。因此它有如下三個使用場景:

  • 網頁爬蟲對 URL 的去重,避免爬取相同的 URL 地址
  • 進行垃圾郵件過濾:反垃圾郵件,從數十億個垃圾郵件列表中判斷某郵箱是否垃圾郵箱(同理,垃圾簡訊)
  • 有的黑客為了讓服務當機,他們會構建大量不存在於快取中的 key 向伺服器發起請求,在資料量足夠大的情況下,頻繁的資料庫查詢可能導致 DB 掛掉。布隆過濾器很好的解決了快取擊穿的問題。

更多內容

更多演算法面試內容敬請關注公眾號『五分鐘學演算法』~

拜託,面試官別問我「布隆」了

相關文章