一文講明白布隆過濾器

布隆過濾器

百度百科:布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都比一般的算法要好的多,缺點是有一定的誤識別率和刪除困難。

沒有看明白的話,其實可以這麼來說。
郵箱大家都用過的吧,163/139/qq等等,都有一個共同的功能,過濾垃圾郵件。
這個實際上就是布隆過濾器最明顯的應用了。試想一下,一封郵件過來他是怎麼知道你是垃圾郵件的?
一般咱們想到的就是散列表了,方便存取,判斷一下在不在表中就可以了。
但是,郵箱地址何止成千上萬,因此搞那麼大的對應的散列表也不合適。
那他是咱們知道當前這個郵件地址是不是垃圾郵件呢?先賣個關子-.-

原理


 在向過濾器中添加元素時,一般會經過三個(更多)hash函數的計算,然後放到數組的對應位置上去。由於hash函數會發生哈希碰撞的情況,因此對函數的選用需要注意。

向布隆過濾器中添加 key 時,會使用多個 hash 函數對 key 進行 hash 算得一個整數索引值然後對位數組長度進行取模運算得到一個位置,每個 hash 函數都會算得一個不同的位置。再把位數組的這幾個位置都置爲 1 就完成了 add 操作。

向布隆過濾器詢問 key 是否存在時,跟 add 一樣,也會把 hash 的幾個位置都算出來,看看位數組中這幾個位置是否都爲 1,只要有一個位爲 0,那麼說明布隆過濾器中這個 key 不存在。如果都是 1,這並不能說明這個 key 就一定存在,只是極有可能存在,因爲這些位被置爲 1 可能是因爲其它的 key 存在所致。如果這個位數組比較稀疏,判斷正確的概率就會很大,如果這個位數組比較擁擠,判斷正確的概率就會降低。具體的概率計算公式比較複雜,感興趣可以閱讀擴展閱讀,非常燒腦,不建議讀者細看。


public class BloomFilterTest {
    public static void main(String[] args) {
        // 創建一千萬的Integer類型的,誤差爲0.01的布隆過濾器
        BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(),10000000,0.01);
        List<Integer> list = new ArrayList<>(10000000);
        Map<Integer,Integer> map = new HashMap<>(100000000);
        for(int i=0;i<10000000;i++) {
            filter.put(i);
            list.add(i);
            map.put(i,i);
        }
        // 比較效率
        long t1 = System.currentTimeMillis();
        System.out.println("bloom:"+filter.mightContain(18000000));
        long t2 = System.currentTimeMillis();
        System.out.println("list:"+list.contains(18000000));
        long t3 = System.currentTimeMillis();
        System.out.println("map:"+map.get(18000000));
        long t4 = System.currentTimeMillis();
        System.out.println("bloom:"+(t2-t1)+",\nlist:"+(t3-t2)+",\nmap:"+(t4-t3));
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章