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