【Redis篇】详解布隆过滤器(原理 | 操作 | 代码)

文章目录

  • 🍔简述布隆过滤器
  • 🌺原理
    • 🛸存入过程
    • 🛸查询过程
  • 🏳️‍🌈优缺点
    • ⭐优点
    • ⭐缺点
  • 🌹代码实现(本地)
  • 🌹代码实现(分布式)

在这里插入图片描述

🍔简述布隆过滤器

布隆过滤器的由来可以追溯到1970年代,由一个名叫Burton Howard Bloom的美国计算机科学家提出。他在1970年的一篇论文中首次描述了这个概念,并将其称为"Bloom filter"。

Bloom当时的目标是设计一种高效的数据结构,用于在大规模数据库中进行快速查询。他的主要思想是通过使用一个位数组和多个哈希函数,能够在不存储实际数据的情况下,快速判断一个元素是否存在于集合中。这种数据结构的提出,为解决大规模数据的查找问题提供了一种经济高效的方法。

布隆过滤器最初的应用场景是在数据库系统中,用于加速查询操作。它可以有效地减少磁盘I/O操作,提高查询效率,并节省存储空间。后来,布隆过滤器得到了广泛的应用,在各种领域都发挥了重要作用。

随着互联网的迅速发展和大数据时代的到来,布隆过滤器的应用范围越来越广泛。它被用于网络缓存、分布式系统、垃圾邮件过滤、URL去重、爬虫的URL判重、密码学等领域。由于其高效的查询性能和低存储成本,布隆过滤器成为了解决大规模数据处理和高并发访问的重要工具。

总结来说,布隆过滤器是由美国计算机科学家Burton Howard Bloom提出的一种高效的概率型数据结构,用于快速判断一个元素是否存在于集合中。它的提出解决了大规模数据查询的问题,并在各个领域得到了广泛的应用和发展。

🌺原理

布隆过滤器其实就是一个很长的二进制向量和一系列随机映射函数,主要用来判断一个元素是否存在一个集合中,存储的数据不是0就是1,默认是0
1代表存在某个数据,0代表不存在

🛸存入过程

因为布隆过滤器就是一个二进制数据的集合,当有一个数据加入到这个集合的时候,会经过下面的步骤

  • 通过k个哈希函数计算该数据,返回k个计算得到的hash值
  • 这些k个hash值映射到对应的k个二进制的数组下标
  • 将k个下标对应的二进制数据改为1

在这里插入图片描述

🛸查询过程

布隆过滤器主要就是来查询一个数据在不在这个二进制集合中,具体方法如下

  • 通过k个hash函数计算该数据,得到hash值
  • 通过hash值找到对应的二进制数字的下标
    如果某一处的二进制数据为0,那么该数据不存在,如果都是1,那么该数据存在集合中

🏳️‍🌈优缺点

⭐优点

布隆过滤器具有以下几个主要的优点:

  • 高效的查询性能:布隆过滤器通过位数组和多个哈希函数实现了快速的元素判断。在查询一个元素是否存在于集合中时,只需要进行多次哈希计算和位数组查询操作,而不需要真正地存储和比较元素本身。因此,查询的时间复杂度是常数级别的,具有非常高的查询效率。
  • 较低的存储需求:布隆过滤器使用位数组表示元素的存在情况,而不需要存储实际的元素本身。且通过多个哈希函数的映射,可以将元素分散到位数组的多个位置上,从而进一步减少存储空间的需求。相比于直接存储元素本身的数据结构,布隆过滤器在存储方面具有较低的空间复杂度。
  • 支持高并发访问:由于布隆过滤器的查询操作只涉及位数组的查询和哈希函数的计算,不需要对实际元素进行读写操作,所以在并发访问的场景下,不会出现数据读写冲突的问题。这使得布隆过滤器非常适合于高并发环境下的数据处理和查询。
  • 可扩展性强:布隆过滤器可以根据需要动态地调整位数组的大小和哈希函数的个数,以适应不同规模和需求的数据集。通过增加位数组的长度和增加哈希函数的数量,可以提高布隆过滤器的准确性和容错性。
  • 简单高效的实现:布隆过滤器的实现相对简单,只需要一个位数组和多个哈希函数即可。哈希函数的选择和设计也相对容易,可以根据实际需求进行调整。这使得布隆过滤器在实际应用中具有较好的可用性和灵活性。

