若是面試官問你,一個網站有 100 億 url 存在一個黑名單中,每條 url 平均 64 字節。問這個黑名單要怎麼存?若此時隨便輸入一個 url,如何判斷該 url 是否在這個黑名單中?面試
對於第一個問題,若是把黑名單當作一個集合,將其存在 hashmap 中,貌似太大了,須要 640G,明顯不科學。算法
那該怎麼辦?ok,如今該介紹今天的主角了 —— 布隆過濾器就能夠解決這樣的問題。數組
首先,布隆過濾器是什麼?維基百科是這樣解釋的:微信
布隆過濾器(英語:Bloom Filter)是1970年由布隆提出的。它其實是一個很長的二進制矢量和一系列隨機映射函數。布隆過濾器能夠用於檢索一個元素是否在一個集合中。它的優勢是空間效率和查詢時間都遠遠超過通常的算法,缺點是有必定的誤識別率和刪除困難。函數
官方說法看下就好,若是不理解不要緊,其實不會難,下面咱們講人話慢慢來。網站
布隆過濾器其實是一個很長的二進制矢量和一系列隨機映射函數。url
「很長的二進制矢量」:這是一個長度很長的數組,什麼類型的數組呢?bit 類型的數組,也是咱們說的「位」,(1Byte = 8bit,1KB = 1024Byte)。spa
「一系列隨機映射函數」:有多個哈希函數。那什麼是哈希函數呢?JDK 裏面有計算獲得哈希值的方法,那就是一個哈希函數。.net
布隆過濾器能夠用於檢索一個元素是否在一個集合中。它的優勢是空間效率和查詢時間都遠遠超過通常的算法,缺點是有必定的誤識別率和刪除困難code
這個不就能夠解決咱們最開始的問題嗎?那它是怎麼解決的呢?
下面我說下大致的過程,細節部分可先不理解,重要的是明白流程,細節我後面補充。
假設,bit 類型數組的長度爲 m,每一個元素值爲 0,有 k 個哈希函數。
首先,當輸入一個 url 的時候,此時這個 url 會通過 k 個哈希函數處理,獲得多個哈希值(v1,v2,...,vk)。以後獲得這些哈希值對應在數組的下標位置,最後將這些下標的元素都置爲 1。
那麼如何判斷一個 url 在黑名單裏面呢?輸入一條 url,它通過上述處理以後,會獲得多個數組的下標位置。若是這些下標的元素值都已經爲 1 了,說明該在黑名單裏面,不然不在。
整體就是這樣的流程,下面說下你們可能存在的疑問:
一、bit 類型的數組如何構建
二、獲得 v1,v2,...,vk 這些哈希值後,如何獲得其在數組的下標位置,並將其設置爲 1 呢?
兩個問題我一塊兒說下,Java 裏面沒有 bit 這樣的類型,怎麼構建呢?—— 不難,咱們可使用 int,一個 int 是 32 位。
//建立了一個 100 * 32bit 的數組
int[] arr = new int[100];
// 表明 bit 數組 0-31 位的元素
arr[0];
複製代碼
所以上面再會說「分別將這些哈希值除以數組的長度 m,和對 m 取模,獲得這些哈希值對應在數組的下標位置」。
具體咱們能夠拿一個哈希值 data 來舉個栗子,假設 int 數組長度爲 100。
void Set(int data) {
// ByteNO 是表示在 table 數組中那個元素
int ByteNo = data / 32;
// bitNo 是表示在 32 位 bit 中哪一個 bit 位。
int BitNo = data % 32;
// 置 1
_table[ByteNo] |= (1 << BitNo);
}
複製代碼
最開始咱們提到,若是將 100 億 url 放到 HashMap 中須要 640GB,那麼使用布隆過濾器後又須要多少空間呢?答案是約等於 23 GB。相比之下,這個空間大小是否是就能夠接受不少了。
布隆過濾器有寧肯錯殺一百,也不能放過一個的性質。講人話就是屬於黑名單的 url 必定可以正確判斷它在黑名單中,但不屬於黑名單中的 url 也可能會被認爲在黑名單中,存在必定的失誤率。
至於失誤率要保持在多少,數組長度,哈希函數的個數分別要設置多少就須要根據實際狀況來選擇了,網上有對應的數學公式計算,這裏就不展開講了。
參考: blog.csdn.net/wenqiang120…
PS:本文原創發佈於微信公衆號「不僅Java」,後臺回覆「Java」,送你 13 本 Java 經典電子書。公衆號專一分享 Java 乾貨、讀書筆記、成長思考。