【Redis】布隆过滤器原理与应用

news2024/12/23 18:57:10

文章目录

  • 原理
  • 应用
  • 实战
  • 总结

布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。
它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难

原理

在谈到原理之前,我们先来看看布隆过滤器的数据结构,它是一个bit数组。如下图所示:

在这里插入图片描述

这是一个长度为8,默认都是0的bit数组。如果我们想要映射一个值到布隆过滤器中,怎么操作呢?首先是使用多个不同的哈希函数生成多个哈希值,再把哈希值指向的bit位置1。例如:我们要将值“baidu”映射到布隆过滤器上,怎么操作呢?假如我们使用三个不同的哈希函数生成了三个哈希值分别是:1、3、6,那么上图就转变为下图这样:

在这里插入图片描述

从图中看出,标有浅蓝色的bit位的值都被置为1,表示该数据已经映射上了。接着我们再把值“alibaba”和三个不同哈希函数生成的值:2、6、8映射到上面布隆过滤器中,它就会变为下图的样子:

在这里插入图片描述

很显然,它把之前映射的哈希值6覆盖了,这就是布隆过滤器是有误报率的一个因素。如果这时候,我们想拿一个未插入映射的值“tencent”查询它是否在上面布隆过滤器中存在。该怎么操作呢?首先,把值“tencent”用上面三个不同哈希函数生成三个哈希值分别是:2、4、6;再去布隆过滤器上找这三个值对应的bit位的值是否都是1,我们发现2和6都返回了1,而4返回0,说明值“tencent”没有做过映射,即不存在。实际上我们并没有事先做过此值的插入映射操作。这当然是正确的。

总结:布隆过滤器的原理是,当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点(offset),把它们置为 1。检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在。这就是布隆过滤器的基本思想。

简单来说就是准备一个长度为 m 的位数组并初始化所有元素为 0,用 k 个散列函数对元素进行 k 次散列运算跟 len(m)取余得到 k 个位置并将 m 中对应位置设置为 1。

SO:当我们搜索一个值的时候,若该值经过 K 个哈希函数运算后的任何一个索引位为 ”0“,那么该值肯定不在集合中。但如果所有哈希索引值均为 ”1“,则只能说该搜索的值可能存在集合中

应用

在实际工作中,布隆过滤器常见的应用场景如下:

  • 网页爬虫对 URL 去重,避免爬取相同的 URL 地址;
  • 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱;
  • Google Chrome 使用布隆过滤器识别恶意 URL;
  • Medium 使用布隆过滤器避免推荐给用户已经读过的文章;
  • Google BigTable,Apache HBbase 和 Apache Cassandra 使用布隆过滤器减少对不存在的行和列的查找。 除了上述的应用场景之外,布隆过滤器还有一个应用场景就是解决缓存穿透的问题。所谓的缓存穿透就是服务调用方每次都是查询不在缓存中的数据,这样每次服务调用都会到数据库中进行查询,如果这类请求比较多的话,就会导致数据库压力增大,这样缓存就失去了意义。
  • 解决缓存穿透

利用布隆过滤器我们可以预先把数据查询的主键,比如用户 ID 或文章 ID 缓存到过滤器中。当根据 ID 进行数据查询的时候,我们先判断该 ID 是否存在,若存在的话,则进行下一步处理。若不存在的话,直接返回,这样就不会触发后续的数据库查询。需要注意的是缓存穿透不能完全解决,我们只能将其控制在一个可以容忍的范围内。

实战

依赖:

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

在导入 Guava 库后,我们新建一个 BloomFilterDemo 类,在 main 方法中我们通过 BloomFilter.create 方法来创建一个布隆过滤器,接着我们初始化 1 百万条数据到过滤器中,然后在原有的基础上增加 10000 条数据并判断这些数据是否存在布隆过滤器中:

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

public class BloomFilterDemo {
    public static void main(String[] args) {
        int total = 1000000; // 总数量
        BloomFilter<CharSequence> bf = 
          BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), total);
        // 初始化 1000000 条数据到过滤器中
        for (int i = 0; i < total; i++) {
            bf.put("" + i);
        }
        // 判断值是否存在过滤器中
        int count = 0;
        for (int i = 0; i < total + 10000; i++) {
            if (bf.mightContain("" + i)) {
                count++;
            }
        }
        System.out.println("已匹配数量 " + count);
    }
}

打印结果:
已匹配数量 1000309