综上所述,布隆过滤器具有高效的查询性能、较低的存储需求、支持高并发访问、可扩展性强和简单高效的实现等优点,使其成为解决大规模数据查询和去重等问题的有效工具。

⭐缺点

布隆过滤器虽然有很多优点,但也存在一些缺点,主要包括以下几个方面:

  • 误判率(False Positive):由于布隆过滤器的设计特性,它可能会产生一定的误判率,即认为一个元素存在于集合中,但实际上并不存在。这是因为多个元素经过哈希函数映射后可能会映射到相同的位数组位置上,从而导致冲突。误判率随着位数组的大小和哈希函数的数量增加而降低,但无法完全消除。
  • 不支持删除操作:布隆过滤器的位数组中存储的是元素是否存在的信息,而不存储元素本身。因此,在布隆过滤器中删除一个元素是比较困难的,通常需要重新创建一个新的布隆过滤器。这限制了布隆过滤器在某些场景下的灵活性和可用性。
  • 无法获取具体元素:由于布隆过滤器只存储元素是否存在的信息,而不存储元素本身,因此无法直接获取具体的元素内容。如果需要获取具体元素,仍需使用其他数据结构进行进一步查询。
  • 存储空间的浪费:虽然布隆过滤器相比其他数据结构具有较低的存储需求,但在一些特定情况下,由于需要保证较低的误判率,可能需要增加位数组的大小和哈希函数的数量,从而导致存储空间的浪费。
  • 初始化时的时间和计算开销:布隆过滤器在初始化时需要分配位数组并进行哈希函数的计算,这个过程可能需要较多的时间和计算资源。尤其是在处理大规模数据集时,初始化的时间和计算开销会比较大。

综上所述,布隆过滤器的主要缺点包括误判率、不支持删除操作、无法获取具体元素、存储空间浪费以及初始化时的时间和计算开销。在使用布隆过滤器时,需要根据实际需求和场景权衡其优缺点,选择合适的数据结构。

假如“你好”和“hello”这2个数据的hash值一样,那么他们将会存储到同一位置
当我们要删除“hello”这个数据的时候,我们会删除存储“hello”这个数据的hash值的位置,由于“hello”和“你好”存储在同一位置,这样子会造成误删
同理
如果仅仅存储了hello,没有存储“你好”,当我们查询“你好”的时候,由于 假设“你好”和“hello”这2个数据的hash值一样,会造成误判

🌹代码实现(本地)

引入依赖

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>29.0-jre</version>
</dependency>

编写核心代码,我们使用下面的代码来测试一下布隆过滤器的误判率

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class BloomFilterCase {

  /**
   * 预计要插入多少数据
   */
  private static int size = 1000000;

  /**
   * 期望的误判率
   */
  private static double fpp = 0.01;

  /**
   * 布隆过滤器
   */
  private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);


  public static void main(String[] args) {
    // 插入10万样本数据
    for (int i = 0; i < size; i++) {
      bloomFilter.put(i);
    }

    // 用另外十万测试数据,测试误判率
    int count = 0;
    for (int i = size; i < size + 100000; i++) {
      if (bloomFilter.mightContain(i)) {
        count++;
        System.out.println(i + "误判了");
      }
    }
    System.out.println("总共的误判数:" + count);
  }
}

这里的误判率可以通过fpp参数进行调节,fpp越小,需要的内存空间就越大:0.01需要900多万位数,0.03需要700多万位数。
fpp越小,集合添加数据时,就需要更多的hash函数运算更多的hash值,去存储到对应的数组下标里。

🌹代码实现(分布式)

上面使用Guava实现的布隆过滤器是把数据放在了本地内存中。分布式的场景中就不合适了,无法共享内存。

我们还可以用Redis来实现布隆过滤器,这里使用Redis封装好的客户端工具Redisson。

