• 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个函数

    和上面对比可以看出,错误率越大,所需空间和时间越小,错误率越小,所需空间和时间约大

  • 相关阅读:
    File
    多态
    方法重载
    Math
    instanceof
    强制类型转换
    泛型
    springboot热部署
    iOS bug处理
    iOS8-xcode6中添加pch全局引用文件
  • 原文地址:https://www.cnblogs.com/xuwenjin/p/9604262.html
Copyright © 2020-2023  润新知