BloomFilter布隆過濾器


BloomFilter 簡介

當一個元素被加入集合時,通過K個散列函數將這個元素映射成一個位數組中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了:如果這些點有任何一個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。

優點:相比於其它的數據結構,布隆過濾器在空間和時間方面都有巨大的優勢。布隆過濾器存儲空間和插入/查詢時間都是常數(O(k))。而且它不存儲元素本身,在某些對保密要求非常嚴格的場合有優勢。

缺點:一定的誤識別率和刪除困難。

 

要使用BloomFilter,需要引入guava包:

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>    

 測試分兩步:

1、往過濾器中放一百萬個數,然后去驗證這一百萬個數是否能通過過濾器

2、另外找一萬個數,去檢驗漏網之魚的數量

/**
 * 測試布隆過濾器(可用於redis緩存穿透)
 * 
 * @author xwj
 */
public class TestBloomFilter {

    private static int total = 1000000;
    private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), total);
//    private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), total, 0.001);

    public static void main(String[] args) {
        // 初始化1000000條數據到過濾器中
        for (int i = 0; i < total; i++) {
            bf.put(i);
        }

        // 匹配已在過濾器中的值,是否有匹配不上的
        for (int i = 0; i < total; i++) {
            if (!bf.mightContain(i)) {
                System.out.println("有壞人逃脫了~~~");
            }
        }

        // 匹配不在過濾器中的10000個值,有多少匹配出來
        int count = 0;
        for (int i = total; i < total + 10000; i++) {
            if (bf.mightContain(i)) {
                count++;
            }
        }
        System.out.println("誤傷的數量:" + count);
    }

}

運行結果:

運行結果表示,遍歷這一百萬個在過濾器中的數時,都被識別出來了。一萬個不在過濾器中的數,誤傷了320個,錯誤率是0.03左右。

看下BloomFilter的源碼:

   public static <T> BloomFilter<T> create(Funnel<? super T> funnel, int expectedInsertions) {
        return create(funnel, (long) expectedInsertions);
    }  

    public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) {
        return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions
    }

    public static <T> BloomFilter<T> create(
          Funnel<? super T> funnel, long expectedInsertions, double fpp) {
        return create(funnel, expectedInsertions, fpp, BloomFilterStrategies.MURMUR128_MITZ_64);
    }

static <T> BloomFilter<T> create(
      Funnel<? super T> funnel, long expectedInsertions, double fpp, Strategy strategy) {
......
}

BloomFilter一共四個create方法,不過最終都是走向第四個。看一下每個參數的含義:

   funnel:數據類型(一般是調用Funnels工具類中的)

   expectedInsertions:期望插入的值的個數

   fpp 錯誤率(默認值為0.03)

   strategy 哈希算法(樓主也不懂啥意思)

 

在最后一個create方法中,設置一個斷點:

上面的numBits,表示存一百萬個int類型數字,需要的位數為7298440,700多萬位。理論上存一百萬個數,一個int是4字節32位,需要4*8*1000000=3200萬位。如果使用HashMap去存,按HashMap50%的存儲效率,需要6400萬位。可以看出BloomFilter的存儲空間很小,只有HashMap的1/10左右

上面的numHashFunctions,表示需要5個函數去存這些數字

使用第三個create方法,我們設置下錯誤率:

private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), total, 0.0003);

再運行看看:

此時誤傷的數量為4,錯誤率為0.04%左右。

當錯誤率設為0.0003時,所需要的位數為16883499,1600萬位,需要12個函數

和上面對比可以看出,錯誤率越大,所需空間和時間越小,錯誤率越小,所需空間和時間約大

 


免責聲明!

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



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