十分钟了解布隆过滤器

1 什么是布隆过滤器

布隆过滤器(Bloom Filter): 1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列的随机映射函数(哈希函数)两部分组成的数据结构。

用途: 用于检索一个元素是否在一个集合中。
——你可以永远相信布隆
在这里插入图片描述

2 布隆过滤器的原理

布隆过滤器的数据结构是一个位向量,也就是一个由0、1所组成的bit数组

2.1 数据结构

在这里插入图片描述

2.2 添加元素

每个元素添加进布隆过滤器前,都会经过多个不同的哈希函数,计算出不同的哈希值,然后映射到位向量上,也就是对应的位"置1"
在这里插入图片描述

2.3 判断元素

对元素进行多个不同的哈希运算,得到多个位下标,判断所有映射位置是否都为1,若是,则元素可能存在,否则一定不存在
注意:由于不同的值通过哈希函数之后可能会映射到相同的位置,因此如果一个不存在的元素对应的位都被其他元素所设置1,则查询时就会误判
在这里插入图片描述

2.4 删除元素

布隆过滤器对元素的删除不太支持,因为元素删除不能简单的把对应的若干位设置为0,会对其他元素有影响。
目前有一些变形的特定布隆过滤器支持元素的删除(尽可能不考虑删除)。

3 布隆过滤器的优缺点

优点:
时间复杂度低,增加及查询元素的时间复杂度都是O(k),k为Hash函数的个数;
保密性强,布隆过滤器不存储元素本身;
占用存储空间小,布隆过滤器相对于其他数据结构(如Set、Map)非常节省空间;

缺点:
存在误判,只能证明一个元素一定不存在或者可能存在,返回结果是概率性的,但是可以通过调整参数来降低误判比例;
删除困难,一个元素映射到bit数组上的k个位置为1,删除的时候不能简单的直接置为0,可能会影响到其他元素的判断;
无法通过key找到元素本身;

3 布隆过滤器适用场景

  • 解决Redis缓存穿透问题(访问非法key)
  • 黑名单过滤
  • 爬虫任务处理过滤,爬过的不再爬
  • 解决新闻推荐过的不再推荐(类似抖音刷过的往下滑动不再刷到)
  • HBase\RocksDB\LevelDB等数据库内置布隆过滤器

4 代码示例

4.1 Java示例

// 初始化布隆过滤器,设计预计元素数量为100w,误差率为1‰
        BloomFilter<Long> bloomFilter = BloomFilter.create(Funnels.longFunnel(), 1000000, 0.001);
        int n = 1000000;

        for (long i = 0; i < n; i++) {
            bloomFilter.put(i);
        }
        int containCount = (n * 5);//匹配总次数
        int rightCount = 0;//正确次数
        int errCount = 0;//误判次数
        for (long i = 0; i < containCount; i++) {
            if (bloomFilter.mightContain(i)) {
                if (i < n) {
                    rightCount++;
                } else {
                    errCount++;
                }
            } else {
                if (i >= n) {
                    rightCount++;
                } else {
                    errCount++;
                }
            }
        }
        long size = ObjectSizeCalculator.getObjectSize(bloomFilter);

        System.out.println(String.format("匹配次数:%s,正确次数:%s,错误次数:%s", containCount, rightCount, errCount));
        System.out.println("过滤器误判率:" + NumberUtil.roundStr(errCount * 1.0 / containCount, 10));
        System.out.println("占用空间,bloomSize:" + NumberUtil.roundStr((size * 1.0 / 1024 / 1024), 4) + "MB");

在这里插入图片描述

4.2 Redis示例

@Resource
private RedissonClient redissonClient;

/**
     * 容量
     */
    private static Long expectedInsertions = 1000000L;
    /**
     * 误差
     */
    private static Double falseProbability = 0.001;

    private void add(String key, String data) {
        RBloomFilter bloomFilter = redissonClient.getBloomFilter(key);
        bloomFilter.tryInit(expectedInsertions, falseProbability);
        bloomFilter.add(data);
    }

    private Boolean exist(String key, String data) {
        RBloomFilter bloomFilter = redissonClient.getBloomFilter(key);
        bloomFilter.tryInit(expectedInsertions, falseProbability);
        boolean isExist = bloomFilter.contains(data);
        return isExist;
    }
    
//测试
{
        add("bloom:place", "abc");
        Boolean check1 = exist("bloom:place", "abc");
        log.info("check1:{}", check1);
        Boolean check2 = exist("bloom:place", "abcd");
        log.info("check2:{}", check2);
        return assembleResponse("ok,");
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值