很明显以上的输出结果已经出现了误报,因为相比预期的结果多了 309 个元素,误判率为:
309/(1000000 + 10000) * 100 ≈ 0.030594059405940593

如果要提高匹配精度的话,我们可以在创建布隆过滤器的时候设置误判率 fpp:

BloomFilter<CharSequence> bf 
    = BloomFilter.create(   Funnels.stringFunnel(Charsets.UTF_8), total, 0.0002 );

在 BloomFilter 内部,误判率 fpp 的默认值是 0.03:

// com/google/common/hash/BloomFilter.class 
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) {   return create(funnel, expectedInsertions, 0.03D); } 

在重新设置误判率为 0.0002 之后,我们重新运行程序,这时控制台会输出以下结果:
已匹配数量 1000003

通过观察以上的结果,可知误判率 fpp 的值越小,匹配的精度越高。当减少误判率 fpp 的值,需要的存储空间也越大,所以在实际使用过程中需要在误判率和存储空间之间做个权衡。

总结

本文主要介绍的布隆过滤器的概念和常见的应用场合,在实战部分我们演示了 Google 著名的 Guava 库所提供布隆过滤器(Bloom Filter)的基本使用,同时我们也介绍了布隆过滤器出现误报的原因及如何提高判断准确性。最后为了便于大家理解布隆过滤器,我们介绍了一个简易版的布隆过滤器 SimpleBloomFilter。

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

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

相关文章

AJAX实现搜索联想 自动补全

分析: 1.想实现联想搜索需要数据库的数据支撑,需要进行模糊查询,搜索出所有包含用户输入的关键字信息,并将这些信息都反馈到前端,简化用户输入,从而提高用户的体验。 2.为了提高用户的使用体验&#xff0c;整个页面不能全部刷新&#xff0c;需要局部刷新&#xff0c;为此需要…

Python中的各种报错-一般错误

目录 ValueError: check_hostname requires server_hostname missing 1 required positional argument: self xxx is not a package libpng warning: iCCP: cHRM chunk does not match sRGB check_hostname requires server_hostname python 安装第三方库&#xff0c;超时…

MQTTC数据桥接上云

[小 迪 导 读]&#xff1a;在工业物联网蓬勃发展的背景下&#xff0c;私有化部署已经不能满足当前的发展趋势了&#xff0c;因此dgiot在原有基础上进行创新&#xff0c;将私有化部署的区域数控一体机上的数据通过mqtt桥接的方式上传到云服务器上&#xff0c;完成数据的实时同步…

Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明一

Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明一 Baumer工业相机Baumer工业相机图像采集功能Baumer工业相机图像基本参数设置 Baumer工业相机 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、…

【前端提效】-- Chrome浏览器开发者工具使用技巧

介绍一下 DevTools 的一些好用的技巧&#xff0c;它能够很好地帮助你提高生产力和解决问题的能力。 1、打开命令行 或者使用&#xff1a;快捷键 Ctrl Shift P (Mac&#xff1a; ⌘ Shift P ) 命令行可以做很多事情&#xff0c;包括但不限于截图、更换主题等 2、控制 DevT…

暑假线上兼职:300-500元/小时,安利一个大学生也能月入8K的线上兼职

在后台经常收到这样的留言&#xff1a; 快接近暑假了&#xff0c;有没有线上兼职推荐&#xff1f; 如何提升自己的眼界和能力&#xff0c;为之后的职场铺路&#xff1f; 不知道有多少朋友是想提升自己获取资源信息的速度&#xff0c;发展自己的爱好&#xff0c;或者增加第二收入…

用友U8增加查询条件

1、检查要增加的条件是否在该表单中&#xff1b; 2、在查询条件中增加查询条件的管理方案 3、参照ID就是要参照的表 4、数据源&#xff0c;在要增加的表单数据库中查询该字段名&#xff0c;进行增加即可。 select * from purbillvouch where cpbvcode 0000000312 --PurBillV…

调用legend资源,生成地图图例

作者&#xff1a;lly 文章目录 前言一、接口详情二、具体实现三、结果展示 前言 最近很多小伙伴资源关于iServer图例的问题&#xff0c; 接下来我们就来介绍下如何使用iServer legend资源&#xff0c;生成地图图例 一、接口详情 请求示例 {"layerLegends": [{&quo…

达索的天线设计和仿真软件Antenna Magus 2023版本下载与安装配置教程

