布隆过滤器

本文介绍了布隆过滤器的概念,它是一种节省空间的数据结构,用于判断元素是否存在,常用于爬虫URL去重和缓存穿透场景。文章详细阐述了布隆过滤器的实现原理,通过多个哈希函数映射位向量,并给出了简单的Java实现示例。同时,提到了Google Guava库中的BloomFilter使用,并提及Redis中的布隆过滤器插件用于分布式去重。
摘要由CSDN通过智能技术生成

0 什么是布隆过滤器

布隆过滤器(Bloom Filter) 是由巴顿布隆于1970提出,是一种通过多个哈希函数映射来对参数存储空间进行压缩的数据结构;本质上是由一个比较长的二进制位向量和一组hash函数映射构成。 由于布隆过滤器不需要存储元素本身,节省了大量的空间,所以其在数据查重时具有很大优势。
布隆过滤器的优点是空间效率和查询时间都远远超过⼀一般的算法,缺点是有一定的误识别率和删除困难,因此其不适合对误判率要求较高的场景。有研究表明如果想保持较低的误判率,布隆过滤器的使用空间应低于50%。

1 布隆过滤器实现原理

假设某个布隆过滤器的位向量大小为m,且在初始状态每一位都是0,如下图所示。
在这里插入图片描述
现有n个元素数据集合{x1,x2,x3…xn},布隆过滤器通过k个hash函数将集合中的每一个元素映射到布隆过滤器的k个位置上,并将相应向量位置为1。如果置位时发现该位值已经是1了,可以不进行操作。如下图所示x1和x2 通过3个hash函数的映射过程。

在这里插入图片描述

2 布隆过滤器应用场景

根据布隆过滤器优缺点,布隆过滤过滤器同城使用来检索某个元素是否在存在。典型如 爬虫中url去重,redis缓存穿透场景。比如在缓存穿透的场景中,可以在把数据写入数据库时,使用布隆过滤器做个标记。当缓存缺失时候,可以通过查询布隆过滤器来快速判断数据是否存在,如果不存在,就不用在去查询数据库了,这样一来即使发生缓存穿透,也不会有大量的流量打到DB。

3 实践

自己编写一个简单的布隆过滤器,代码如下。

/**
 * @author hsc
 * @date 2021/4/3
 */
public class MyBloomFilter {
    private final static int DEFAULT_SIZE = 1024 * 1024;
    private int size;
    private BitSet bitSet;
    private List<HashFunction> hashFunctions = new ArrayList<>(8);

    public MyBloomFilter() {
        //这里面默认使用3个hash函数
        for (int i = 0; i < 3; i++) {
            hashFunctions.add(new HashFunction(i + 2));
        }
        bitSet = new BitSet(DEFAULT_SIZE);
        size = DEFAULT_SIZE;
    }

    private int getBitIndex(int hash) {
        return (size - 1) & hash;
    }

    public void add(String value) {
        if (value == null) {
            return;
        }
        for (HashFunction f : hashFunctions) {
            bitSet.set(getBitIndex(f.hash(value)), true);
        }
    }

    public boolean containValue(String value) {
        if (value == null) {
            return false;
        }
        for (HashFunction f : hashFunctions) {
            boolean result = bitSet.get(getBitIndex(f.hash(value)));
            if (!result) {
                return false;
            }
        }
        return true;
    }

    private static class HashFunction {
        private int seed;

        public HashFunction(int seed) {
            this.seed = seed;
        }

        public int hash(String value) {
            int result = 0;
            int len = value.length();
            for (int i = 0; i < len; i++) {
                result = seed * result + value.charAt(i);
            }
            return Math.abs(result);
        }
    }

    public static void main(String[] args) {
        MyBloomFilter bloomFilter = new MyBloomFilter();
        for (int i = 0; i < 1000000; i++) {
            bloomFilter.add(String.valueOf(i));
        }
        System.out.println(bloomFilter.containValue("121212"));
    }
}

Google Guava 中已经包含BloomFilter实现,我们可以直接使用。

        BloomFilter bloomFilter=BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")),10000,0.01);
        for (int i = 0; i < 1000000; i++) {
            bloomFilter.put(String.valueOf(i));
        }
        System.out.println(bloomFilter.mightContain("121212"));

在redis中 布隆过滤器作为一个插件加载到 Redis Server 中,给 Redis 提供了强大的分布式去重功能。在已安装 Redis 的前提下, 需要安装RedisBloom插件。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值