應用場景
-
數據庫防止穿庫。 Google Bigtable,HBase 和 Cassandra 以及 Postgresql 使用BloomFilter來減少不存在的行或列的磁盤查找。避免代價高昂的磁盤查找會大大提高數據庫查詢操作的性能。
-
業務場景中判斷用戶是否閱讀過某視頻或文章,比如抖音或頭條,當然會導致一定的誤判,但不會讓用戶看到重複的內容。還有之前自己遇到的一個比賽類的社交場景中,需要判斷用戶是否在比賽中,如果在則需要更新比賽內容,也可以使用布隆過濾器,可以減少不在的用戶查詢db或緩存的次數。
-
緩存宕機、緩存擊穿場景,一般判斷用戶是否在緩存中,如果在則直接返回結果,不在則查詢db,如果來一波冷數據,會導致緩存大量擊穿,造成雪崩效應,這時候可以用布隆過濾器當緩存的索引,只有在布隆過濾器中,纔去查詢緩存,如果沒查詢到,則穿透到db。如果不在布隆器中,則直接返回。
-
WEB攔截器,如果相同請求則攔截,防止重複被攻擊。用戶第一次請求,將請求參數放入布隆過濾器中,當第二次請求時,先判斷請求參數是否被布隆過濾器命中。可以提高緩存命中率。
原理
布隆過濾器,英文叫BloomFilter,可以說是一個二進制向量和一系列隨機映射函數實現。 可以用於檢索一個元素是否在一個集合中。
下面來看看布隆過濾器是如何判斷元素在一個集合中,如下圖:
有三個hash函數和一個位數組,oracle經過三個hash函數,得到第1、4、5位爲1,database同理得到2、5、10位1,這樣如果我們需要判斷oracle是否在此位數組中,則通過hash函數判斷位數組的1、4、5位是否均爲1,如果均爲1,則判斷oracle在此位數組中,database同理。這就是布隆過濾器判斷元素是否在集合中的原理。
想必聰明的讀者已經發現,如果bloom經過三個hash算法,需要判斷 1、5、10位是否爲1,恰好因爲位數組中添加oracle和database導致1、5、10爲1,則布隆過濾器會判斷bloom會判斷在集合中,這不是Bug嗎,導致誤判。但是可以保證的是,如果布隆過濾器判斷一個元素不在一個集合中,那這個元素一定不會再集合中。
是的,這個是布隆過濾器的缺點,有一點的誤識別率,但是布隆過濾器有2大優點,使得這個缺點在某些應用場景中是可以接受的,2大優點是空間效率和查詢時間都遠遠高於一般的算法。常規的數據結構set,也是經過被用於判斷一個元素是否在集合中,但如果有上百萬甚至更高的數據,set結構所佔的空間將是巨大的,布隆過濾器只需要上百萬個位即可,10多Kb即可。
總結,敲黑板:
布隆過濾器是用於判斷一個元素是否在集合中。通過一個位數組和N個hash函數實現。
- 優點:
- 空間效率高,所佔空間小。
- 查詢時間短。
- 缺點:
- 元素添加到集合中後,不能被刪除。
- 有一定的誤判率
- 布隆過濾器使用多個hash函數計算位圖多個不同位點,由於多個位點在內存中不連續,CPU尋址花銷較大
Bloom Filter會有幾比較關鍵的值,根據這個值你是大致可以算出放多少條數據然後它的誤傷率在多少時會佔用多少系統資源的。這個算法有一個網址: https://krisives.github.io/bloom-calculator/
布穀鳥過濾器
布穀鳥過濾器源於布穀鳥Hash算法,布穀鳥Hash表有兩張,分別兩個Hash函數,當有新的數據插入的時候,它會計算出這個數據在兩張表中對應的兩個位置,這個數據一定會被存在這兩個位置之一(表1或表2)。一旦發現其中一張表的位置被佔,就將改位置原來的數據踢出,被踢出的數據就去另一張表找對應的位置。通過不斷的踢出數據,最終所有數據都找到了自己的歸宿。但仍會有數據不斷的踢出,最終形成循環,總有一個數據一直沒辦法找到落腳的位置,這代表布穀Hash表走到了極限,需要將Hash算法優化或Hash表擴容。
布穀鳥過濾器只會存儲元素的指紋信息(幾個bit,類似於布隆過濾器),由於不是存儲了數據的全部信息,會有誤判的可能。
由於布穀鳥過濾器在踢出數據時,需要再次計算原數據在另一種表的Hash值,因此作者設計Hash算法時將兩個Hash函數變成了一個Hash函數,第一張表的備選位置是Hash(x),第二張表的備選位置是Hash(x)⊕hash(fingerprint(x)),即第一張表的位置與存儲的指紋的Hash值做異或運算。這樣可以直接用指紋的值 異或 原來位置的Hash值來計算出其另一張表的位置。
綜上,布穀鳥過濾器
- 優點:
- 訪問內存次數低
- Hash函數計算簡單
- 缺點:
- 內存空間不聯繫,CPU消耗大
- 容易出現裝填循環問題
- 刪除數據時,Hash衝突會引起誤刪