docker介紹
層巒疊崎一一布隆過濾器
布隆過濾器( Bloom Filter )在起到去重作用的同時,在空間上還能節省 90% 以上,只是稍微有那麼點不精確,也就是有一定的誤判概率。
怎樣理解布隆過濾器?
布隆過濾器理解為一個不怎麼精確的 set 結構,當你使用它的 contains 法判斷某個物件是否存在時,它可能會誤判。當布隆過濾器說某個值存在時,這個值可能不存在;當它說某個值不存在時, 那就肯定不存在。
使用場景:布隆過濾器能準確過濾掉那些使用者已經看過的內容, 那些使用者沒有看過的新內容,它也會過濾掉極小一部分(誤判) ,但是絕大多數新內容它都能準確識別。這樣就可以保證推薦給使用者的內容都是無重複的。
Redis 中的布隆過濾器
Redis從4.0開始提供了外掛功能,才有布隆過濾器
基本用法
bf.add
新增元素,bf.exists
查詢元素是否存在
一次新增多個,就需要用到 bf.madd
指令。一次查詢多個元素是否存在,就需要用到 bf.mexists
指令。
注意事項
使用者在使用之前一定要儘可能地精確估計元素數量,還需要加上一定的冗餘空間以避免實際元素可能會意外高出估計值很多。
布隆過濾器的 error_rate 越小,需要的儲存空間就越大,對於不需要過於精確的場合, error_rate 設定稍大一點也無傷大雅。比如在新聞客戶端的去重應用上,誤判率高一點只會讓小部分文章不能被合適的人看到。
布隆過濾器的原理
每個布隆過濾器對應到 Redis 的資料結構裡面就是一個大型的位陣列和幾個不一 樣的無偏 hash 函式,無偏就是能夠把元素的 hash 值算得比較均勻,讓元素被 hash 對映到位陣列中的位置比較隨機。
向布隆過濾器中新增 key 肘,會使用多個 hash 函式對 key 進行 hash ,算得一個 整數索引值,然後對位陣列長度進行取模運算得到一個位置,每個 hash 函式都會算得一個不同的位置。再把位陣列的這幾個位置都置為 1,就完成了 add 操作。
向布隆過濾器詢問 key 是否存在時,跟 add 一樣,也會把 hash 的幾個位置都算出來,看看位陣列中這幾個位置是否都為 1,只要有一個位為 0,那麼說明布隆過濾器中這個 key 不存在。如果這幾個位置都是 1,並不能
使用時不要讓實際元素數量遠大於初始化數量,當實際元素數量開始超出初始化數量時,應該對布隆過濾器進行重建,重新分配一個 size 更大的過濾器,再將所有的歷史元素批量 add 進去(這就要求我們在其他的儲存器中記錄所有的歷史元素)。
空間佔用估計
布隆過濾器有兩個引數,第一個是預計元素的數量 n,第二個是錯誤率 f。公式根據這兩個輸入得到兩個輸出,第一個輸出是位陣列的長度 l,也就是需要的儲存空間大小( bit ),第二個輸出是 hash 函式的最佳數量 k。hash 函式的數量也會直接影響到錯誤率,最佳的數量會有最低的錯誤率。
k=0 . 7* (l/n) #約等於
f=0 . 6185 <( l/n ) #^表示次方計算,也就是 math.pow
結論
- 位陣列相對越長(l/n ),錯誤率 f 越低,這個和直觀上理解是一致的。
- 位陣列相對越長(l/n) , hash 函式需要的最佳數量也越多,影響計算效率
- 當一個元素平均需要 1 個位元組( 8bit )的指紋空間時(l/n=8 ),錯誤率大約為 2%
- 錯誤率為 10% 時,一個元素需要的平均指紋空間為 4.792 個bit,大約為 5bit
- 錯誤率為 1% 時,一個元素需要的平均指紋空間 9.585 bit ,大約為 I0bit
- 錯誤率為 0.1% 時, 一個元素需要的平均指紋空間為 14.377 bit,大約為 15bit
實際元素超出時, 誤判率會怎樣變化
引入引數t 表示實際元素和預計元素的倍數
f=(1-0.5t)k #極限近似,k是 hash 函式的最佳數量
結論
- 錯誤率為 10% 時,倍數比為 2 時,錯誤率就會升至接近 40% ,這個值就比較危險了。
- 錯誤率為 1% 時,倍數比為 2 時,錯誤率會升至 15% ,也挺可怕的。
- 錯誤率為 0.1% 時,倍數比為 2 時,錯誤率會升至 5% ,也是比較高的。