Bloom Filter算法


集合數據結構一般都有這么一個方法:contains。其作用就是判斷給定的元素是否存在集合中,這是一個常用的方法。其最簡單的內部實現即遍歷集合內的元素,一個個的判斷是否與給定元素相等。為了更高效點我們甚至可以采用“更好的(好是相對的)”算法實現。比如如果該集合是已經排序的,那么我們用二分查找來實現contains肯定更好。但是,如果集合的數據量龐大到一定程度,大部分我們熟知的算法不再有什么用了。即使可以使用,但是機器內存也不允許。

而Bloom Filter就是這么一個空間利用率非常高的算法。我們先來看看這個算法的原理:

1 首先我們有一個長度為n的比特數組,開始的時候將這個比特數組里所有的元素都初始化為0

00000000000000000000

上面的比特數組n為20

2 然后選取k個哈希函數,這k個哈希函數產生的結果的值的范圍在0到n-1之間(對於上面的比特數組,即0到19) 。對每個要添加進集合的對象進行哈希運算,然后將哈希計算結果作為數組的索引,將索引位置的比特位設置為1(不管該比特位原先為0還是為1)。

比如我們選取三個哈希函數,對於對象A哈希值為0,5,7。那么比特數組就為:

10000101000000000000

對象B的值為2,8,13,那么添加B后的比特數組為:

10100101100001000000

對象C為0,4,7(對象C的第一個哈希函數的值與對象A的相同了,沒關系我們還是設置為1就可以了):

10101101100001000000

現在我們的Bloom Filter里已經有3個元素了。現在我們要判斷某元素X是否在該集合中。就相當於我們要實現一個contains方法。那么這個方法如何實現呢?

對元素X采用相同的三個哈希函數哈希,然后以這三個哈希值為索引去比特數組里找。如果三個索引位置的比特位都為1我們就認為該元素在集合中,否則不是。

我們可以用偽代碼簡單的描述一下這個算法:

public  class BloomFilter{
     private bit[] bitSet =  new bit[N];

     public  void add(Object element){
       int[] hashValues = getHashValues(element);
       for( int i : hashValues){
         bitSet[i] =  1;
      }
    }

     public boolean contains(Object element){
         int[] hashValues = getHashValues(element);
         for( int i : hashValues){
            if(bitSet[i] !=  1return  false;
        }
         return  true;
    }

 

}

算法還是挺直觀的,對不。想想,一個很大的對象,經過一哈希,然后就變成了Bloom Filter里面的一個比特,這個空間利用效率是多么高啊。如果哈希函數的實現效率也很高的話那么不僅空間利用率高,時間復雜度也低啊。這真是一個神奇的算法對吧。

可能你想,以后我就把我們那個啥數組的contains方法替換成Bloom Filter的實現吧。

不過你仔細驗證過這個算法沒,它存在一些問題。這個算法有以下這么幾個特征:

1 如果該元素真的在集合中,那么Bloom Filter的contains方法肯定會返回true,這就是Bloom Filter不會漏報的特性。

2 如果該元素不在集合中,但Bloom Filter的contains方法有可能返回true。因為不同的元素經過哈希之后哈希值可能發生碰撞。這是Bloom Filter有可能誤報的特性。但是這個誤報的幾率並不高。

根據這兩個特性Bloom Filter在大量數據時還是挺有用的。比如假設我們有一個緩存服務器集群,集群里的不同的服務器承擔的緩存也不盡相同。如果一個用戶請求過來了,我們如何能快速的判斷出用戶請求的這個url在集群里哪台服務器上呢?因為每台服務器上緩存的url對應的頁面非常龐大,我們全部弄到內存里代價也很高。我們就可以在每台服務器上放一個Bloom Filter,里面添加的都是本服務器上有緩存的那些url。這樣即使Bloom Filter誤報了,那就是把一個url發到了一個並不持有該url對應的緩存的服務器上,結果就是緩存未命中,緩存服務器只需要將該url打到后端的上游服務器就好了。

根據Bloom Filter的特征我們可以看到不是所有的場景都可以用的,只有在一些能容許少量的誤報的情況下使用才行。該算法用很低的誤報率卻換來了大量的存儲空間,實在是是一個很巧妙的算法。 

 Bloom Filter算法:http://en.wikipedia.org/wiki/Bloom_filter

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM