当前位置: 首页 > news >正文

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

目录

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"));   // 输出 trueSystem.out.println(bloomFilter.contains("banana"));  // 输出 trueSystem.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. 动态更新布隆过滤器: 当缓存中的数据更新时,需要相应地更新布隆过滤器中的信息,以确保布隆过滤器的准确性。否则,布隆过滤器可能会误判某个参数在缓存中不存在。

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

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

http://www.lryc.cn/news/121434.html

相关文章:

  • ElasticSearch学习
  • 软件测试基础篇——Redis
  • 大数据扫盲(1): 数据仓库与ETL的关系及ETL工具推荐
  • spring的aop动态代理对象注入时机
  • idea集成svn
  • RedisDesktopManage
  • 《Vue.js实战》——基础篇(1)
  • R语言 列表中嵌套列名一致的多个数据框如何整合为一个数据框
  • PyQt5利用QTextEdit控件输入多行文本
  • 【数据结构】二叉树常见题目
  • 树莓派使用 ENC28J60
  • 跟我学C++中级篇——模板友元的应用
  • 软件测试基础篇——MySQL
  • FreeRTOS(二值信号量)
  • leetcode面试题:动物收容所(考查对队列的理解和运用)
  • 【Linux命令行与Shell脚本编程】第十八章 文本处理与编辑器基础
  • 2023牛客暑期多校训练营7
  • centos7升级glibc2.28
  • 腾讯云香港服务器租用_2核2G20M_2核4G30M
  • 十三、ESP32PS2摇杆(ADC)
  • 网络安全的相关知识点
  • 算法练习(6):牛客在线编程06 递归/回溯
  • C#使用OpenCv(OpenCVSharp)图像局部二值化处理实例
  • MySQL多表关联查询
  • flutter开发实战-CustomClipper裁剪长图帧动画效果
  • CSS 中的优先级规则是怎样的?
  • 概率图模型(Probabilistic Graphical Model,PGM)
  • Oracle 知识篇+会话级全局临时表在不同连接模式中的表现
  • MySQL 数据库文件的导入导出
  • 找不到资产文件project.assets.json