引入依赖

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson-spring-boot-starter</artifactId>
  <version>3.13.4</version>
</dependency>

编写核心代码

public class RedissonBloomFilter {

  public static void main(String[] args) {
    Config config = new Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:6379");
    config.useSingleServer().setPassword("1234");
    //构造Redisson
    RedissonClient redisson = Redisson.create(config);

    RBloomFilter<String> bloomFilter = redisson.getBloomFilter("phoneList");
    //初始化布隆过滤器:预计元素为100000000L,误差率为3%
    bloomFilter.tryInit(100000000L,0.03);
    //将号码10086插入到布隆过滤器中
    bloomFilter.add("10086");

    //判断下面号码是否在布隆过滤器中
    //输出false
    System.out.println(bloomFilter.contains("123456"));
    //输出true
    System.out.println(bloomFilter.contains("10086"));
  }
}

代码参考文章:https://mp.weixin.qq.com/s/vwy5oGEWNuQ7k5DQfGrhCQ

在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis 集群(Cluster)

集群概念 Redis 的哨兵模式&#xff0c;提高了系统的可用性&#xff0c;但是正在用来存储数据的还是 master 和 slave 节点&#xff0c;所有的数据都需要存储在单个 master 和 salve 节点中。 如果数据量很大&#xff0c;接近超出了 master / slave 所在机器的物理内存&#…

HTTP请求报文与响应报文格式

HTTP请求报文与响应报文格式 HTTP请求报文与响应报文格式 请求报文包含四部分&#xff1a; a、请求行&#xff1a;包含请求方法、URI、HTTP版本信息b、请求首部字段c、请求内容实体d、空行 响应报文包含四部分&#xff1a; a、状态行&#xff1a;包含HTTP版本、状态码、状态码…

【从Python基础到深度学习】7. 使用scp命令实现主机间通讯

一、生成 SSH 密钥对 ssh-keygen 是一个用于生成 SSH 密钥对的命令行工具&#xff0c;用于身份验证和加密通信 ssh-keygen 二、将本地主机上的 SSH 公钥添加到远程主机 ssh-copy-id 命令用于将本地主机上的 SSH 公钥添加到远程主机上的 authorized_keys 文件中&#xff0c;…

《苍穹外卖》知识梳理P9-定时任务、来单提醒与用户催单

一.定时任务 实现定时任务可以使用spring家族中的sprinig-task&#xff1b; 1.1 spring-task spring-task是Spring框架的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑&#xff1b; 应用场景 信用卡每月归还贷款提醒&#xff0c;定时任务检查&#xff…

Jetpack Compose 第 2 课:布局

点击查看&#xff1a;Jetpack Compose 教程 点击查看&#xff1a;Composetutorial 代码 简介 Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API&#xff0c;可以帮助您简化并加快 Android 界面开发。 在本教程中&a…

【springboot+vue项目(十四)】基于Oauth2的SSO单点登录(一)整体流程介绍

场景&#xff1a;现在有一个前后端分离的系统&#xff0c;前端框架使用vue-element-template&#xff0c;后端框架使用springbootspringSecurityJWTRedis&#xff08;登录部分&#xff09;现在需要接入到已经存在的第三方基于oauth2.0的非标准接口统一认证系统。 温馨提示&…

html表格标签(下):lable标签,select标签和textara标签

html表格标签(下)&#xff1a;lable标签&#xff0c;select标签和textarea标签 lable标签 搭配 input 使用,点击 label 标签就能选中对应的单选/复选框, 能够提升用户体验。 for 属性: 指定当前 label 和哪个相同 id 的 input 标签对应 (此时点击才是有用的) 运行效果&#x…

php数组运算符 比较 isset、is_null、empty的用法和区别

php数组运算符 1. 数组运算符2. 判断两个数组是否相等3. isset、is_null、empty的用法和区别 1. 数组运算符 注意&#xff1a;只会保留第一个数组中的键值对&#xff0c;而忽略后面数组中相同键名的元素&#xff0c;如果想要合并两个数组并覆盖相同键名的元素&#xff0c;可以…

