布隆過濾器(Bloom Filter)是一種基於Hash的高效查詢資料結構,它能夠快速答覆“某個元素是否存在”的問題。布隆過濾器只能用於新增元素與查詢元素,不能夠用於刪除元素。
在布隆過濾器之前,使用的是基於Hash的快速查詢演算法。Hash可以將一個元素進行雜湊,然後根據雜湊值對映到陣列的某一個位置。並且根據Hash演算法的優劣,不同元素對映到相同位置的可能性不同。但是如果基於Hash的快速查詢演算法的陣列大小被限制在一定的範圍內,那麼發生雜湊衝突的概率將會變大。並且陣列範圍越小,衝突概率將越大。因此布隆過濾器採用了使用多個hash函式進行運算來提高空間利用率。
Bloom過濾器原理
布隆過濾器是由一個可變長度為N的二進位制陣列與一組數量可變M的雜湊函式構成。其中,雜湊函式為確定性函式,所有雜湊函式的輸出值都在1~N之間,與二進位制陣列相對應。因此,每一個元素使用布隆過濾器的雜湊函式進行運算都將會得到相同的結果。
插入一個元素
假設我們需要插入一個元素到布隆過濾器中,我們需要使用不同的雜湊函式進行運算生成不同的雜湊值,並且根據生成的雜湊值將二進位制陣列對應的Bit
位置為1.例如插入字串"Bloom"
到過濾器中,使用三種雜湊函式進行計算所得到的雜湊值分別為1,3,7,那麼布隆過濾器的二進位制陣列則會變為:
假設我們插入第二個字串"Filter"
到過濾器中,同樣,我們使用相同的雜湊函式進行運算,假設雜湊值分別為2,4,7,那麼二進位制陣列則會變為:
因為在插入第一個字串時,雜湊值為7的Bit
位置已經被置為1,因此不需要更改,只需要將Bit
位為2,4置為1即可。
查詢元素
假設需要查詢某個元素是否存在,只需要使用相同的雜湊函式進行運算,然後與二進位制陣列進行Bit值匹配即可。比如,我們需要查詢字串"hash"
是否存在,使用之前的雜湊函式進行運算,假設輸出的雜湊值為4,5,7,由於Bit
位為5的位置仍然為0,所以對於字串"hash"
並不存在。
但是如果運算的雜湊值為2,3,7,我們也只能說該字串有可能存在。因為隨著儲存的陣列越多,將會有越多的Bit
位被置為1,即使某個字串沒有儲存,但是有可能該字串的雜湊值與其他被儲存的資料雜湊值重複,仍然可能誤判為該字串存在。
因此,對於查詢某個元素,只能判定某個元素一定不存在或者有可能存在,並不能判定某個元素一定存在。
選擇合適的陣列長度與雜湊函式數量
因此需要設定合適的陣列長度與雜湊函式數量。
- 陣列越短則更容易所有的位置被置為1,那麼可能查詢任何值都會被判斷可能存在,過濾的效率將大大降低。
- 陣列越長則會增加過濾效率,但是過長則會耗費大量空間。
雜湊函式數量也會影響過濾效率.
- 雜湊函式越多則二進位制位置1的次數越多,效率也會變低
- 但是數量過少的話誤判率將會變高。
可以通過以下公式計算合適的陣列長度與雜湊函式數量:
其中k
為雜湊函式個數,m
為布隆過濾器長度,n
為插入的元素個數,p
為誤報率。
Hash與布隆過濾器
實際上,無論是 Hash,還是布隆過濾器,基本思想是一致的,
- 都是基於內容的編址。
- Hash 函式存在衝突,布隆過濾器也存在衝突。
- 都可能誤報,但絕對不會漏報。
參考文獻: https://github.com/yeasy/blockchain_guide/blob/master/05_crypto/bloom_filter.md