1.適用場景
在極大的數據集合中快速查找某個元素是否存在,但是不要求100%正確.這個是文縐縐的說法,說人話: 一個很理想的場景:分佈式緩存
緩存的數據可能很大,QPS也相當的高,比如千萬級,那麼一般這個緩存集羣就會達到近百臺機器的規模.能不能少點機器呢? 畢竟找老闆要這麼多機器,不容易啊,動不動就是KPI導向!
這個時候Bloom Filter就可以上場了
2.橫向對比
爲了查找某元素是否出現,一般有哪些方法呢?
- 將所有的數據存起來(比如存數據庫),然後直接查詢唄: 第一是存不下,第二是找不快
- 使用Hash結構存儲:更加存不下,一般hash空間利用率<=50%, 數據量大了,Hash碰撞也不容小覷
- 將原始數據md5或者SHA-1,再存hash:MD5結果128Bit, SHA-1結果160Bit,確實比上面的靠譜多了
- 位向量(將數據哈希值對應的bit位置1):可查證數據顯示,要降低衝突發生的概率到1%,就要將BitSet的長度設置爲數據總數量的100倍
以上方法都是能百分百準確找到或者找不到元素,空間上多少不盡如人意,但是能百分百準確!可是作爲一個緩存服務器,百分百的準確性,有必要麼? 爲了百分百的準確,多花了多少存儲啊!緩存命不中,又不懷孕,是吧? 如果降低5%的準確率,能省20%甚至40%的機器呢?是不是更划算!
3.Bloom Filter原理
布隆過濾器首先是基於上面的方法4,位向量,判斷數據的哈希值對應的bit是否爲1
改進點在於,使用多個哈希函數,而不是一個
比如數據aaa
index1=func_hash_1(aaa)
index2=func_hash_2(aaa)
那麼同時判斷bitset[index1]
和bitset[index2]
是否同時爲1,就能大致
知道aaa是否存在.
判斷規則:
- 只要bitset[index1]活着bitset[index2]任意一個爲0,表示數據aaa不存在
- bitset[index1],bitset[index2]全部同時爲1,數據aaa
可能
存在
爲什麼所有的都是1了,只是可能存在呢?仔細想想,每個數據都會被映射到2個標誌位,可能剛好index1標誌位與bbb的其中一個碰撞(重疊),剛好index2標誌位與ccc的其中一個標誌位碰撞(重疊).
再直白一點A=func1(aaa)
,B=func2(aaa)
,C=func1(bbb)
,D=func2(bbb)
,AB是數據aaa產生的兩個標誌位,CD是數據bbb產生的兩個標誌位.然而很可能aaa
和bbb
原始數據都不存在,而是A=func2(ccc)
,B=func1(ddd)
,C=func2(eee)
,D=func1(fff)
,意思是ccc,ddd,eee,fff分別有一個標誌位與aaa,bbb碰撞(重疊),其實aaa,bbb壓根不存在
4.Counting Bloom Filter
上面已經舉例分析,布隆過濾器存在不準確性,可能誤報.誤報率是多少,有興趣額的可以查查,公式就不貼了.
此處另外一個問題,數據一旦寫入集合,就不能刪除,原因同上面:
ccc,eee,fff,ddd能碰撞虛構出aaa,bbb存在的假象; 那麼你刪除ccc,ddd,eee,fff時將ABCD標誌位置0,也就能虛構aaa,bbb不存在的假象,而此時aaa,bbb可能恰好又倒黴催的真實存在
Counting bloomfilter(CBF),這是一種基本Bloom Filter的變體,CBF將基本Bloom Filter每一個Bit改爲一個計數器,出現一個加1,刪除一個減1,此時就支持刪除數據了
5.數學細節
關於錯誤率估算
,最優的哈希函數個數
,位數組的大小
,這幾個值如何計算調優?鄙人數學不精,不推理公式了,有興趣的搜索一把,應有盡有