obsidian的Workbooks插件

学习目标&#xff1a; 学会使用obsidian 学习内容&#xff1a; obsidian咖啡豆教程 | Obsidian的Excel管理解密|Workbooks插件 直接在obsidian中插入表格编辑 但是在实际的使用过程中不好。虽然设置了自动保存&#xff0c;但是实际有时没有保存 读取外部excel文件进行修改 默…

【Jvm】性能调优(拓展)Jprofiler如何监控和解决死锁、内存泄露问题

文章目录 Jprofiler简介1.安装及IDEA集成Jprofiler2.如何监控并解决死锁3.如何监控及解决内存泄露(重点)4.总结5.后话 Jprofiler简介 Jprofilers是针对Java开发的性能分析工具(免费试用10天), 可以对Java程序的内存,CPU,线程,GC,锁等进行监控和分析, 1.安装及IDEA集成Jprofil…

VFH特征的使用(一)

一、SHOT特征描述符可视化 C #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d_omp.h> #include <pcl/registration/correspondence_estimation.h> #include <boo…

软件测试项目测试报告总结

测试计划概念&#xff1a;就在软件测试工作实施之前明确测试对象&#xff0c;并且通过资源、时间、风险、测试范围和预算等方面的综合分析和规划&#xff0c;保证有效的实施软件测试。 需求挖掘的6个方面&#xff1a; 1、输入方面 2、处理方面 3、结果输出方面 4、性能需求…

C语言学习day15:数组强化训练

题目一&#xff1a; 称体重&#xff1a;分别给10个值&#xff0c;来获得最大值 思路&#xff1a; 定义数组&#xff0c;给数组内赋10个值第一个下标的值与第二个下标的值进行比较定义max&#xff0c;将比较得来的较大的值赋值给max一直比较直到比较到最后一个下标&#xff0…

ubuntu22.04-磁盘管理-虚拟机动态扩容-系统monitor

文章目录 1.虚拟机2.ubuntu设置3.命令查看4.系统资源管理器1.虚拟机 关闭ubuntu22.04,然后修改虚拟机设置,如下图所示: 修改容量 2.ubuntu设置 搜索打开disks,如下图所示: 选择目标磁盘,选择调整大小到目标大小即可。

萝卜大杂烩 | 把微信接入ChatGPT,变成聊天机器人竟然这么简单!(一起来尝试吧~)

本文来源公众号“萝卜大杂烩”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;把微信接入ChatGPT&#xff0c;变成聊天机器人竟然这么简单&#xff01; 最近的 ChatGPT 又再次火热起来了&#xff0c;各种周边工具也是层出不穷&…

离谱!用ChatGPT进行审稿!

离谱&#xff01;用ChatGPT进行审稿&#xff01; 关注微信公众号: DeepGoAI 在这个信息爆炸的时代&#xff0c;AI已经跑到了学术会议的后台&#xff0c;偷偷摸摸地开始“帮忙”审稿了&#xff01;&#x1f916; 最近&#xff0c;一位教授的LinkedIn动态可谓是火了一把&#xf…

蜂蜜器实验-驱动代码测试

一. 简介 上一篇文章实现了蜂鸣器驱动代码&#xff0c;实现关闭蜂鸣器与打开功能。文章地址如下&#xff1a; 蜂鸣器驱动代码完善-CSDN博客 本文对所实现的蜂鸣器驱动代码进行测试。 二. 蜂鸣器驱动代码测试 1. 准备应用程序 这里应用程序还使用 前面实现所使用的Led应用…

2.18 day5 C++

以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系:比喻:动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲解员&#xff0c;他会为每种动物表演…

【C++初阶】值得一刷的字符串string相关oj题

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

Visual Studio+C#实现信道与信息率失真函数

1. 要求 设计一款信道与信息率失真函数计算系统&#xff0c;要求如下&#xff1a; 系统能够通过输入的转移概率矩阵计算对称以及非对称离散无记忆信道的信道容量系统能够通过输入的概率分布以及失真矩阵来计算与信息率失真函数有关的相关参数&#xff0c;例如Dmin&#xff0c…