布隆过滤器的原理和应用场景

目录

1 原理

2 代码示例

3 位数组

4 布隆过滤器的实际应用场景


1 原理

布隆过滤器(Bloom Filter)是一种数据结构,用于快速判断一个元素是否存在于一个集合中,具有高效的插入和查询操作。它的设计目的是在空间效率和查询效率之间寻求一种折衷方案。

布隆过滤器基于位向量(bit array)和一系列的哈希函数。它适用于需要进行高速判断的场景,例如缓存系统、拼写检查、垃圾邮件过滤等。

布隆过滤器的原理如下:

  1. 初始化:创建一个大小为 m 的位向量,所有位初始化为 0。

  2. 插入:当要插入一个元素时,对该元素进行 k 次哈希函数计算,将对应的 k 个位设为 1。

  3. 查询:当要查询一个元素是否存在时,同样对该元素进行 k 次哈希函数计算,检查对应的 k 个位是否都为 1,如果有任何一个位不为 1,则确定该元素不存在于集合中。如果所有位都为 1,则该元素可能存在于集合中(但不确定,考虑到误判率)。

因为布隆过滤器采用了多次哈希函数,并将元素映射到多个位,所以存在一定的误判率。即使一个元素不存在于集合中,由于其哈希值可能会与其他元素的哈希值重叠,导致误判为存在。但是,布隆过滤器具有占用空间小、查询速度快的特点,适用于需要快速判断元素是否可能存在的场景。

需要注意的是,布隆过滤器不支持删除操作,因为删除操作会影响到其他可能存在的元素。如果需要支持删除操作,可能需要考虑其他数据结构。

2 代码示例

import java.util.BitSet;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class BloomFilter {
    private int size; // 位数组的大小
    private int hashCount; // 哈希函数的个数
    private BitSet bitArray; // 位数组

    public BloomFilter(int size, int hashCount) {
        this.size = size;
        this.hashCount = hashCount;
        this.bitArray = new BitSet(size);
    }

    public void add(String item) {
        for (int i = 0; i < hashCount; i++) {
            int index = hashFunction(item, i) % size;
            bitArray.set(index, true);
        }
    }

    public boolean contains(String item) {
        for (int i = 0; i < hashCount; i++) {
            int index = hashFunction(item, i) % size;
            if (!bitArray.get(index)) {
                return false;
            }
        }
        return true;
    }

    private int hashFunction(String item, int seed) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update((item + seed).getBytes());
            byte[] digest = md.digest();
            return Math.abs(java.util.Arrays.hashCode(digest));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Hash function error: " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        BloomFilter bloomFilter = new BloomFilter(100, 3);

        bloomFilter.add("apple");
        bloomFilter.add("banana");
        bloomFilter.add("cherry");

        System.out.println(bloomFilter.contains("apple"));   // 输出 true
        System.out.println(bloomFilter.contains("banana"));  // 输出 true
        System.out.println(bloomFilter.contains("grape"));   // 输出 false
    }
}

根据上述代码可知,要使用布隆过滤器,需要的成员属性有:size(位数组大小)、hashCount(哈希函数的个数)、bitArray(位数组)、hashFunction()这个是定义哈希函数的方法,参数是要加入集合的值以及哈希计算的次数,注意hashCount一般会通过for循环去调用它,以便k次哈希计算中每次使用的哈希函数是不同的。

3 位数组

这里提下位数组的概念以及与普通数组的区别

  1. 存储方式

    • 位数组:位数组中的每个元素只占用一个位(0 或 1),因此在存储上非常紧凑。它使用的是比特位来表示数据。
    • 普通数组:普通数组中的每个元素可以是任意数据类型,比如整数、浮点数、对象等。根据数据类型的不同,存储占用的空间可能会更多。
  2. 存储内容

    • 位数组:通常用于表示某种状态、存在与否、开关等,每个位代表一个二进制信息,例如布尔值。
    • 普通数组:存储任意数据类型,可以包含数字、字符串、对象等。
  3. 内存占用

    • 位数组:由于每个元素只占用一个位,因此在相同存储空间下,可以存储更多的元素,适用于需要存储大量布尔信息的情况。
    • 普通数组:根据元素的数据类型和数量,占用的内存空间会更大。
  4. 使用场景

    • 位数组:适用于需要紧凑地表示某种状态或标记,如布隆过滤器、位图索引等。
    • 普通数组:适用于存储多种数据类型的数组,如整数数组、字符串数组、对象数组等。

总之,位数组和普通数组的主要区别在于存储方式和存储内容。位数组通常用于紧凑地存储标志、状态等信息,而普通数组可以存储多种类型的数据。选择使用哪种类型的数组取决于具体的应用场景和需求。

4 布隆过滤器的实际应用场景

背景:我们知道,现如今的电商系统特别是像阿里旗下的、京东等肯定是需要面对高并发请求问题的,这时避免不了用到中间件技术例如Redis、MQ。而以某宝为例,即使在用户不登录的情况下,它是需要有一些开放的API供未登录用户去看的,如“/product/{id}”,表示界面上对应的商品。当商品特别多,且用户同时点击作请求的次数太大时,Redis作为缓存是让服务器能够稳定运行的前提。这看起来似乎是解决了高并发问题,且能够避免最影响整个系统服务性能的数据库被频繁访问。但对于黑客来说,这其中有个漏洞可钻。既然id是指商品的标识符,那我不断输入不存在的商品id,而Redis又发现缓存中没有这样的id,就会转向数据库作请求,如此这般,便造成了缓存穿透。所以,一个新的问题是:我要如何识别并处理这些不存在的id,避免让它们频繁“骚扰”数据库呢?这时布隆过滤器就这样闪亮登场了。

解决

上面提到的缓存穿透,总结来讲是指在缓存中找不到所需的数据,导致每次请求都需要访问数据库或其他数据源,从而造成系统负担过大。这种情况可能是由于恶意请求、非法输入或者业务逻辑问题导致的。

布隆过滤器可以在缓存层面起到一定的预防作用,减轻缓存穿透带来的影响。具体来说,以下是布隆过滤器如何用于防止缓存穿透的细节:

  1. 在查询缓存前进行判断: 在查询缓存之前,先将查询的参数进行布隆过滤器的检查。如果布隆过滤器判断这个参数不在缓存的可能存在集合中,那么就不会去查询缓存,避免了不必要的数据库或其他数据源访问。

  2. 合法参数和非法参数的判断: 布隆过滤器可以帮助区分合法参数和非法参数。如果一个参数不在布隆过滤器中,说明它肯定是非法的,可以直接返回一个错误或默认值,而不会继续访问后端数据源。

  3. 动态更新布隆过滤器: 当缓存中的数据更新时,需要相应地更新布隆过滤器中的信息,以确保布隆过滤器的准确性。否则,布隆过滤器可能会误判某个参数在缓存中不存在。

需要注意的是,布隆过滤器虽然可以减轻缓存穿透问题,但并不是完全解决方案。它可以用来过滤掉一部分明显无效的请求,但不能保证百分之百防止缓存穿透。在实际应用中,布隆过滤器通常与其他技术一起使用,如合理设置缓存过期时间、使用缓存预热等,来综合解决缓存穿透问题。

其它的应用场景包括拼写检查、垃圾邮件过滤

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛变涡流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值