在SpringBoot项目中利用Redission实现布隆过滤器(布隆过滤器的应用场景、布隆过滤器误判的情况、与位图相关的操作)

news2024/11/15 17:41:53

文章目录

  • 1. 布隆过滤器的应用场景
  • 2. 在SpringBoot项目利用Redission实现布隆过滤器
  • 3. 布隆过滤器误判的情况
  • 4. 与位图相关的操作
  • 5. 可能遇到的问题(Redission是如何记录布隆过滤器的配置参数的)
    • 5.1 问题产生的原因
    • 5.2 解决方案
      • 5.2.1 方案一:删除Redis中与布隆过滤器相关的key
      • 5.2.2 方案二:创建一个新的布隆过滤器

对 Redission 不了解的同学,可以参考我的另一篇博文: 在SpringBoot项目中使用Redission实现分布式锁(什么是Redission、为什么要使用分布式锁、分布式锁的应用场景、Redission的读锁和写锁、可重入锁的原理

至于什么是布隆过滤器,可以参考我的另一篇博文:Redis缓存面试三兄弟:缓存穿透、缓存雪崩、缓存击穿 的 1.3.3 方案三:使用布隆过滤器 部分

1. 布隆过滤器的应用场景

布隆过滤器(Bloom Filter)是一种空间效率极高的概率数据结构,用于测试一个元素是否属于集合

布隆过滤器可能会产生误报(一个元素不属于集合,但布隆过滤器判断元素属于该集合),但绝不会漏报(一个元素属于集合,但布隆过滤器判断元素不属于该集合)


布隆过滤器适用于以下一些应用场景:

  1. 网络爬虫:避免爬取已经访问过的URL,减少重复工作
  2. 防止缓存穿透:在缓存系统中,使用布隆过滤器检查请求的数据是否可能存在,以避免对不存在的数据进行数据库查询
  3. 数据库索引:用于快速判断一个记录是否存在于数据库中,减少不必要的磁盘I/O操作
  4. 邮件系统:过滤垃圾邮件,通过布隆过滤器快速判断一个邮件地址是否在垃圾邮件发送者列表中
  5. 网络安全:用于检测和防御DDoS攻击,通过布隆过滤器识别和过滤恶意流量
  6. 分布式系统:在分布式环境中,布隆过滤器可以用来检查数据是否已经被处理,以避免重复处理
  7. 文件系统:在文件检索系统中,快速判断一个文件是否存在于文件系统中,减少文件系统的访问次数
  8. 大数据集去重:在处理大规模数据集时,使用布隆过滤器进行高效去重
  9. 网络服务:检查客户端请求的内容是否已经被服务器处理过,从而避免重复处理

布隆过滤器的优点在于它的空间效率和查询速度,布隆过滤器在处理大量数据时非常有用

2. 在SpringBoot项目利用Redission实现布隆过滤器

如果不知道如何在 SpringBoot 项目项目中接入 Redission,可以参考我的另一篇博文:在SpringBoot项目中使用Redission实现分布式锁(什么是Redission、为什么要使用分布式锁、分布式锁的应用场景、Redission的读锁和写锁、可重入锁的原理)


编写一个测试类,测试布隆过滤器的过滤效果

import org.junit.jupiter.api.Test;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BloomFilterTests {

    @Autowired
    private RedissonClient redissionClient;

    @Test
    public void testBooleanFilter() {
        try {
            String filterName = "myBloomFilter";
            long expectedInsertions = 100000L; // 预期元素数量
            double falseProbability = 0.01; // 容错率,也就是误报率

            // 创建布隆过滤器,参数分别为:过滤器名称,预期元素数量,误差率
            RBloomFilter<Object> bloomFilter = redissionClient.getBloomFilter(filterName);
            bloomFilter.tryInit(expectedInsertions, falseProbability);

            // 添加元素
            for (int i = 1; i <= 50; i++) {
                bloomFilter.add(String.format("element%02d", i));
            }

            // 检查元素是否存在
            System.out.println("bloomFilter.contains(\"element01\") = " + bloomFilter.contains("element01"));
            System.out.println("bloomFilter.contains(\"element51\") = " + bloomFilter.contains("element51"));
        } finally {
            // 关闭 Redission 客户端
            redissionClient.shutdown();
        }
    }

}

输出结果如下

在这里插入图片描述

3. 布隆过滤器误判的情况

我们将预期元素数量改为 5 个,再次对布隆过滤器进行测试

import org.junit.jupiter.api.Test;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BloomFilterTests {

    @Autowired
    private RedissonClient redissionClient;

    @Test
    public void testBooleanFilter() {
        try {
            String filterName = "myBloomFilter";
            long expectedInsertions = 5L; // 预期元素数量
            double falseProbability = 0.01; // 容错率,也就是误报率

            // 创建布隆过滤器,参数分别为:过滤器名称,预期元素数量,误差率
            RBloomFilter<Object> bloomFilter = redissionClient.getBloomFilter(filterName);
            bloomFilter.tryInit(expectedInsertions, falseProbability);

            // 添加元素
            for (int i = 1; i <= 50; i++) {
                bloomFilter.add(String.format("element%02d", i));
            }

            // 检查元素是否存在
            System.out.println("bloomFilter.contains(\"element01\") = " + bloomFilter.contains("element01"));
            System.out.println("bloomFilter.contains(\"element51\") = " + bloomFilter.contains("element51"));
        } finally {
            // 关闭 Redission 客户端
            redissionClient.shutdown();
        }
    }

}

运行结果如下

在这里插入图片描述

可以看到,布隆过滤器出现了误判的情况(element51 不在集合中,但布隆过滤器判断 element51 在集合中)


我们查看布隆过滤器的配置(布隆过滤器中各个参数的含义可参考本文的 布隆过滤器中各个参数的含义 章节)

在这里插入图片描述

可以发现,布隆过滤器底层的位图的大小为 47,布隆过滤器在处理每个元素时要应用的哈希函数的数量为 7,也就是说,每个元素会映射到位图的 7 个位置上

我们往布隆过滤器中插入了 50 个元素,每个元素映射到位图的 7 个位置上,非常容易发生哈希冲突的情况,从而导致布隆过滤器误判


我们删除布隆过滤器后,重写运行测试代码,查看位图中 1 的数量

在这里插入图片描述

redissionClient.getBitSet(filterName).cardinality()

在这里插入图片描述

可以发现,位图的大小为 47,位图中 1 的数量也是 47,也就是说,位图中所有位置都是 1,也就意味着此时布隆过滤器已经完全失去了过滤作用

所以说,在初始化布隆过滤器时,我们需要十分注意 预期元素数量误判率 参数,否则布隆过滤器的过滤效果将会大打折扣,甚至失效

4. 与位图相关的操作

Redission 提供的 RBloomFilter 类用于布隆过滤,而 RBitSet类 用于常规的位图操作

使用 RBitSet 类可以对各种位图进行各种操作,如设置位、清除位、检查位的状态等

在这里插入图片描述

@Test
public void testBitmap() {
    try {
        String filterName = "myBloomFilter";

        RBitSet bitSet = redissionClient.getBitSet(filterName);

        bitSet.set(0, true); // 设置第0位为1
        bitSet.set(1, false); // 设置第1位为0

        bitSet.clear(0); // 清除第0位

        boolean isSet = bitSet.get(0); // 检查第0位是否为1
        System.out.println("isSet = " + isSet);

        long count = bitSet.cardinality(); // 返回位图中1的数量
        System.out.println("count = " + count);
    } finally {
        // 关闭 Redission 客户端
        redissionClient.shutdown();
    }
}

5. 可能遇到的问题(Redission是如何记录布隆过滤器的配置参数的)

在这里插入图片描述

org.redisson.client.RedisException: ERR Error running script (call to f_a7ac8cff901d5cafb8de37987dfbe1fc11f00eb4): @user_script:1: user_script:1: Bloom filter config has been changed . channel: [id: 0xe1fd1f6a, L:/127.0.0.1:3098 - R:127.0.0.1/127.0.0.1:6379] command: (EVAL), promise: java.util.concurrent.CompletableFuture@52a215fa[Not completed, 1 dependents], params: [local size = redis.call(‘hget’, KEYS[1], ‘size’);local hashIterations = redis.call(‘hget’, KEYS[1], ‘hashIterations’);assert(size == ARGV[1] and hashIterations == ARGV[2], ‘Bloom filter config has been changed’)local k = 0;local c = 0;for i = 4, #ARGV, 1 do local r = redis.call(‘setbit’, KEYS[2], ARGV[i], 1); if r == 0 then k = k + 1;end; if ((i - 4) + 1) % ARGV[3] == 0 then if k > 0 then c = c + 1;end; k = 0; end; end; return c;, 2, {myBloomFilter}:config, myBloomFilter, 47, 7, 7, 6, 14, 20, …]


5.1 问题产生的原因

之所以会报错,是因为布隆过滤器的配置参数被篡改了

那布隆过滤器的配置参数存放在哪里呢,当然是存在 Redis 里面,Redis 中会有一个与布隆过滤器配置参数相关的 key,这个 key 使用的是 Hash 结构

在这里插入图片描述

在这里插入图片描述

各个参数的含义:

  1. size:布隆过滤器位图的大小
  2. hashIterations:布隆过滤器在处理每个元素时要应用的哈希函数的数量
  3. falseProbability:布隆过滤器的误报率,即错误地判断一个元素存在于集合中的概率
  4. expectedInsertions:预期将要插入布隆过滤器的元素数量

5.2 解决方案

5.2.1 方案一:删除Redis中与布隆过滤器相关的key

直接删除 Redis 中与布隆过滤器相关的 key,下次再操作布隆过滤器时会重新创建布隆过滤器

在这里插入图片描述

5.2.2 方案二:创建一个新的布隆过滤器

直接更改布隆过滤器的名字,创建一个新的布隆过滤器

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2152699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DBeaver启动报错 Faild to load the JNI shared library

DBeaver启动报错 Faild to load the JNI shared library 问题现象 安装完成后&#xff0c;启动dbeaver报错 查看版本为64位版本&#xff0c;JAVA也为64为版本 dbeaver版本 java版本 解决 在dberver.ini添加指定配置&#xff0c;即可启动成功

msvcp100.dll是什么意思?msvcp100.dll丢失有什么可靠的解决方法

当我们在电脑中试图启动某些程序或游戏时&#xff0c;可能会遇到一个错误消息&#xff1a;"程序无法启动&#xff0c;因为计算机缺少msvcp100.dll"。其实遇到这种情况是非常的常见的&#xff0c;只要你是经常使用电脑的人&#xff0c;我们要解决它也非常的简单&#…

工作中遇到的问题总结(1)

文章目录 第一题问题描述解决思路 第二题问题描述解决思路核心大表如何优化数据迁移过程是怎么样的如何将流量从旧系统迁移到新系统上 第三题问题描述解决思路 第四题问题描述解决思路方案一&#xff1a;双写机制方案二&#xff1a;基于时间戳的分流机制方案三&#xff1a;灰度…

数据结构之线性表——LeetCode:707. 设计链表,206. 反转链表,92. 反转链表 II

707. 设计链表 题目描述 707. 设计链表 你可以选择使用单链表或者双链表&#xff0c;设计并实现自己的链表。 单链表中的节点应该具备两个属性&#xff1a;val 和 next 。val 是当前节点的值&#xff0c;next 是指向下一个节点的指针/引用。 如果是双向链表&#xff0c;则…

【滑动窗口】算法总结

文章目录 滑动窗口算法总结1.暴力求解vs滑动窗口2.需要注意的细节问题 2.滑动窗口的基本模板1.非固定窗口大小的滑动窗口2.固定窗口大小的滑动窗口细节 滑动窗口算法总结 1.暴力求解vs滑动窗口 遇到那些可以转化成一个子数组的长度的问题时&#xff0c;往往需要用到双指针。 …

二,MyBatis -Plus 关于映射 Java Bean 对象的注意事项和细节(详细说明)

二&#xff0c;MyBatis -Plus 关于映射 Java Bean 对象的注意事项和细节(详细说明) 文章目录 二&#xff0c;MyBatis -Plus 关于映射 Java Bean 对象的注意事项和细节(详细说明)1. 映射2. 表的映射3. 字段映射4. 字段失效5. 视图属性6. 总结&#xff1a;7. 最后&#xff1a; 1.…

【C/C++】速通涉及string类的经典编程题

【C/C】速通涉及string类的经典编程题 一.字符串最后一个单词的长度代码实现&#xff1a;&#xff08;含注释&#xff09; 二.验证回文串解法一&#xff1a;代码实现&#xff1a;&#xff08;含注释&#xff09; 解法二&#xff1a;&#xff08;推荐&#xff09;1. 函数isalnum…

单卡3090 选用lora微调ChatGLM3-6B

环境配置 Python 3.10.12 transformers 4.36.2 torch 2.0.1 下载demo代码 在官方网址https://github.com/THUDM/ChatGLM3/blob/main/finetune_demo 下载demo代码cd 进入文件夹 pip install -r requirements.txt 安装一些包 基本知识 SFT 全量微调: 4张显卡平均分配&#…

13年计算机考研408-数据结构

解析&#xff1a; 这个降序链表不影响时间复杂度&#xff0c;因为是链表&#xff0c;所以你想要升序就使用头插法&#xff0c;你想要降序就使用尾插法。 然后我们来分析一下最坏的情况是什么样的。 因为m和n都是两个有序的升序序列。 如果刚好m的最大值小于n的最小值&#xff0…

AI宠物拟人化新玩法,教你如何用0成本打造爆款创意内容!

近年来&#xff0c;随着AI技术的快速发展&#xff0c;各种创新玩法不断涌现&#xff0c;尤其是在内容创作领域&#xff0c;AI带来的变革尤为显著。 **其中&#xff0c;宠物拟人化逐渐成为社交媒体上的一大热门话题。**通过AI生成工具&#xff0c;我们不仅可以将宠物拟人化&…

Snapchat API 访问:Objective-C 实现示例

Snapchat 是一个流行的社交媒体平台&#xff0c;它允许用户发送和接收短暂存在的图片和视频。对于开发者来说&#xff0c;访问 Snapchat API 可以为应用程序添加独特的社交功能。本文将介绍如何在 Objective-C 中实现对 Snapchat API 的访问&#xff0c;并提供一个详细的代码示…

GD32F103单片机-EXTI外部中断

GD32F103单片机-EXTI外部中断 一、EXTI及NVIC介绍二、编程实验2.1 相关库函数2.2 实验代码 一、EXTI及NVIC介绍 GD32和STM32的EXTI基本相似&#xff0c;具体见STM32F1单片机-外部中断GD32的EXTI包括20个相互独立的边沿检测电路请求产生中断或事件&#xff0c;4位优先级配置寄存…

热像仪是如何工作的?

红外热像仪是一种非接触式设备&#xff0c;能够检测红外能量&#xff08;热量&#xff09;并将其转变成可见光图像。让我们深入了解红外热像仪的科学原理&#xff0c;以及借助红外热像仪我们能够看到的隐形世界。 捕捉红外波&#xff0c;而不是可见光 首先必须清楚的是&#…

windows环境下配置MySQL主从启动失败 查看data文件夹中.err发现报错unknown variable ‘log‐bin=mysql‐bin‘

文章目录 问题解决方法 问题 今天在windows环境下配置MySQL主从同步&#xff0c;在修改my.ini文件后发现MySQL启动失败了 打开my.ini检查参数发现没有问题 [mysqld] #开启二进制日志&#xff0c;记录了所有更改数据库数据的SQL语句 log‐bin mysql‐bin #设置服务id&#x…

Vue(13)——router-link

router-link vue-router提供了一个全局组件router-link(取代a标签) 能跳转&#xff0c;配置to属性指定路径&#xff08;必须&#xff09;。本质还是a标签。默认会提供高亮类名&#xff0c;可以直接设置高亮样式 右键检查&#xff0c;发现多了两个类&#xff1a; 可以直接写样式…

Java数据结构专栏介绍

专栏导读 在软件工程的世界里&#xff0c;数据结构是构建高效、可靠程序的基石。"Java数据结构"专栏致力于为Java开发者提供一个全面、深入的学习平台&#xff0c;帮助他们掌握各种数据结构的原理、实现及其在Java中的应用。通过这个专栏&#xff0c;读者将能够提升…

IPsec-Vpn

网络括谱图 IPSec-VPN 配置思路 1 配置IP地址 FWA:IP地址的配置 [FW1000-A]interface GigabitEthernet 1/0/0 [FW1000-A-GigabitEthernet1/0/0]ip address 10.1.1.1 24 [FW1000-A]interface GigabitEthernet 1/0/2 [FW1000-A-GigabitEthernet1/0/2]ip address

分布式Id生成策略-美团Leaf

之前在做物流相关的项目时候&#xff0c;需要在分布式系统生成运单的id。 1.需求&#xff1a; 1.全局唯一性&#xff1a;不能出现重复的ID。&#xff08;基本要求&#xff09; 2.递增&#xff1a;大多数关系型数据库&#xff08;如 MySQL&#xff09;使用 B 树作为索引结构。…

web前端-HTML常用标签-综合案例

如图&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document&…

mysql时间戳格式化yyyy-mm-dd

格式化到 年月日 # 将时间换成列名就行&#xff1b;当前是秒级时间戳&#xff0c;如果是毫秒的 / 1000即可 # SELECT FROM_UNIXTIME(1602668106666.777888999 / 1000,%Y-%m-%d) AS a; # SELECT FROM_UNIXTIME(列名 / 1000,%Y-%m-%d) AS a; SELECT FROM_UNIXTIME(1602668106.666…