目录 前言一、Antenna Magus安装二、使用配置总结 前言 Antenna Magus软件是一款用于天线设计和仿真的软件&#xff0c;提供了一个全面的设计工具集&#xff0c;帮助工程师优化天线设计&#xff0c;同时减少设计周期。 Antenna Magus的主要特点&#xff1a; ——高级天线库&…

如何用 ChatGPT 帮你自动分析数据?

误判 好几天之前&#xff0c;我就在 ChatGPT 选单里看到了 Code Interpreter。它正在灰度测试中 —— 先给一部分用户试用&#xff0c;如果反响不错并做了一定改进&#xff0c;就能推广给更多用户。 可惜当时我没能正确理解它的含义&#xff0c;犯了一个大错误 —— 望文生义。…

ChatGPT 上线联网和插件功能;投资者看好新版搜索引擎

&#x1f680; ChatGPT 上线联网和插件功能 OpenAI宣布将在这周推出联网和插件功能&#xff0c;位于Alpha和Beta通道的ChatGPT Plus用户都可使用70多个上线的插件。 更新意味着ChatGPT将利用最新的信息和资讯为使用者提供服务。 上线的ChatGPT插件种类涵盖了行程安排助理、代…

Android开发-Android常用组件-Date Time组件

4.11 Date & Time组件 1.TextClock(文本时钟) TextClock是在Android 4.2(API 17)后推出的用来替代DigitalClock的一个控件&#xff01; TextClock可以以字符串格式显示当前的日期和时间&#xff0c;因此推荐在Android 4.2以后使用TextClock。 这个控件推荐在24进制的and…

[内网]RDP远程桌面密码凭证获取

文章目录 RDP保存凭据通过注册表查看当前主机本地连接过的目标机器记录查看当前主机保存的RDP凭据查看本地用户是否存有RDP密码文件通过密码文件获取guidMasterKey的值根据guidMasterKey找到对应Masterkey解密获取明文以上总结&#xff1a; 在授权渗透过程中&#xff0c;如果获…

PCB当中的跳线有什么作用

在PCB设计中&#xff0c;跳线是一种常见的连接方式。跳线是为了连接电路中的距离较远或无法直接连接的电路元件而设置的&#xff0c;其作用是非常重要的。在本文中&#xff0c;我们将探讨PCB中跳线的作用和应用。 一、什么是跳线 跳线是一种特殊的电路连接方式&#xff0c;它是…

EXCEL 0开头的数据处理

方法一&#xff1a;从数据库中存为csv 再新建一个EXCEL 数据——从文本/CSV 方法二&#xff1a; 在数据库里面加A&#xff0c;在EXCEL里面将A替换成 上单引号 ‘

【002】C++的关键字介绍

C的关键字介绍 引言一、关键字一览表二、数据类型相关的关键字三、存储相关的关键字四、控制语句相关的关键字总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计和开发&#xff0c;理论与代码实践结合&#xff0c;让世界没有难学的技术。包括C/C、Linux、M…

CentOS7搭建keepalived+DRBD+NFS高可用共享存储

一、服务器信息 IP地址 类型 主机名 操作系统 内存 磁盘 192.168.11.110 主服务器 node01 CentOS7.9 2G 系统盘20G 存储盘20G 192.168.11.111 备服务器 node02 CentOS7.9 2G 系统盘20G 存储盘20G 二、两台主机…

新王诞生!ACP世界大赛中国区总决赛超燃收官!

“夺最高的冠&#xff0c;摘最亮的星&#xff01;” 2023 Adobe Certified Professional 世界大赛中国区总决赛 冠军诞生&#xff01; 2023ACP世界大赛中国区总决赛于5月13日-5月14日在苏州西交利物浦大学举办&#xff0c;历时2天的精彩角逐&#xff0c;于今日圆满收官&…

socket各个结构体及其参数

1.sockaddr_in结构体 //老的结构体 struct sockaddr{unsigned short sa_family; //地址类型,AF_xxxchar sa_data[14]; //14字节的端口和地址 }struct sockaddr_in{short int sin_family; //地址类型unsigned short int sin_port; //端口号st…

如何在项目中自定义注解实现权限数据管理案例

如何在项目中自定义注解实现权限数据管理案例 一、准备工程基本功能1. 创建工程并添加依赖2. 配置数据库信息3. Mybatis-Plus 代码生成器生成基本项目结构4. 因为项目中引入了spring-security&#xff0c;所有接口被保护了&#xff0c;所以用户实体和service分别实现UserDetail…