尚硅谷大數(shù)據(jù)技術(shù)之HBase第8章 擴(kuò)展
8.1布隆過濾器
在日常生活中,包括在設(shè)計(jì)計(jì)算機(jī)軟件時(shí),我們經(jīng)常要判斷一個(gè)元素是否在一個(gè)集合中。比如在字處理軟件中,需要檢查一個(gè)英語(yǔ)單詞是否拼寫正確(也就是要判斷它是否在已知的字典中);在 FBI,一個(gè)嫌疑人的名字是否已經(jīng)在嫌疑名單上;在網(wǎng)絡(luò)爬蟲里,一個(gè)網(wǎng)址是否被訪問過等等。最直接的方法就是將集合中全部的元素存在計(jì)算機(jī)中,遇到一個(gè)新元素時(shí),將它和集合中的元素直接比較即可。一般來講,計(jì)算機(jī)中的集合是用哈希表(hash table)來存儲(chǔ)的。它的好處是快速準(zhǔn)確,缺點(diǎn)是費(fèi)存儲(chǔ)空間。當(dāng)集合比較小時(shí),這個(gè)問題不顯著,但是當(dāng)集合巨大時(shí),哈希表存儲(chǔ)效率低的問題就顯現(xiàn)出來了。比如說,一個(gè)象 Yahoo,Hotmail 和 Gmai 那樣的公眾電子郵件(email)提供商,總是需要過濾來自發(fā)送垃圾郵件的人(spamer)的垃圾郵件。一個(gè)辦法就是記錄下那些發(fā)垃圾郵件的 email 地址。由于那些發(fā)送者不停地在注冊(cè)新的地址,全世界少說也有幾十億個(gè)發(fā)垃圾郵件的地址,將他們都存起來則需要大量的網(wǎng)絡(luò)服務(wù)器。如果用哈希表,每存儲(chǔ)一億個(gè) email 地址, 就需要 1.6GB 的內(nèi)存(用哈希表實(shí)現(xiàn)的具體辦法是將每一個(gè) email 地址對(duì)應(yīng)成一個(gè)八字節(jié)的信息指紋googlechinablog.com/2006/08/blog-post.html,然后將這些信息指紋存入哈希表,由于哈希表的存儲(chǔ)效率一般只有 50%,因此一個(gè) email 地址需要占用十六個(gè)字節(jié)。一億個(gè)地址大約要 1.6GB, 即十六億字節(jié)的內(nèi)存)。因此存貯幾十億個(gè)郵件地址可能需要上百 GB 的內(nèi)存。除非是超級(jí)計(jì)算機(jī),一般服務(wù)器是無法存儲(chǔ)的。
布隆過濾器只需要哈希表 1/8 到 1/4 的大小就能解決同樣的問題。
Bloom Filter是一種空間效率很高的隨機(jī)數(shù)據(jù)結(jié)構(gòu),它利用位數(shù)組很簡(jiǎn)潔地表示一個(gè)集合,并能判斷一個(gè)元素是否屬于這個(gè)集合。Bloom Filter的這種高效是有一定代價(jià)的:在判斷一個(gè)元素是否屬于某個(gè)集合時(shí),有可能會(huì)把不屬于這個(gè)集合的元素誤認(rèn)為屬于這個(gè)集合(false positive)。因此,Bloom Filter不適合那些“零錯(cuò)誤”的應(yīng)用場(chǎng)合。而在能容忍低錯(cuò)誤率的應(yīng)用場(chǎng)合下,Bloom Filter通過極少的錯(cuò)誤換取了存儲(chǔ)空間的極大節(jié)省。
下面我們具體來看Bloom Filter是如何用位數(shù)組表示集合的。初始狀態(tài)時(shí),Bloom Filter是一個(gè)包含m位的位數(shù)組,每一位都置為0。
為了表達(dá)S={x1, x2,…,xn}這樣一個(gè)n個(gè)元素的集合,Bloom Filter使用k個(gè)相互獨(dú)立的哈希函數(shù)(Hash Function),它們分別將集合中的每個(gè)元素映射到{1,…,m}的范圍中。對(duì)任意一個(gè)元素x,第i個(gè)哈希函數(shù)映射的位置hi(x)就會(huì)被置為1(1≤i≤k)。注意,如果一個(gè)位置多次被置為1,那么只有第一次會(huì)起作用,后面幾次將沒有任何效果。在下圖中,k=3,且有兩個(gè)哈希函數(shù)選中同一個(gè)位置(從左邊數(shù)第五位)。
在判斷y是否屬于這個(gè)集合時(shí),我們對(duì)y應(yīng)用k次哈希函數(shù),如果所有hi(y)的位置都是1(1≤i≤k),那么我們就認(rèn)為y是集合中的元素,否則就認(rèn)為y不是集合中的元素。下圖中y1就不是集合中的元素。y2或者屬于這個(gè)集合,或者剛好是一個(gè)false positive。
- 為了add一個(gè)元素,用k個(gè)hash function將它hash得到bloom filter中k個(gè)bit位,將這k個(gè)bit位置1。
- 為了query一個(gè)元素,即判斷它是否在集合中,用k個(gè)hash function將它hash得到k個(gè)bit位。若這k bits全為1,則此元素在集合中;若其中任一位不為1,則此元素比不在集合中(因?yàn)槿绻冢瑒t在add時(shí)已經(jīng)把對(duì)應(yīng)的k個(gè)bits位置為1)。
- 不允許remove元素,因?yàn)槟菢拥脑挄?huì)把相應(yīng)的k個(gè)bits位置為0,而其中很有可能有其他元素對(duì)應(yīng)的位。因此remove會(huì)引入false negative,這是絕對(duì)不被允許的。
布隆過濾器決不會(huì)漏掉任何一個(gè)在黑名單中的可疑地址。但是,它有一條不足之處,也就是它有極小的可能將一個(gè)不在黑名單中的電子郵件地址判定為在黑名單中,因?yàn)橛锌赡苣硞€(gè)好的郵件地址正巧對(duì)應(yīng)個(gè)八個(gè)都被設(shè)置成一的二進(jìn)制位。好在這種可能性很小,我們把它稱為誤識(shí)概率。
布隆過濾器的好處在于快速,省空間,但是有一定的誤識(shí)別率,常見的補(bǔ)救辦法是在建立一個(gè)小的白名單,存儲(chǔ)那些可能別誤判的郵件地址。
布隆過濾器具體算法高級(jí)內(nèi)容,如錯(cuò)誤率估計(jì),最優(yōu)哈希函數(shù)個(gè)數(shù)計(jì)算,位數(shù)組大小計(jì)算,請(qǐng)參見http://blog.csdn.net/jiaomeng/article/details/1495500。