一文讲明白布隆过滤器

布隆过滤器

百度百科:布隆过滤器(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));
    }
}

 

 

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