【数据结构】布隆过滤器

SueWakeup

                                                     个人主页:SueWakeup

                                                     系列专栏:学习技术栈

                                                     个性签名:保留赤子之心也许是种幸运吧

本文封面由 凯楠📸 友情提供

目录

本栏传送门 

前言

1. 什么是布隆过滤器? 

2. 布隆过滤器的原理 

2.2 判断元素存在原理

3. 布隆过滤器使用场景 

4. 使用 Java 语言实现布隆过滤器 

测试用例

测试结果

注:手机端浏览本文章可能会出现 “目录”无法有效展示的情况,请谅解,点击侧栏目录进行跳转 


本栏传送门 

1.【技术栈】Redis 的理解与数据存储格式

2.【技术栈】Redis 中的事务及持久化方式

3.【技术栈】Redis 删除策略

4.【技术栈】Redis 企业级解决方案

5.【数据结构】布隆过滤器

6.【开发】SpringBoot 整合 Redis

7.【技术栈】Spring Cache 简化 Redis 缓存使用


前言

        在使用 Redis 作缓存时,可能出现 “缓存穿透对不存在于Redis的数据发起请求,恶意或者误操作地使得大量的请求穿透缓存直接访问数据库,导致数据库压力过大)” 问题。为了防止 Redis 缓存穿透,可以使用 “布隆过滤器” 避免大量不存在的 key 直接访问数据库。


1. 什么是布隆过滤器? 

布隆过滤器(Bloom Filter)是由 Burton Howard Bloom 于 1970 年提出的 “位数组” 和 “一组哈希函数” 两部分组成,用于检查元素是否存在于指定集合中的数据结构。

  • 优点:高效且性能很好。

        位数组中的每个元素都只占用 1 bit,并且每个元素只能是 0 或者 1。申请 100w 个元素的位数组只占用 1000000 Bit / 8 = 125000 字节 = 125000字节 / 1024 ≈ 122 字节 的空间。

  • 缺点:具有一定的误判性(错误识别率)和删除难度。理论情况下,添加到集合中的元素越多,误判的可能性越大。

2. 布隆过滤器的原理 

2.1 添加元素原理

  1. 使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(哈希值为多个)。
  2. 根据得到的哈希值,在位数组中把对应下标的值 “置为1”。

2.2 判断元素存在原理

  1. 对给定元素再次进行相同的哈希计算。
  2. 得到值之后判断位数组中的每个元素是否都为 1,如果都为 1,则说明这个元素可能存在于布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。

为什么说 “位数组” 中的每个元素都为1,这个元素可能存在于布隆过滤器中?

  • 一方面,判断元素存在需要对给定元素进行哈希计算,哈希计算的 “范围” 受 Integer 的MIN_VALUE(-2 ^ 31) 和 MAX_VALUE(2 ^ 31 - 1)影响,范围有限,不同的元素的哈希计算可能出现同一个哈希值。
  • 另一方面,在布隆过滤器 “添加元素” 时,我们会对给定元素进行多次哈希计算避免 “哈希冲突(哈希函数计算得到相同的哈希码)”,所以,两个不同的元素分别进行多次哈希计算,某次计算的哈希码在位数组的指向可能为同一个位置(如图所示)。

  • 故,位数组中的每个元素都为1,这个元素可能存在于布隆过滤器中。
  • 但是,都不为1,这个元素肯定不存在于布隆过滤器中。

这个说法,在后文中 “使用 Java 语言实现布隆过滤器” 有体现


3. 布隆过滤器使用场景 

  • 判断给定数据是否存在:  
    • 判断一个数字是否存在于 “包含大量数字” 的数字集合中(5 亿)。
    • 防止 “缓存穿透”(判断请求的数据是否有效避免直接绕过缓存请求数据库)。
    • 邮箱的垃圾邮件过滤、黑名单功能等。
  • 去重
    • 爬虫程序对已经爬取过的 URL 去重。

4. 使用 Java 语言实现布隆过滤器 

思路:

  1. 一个合适大小的位数组保存数据。
  2. 几个不同的哈希函数。
  3. 添加元素到位数组(布隆过滤器)的方法实现。
  4. 判断给定元素是否存在于位数组(布隆过滤器)的方法实现。
public class MyBloomFilter {// ①位数组的长度private static final int DEFAULT_SIZE = 2 << 24; //2^24// ③初始化位数组private BitSet bits =new BitSet(DEFAULT_SIZE);// ④一组哈希函数(哈希操作)private static final int[] SEEDS = new int[] {3,13,46,71,91,134}; // 散列的种子数组private SimpleHash[] hashOps = new SimpleHash[SEEDS.length];// ⑤过滤器构造方法public MyBloomFilter(){for(int i =0;i<hashOps.length;i++){hashOps[i] = new SimpleHash(DEFAULT_SIZE,SEEDS[i]);}}// ⑥添加元素public void add(Object value){for(SimpleHash sh :hashOps){bits.set(sh.hash(value),true);}System.out.println(bits);}// ⑦判断元素是否存在public boolean contains(Object value){boolean ret = true;for(SimpleHash sh : hashOps){ret = ret && bits.get(sh.hash(value));}return ret;}// ②哈希操作static class SimpleHash{private int cap; //容量private int seed; //种子public SimpleHash(int cap,int seed){this.cap = cap;this.seed = seed;}//哈希函数public int hash(Object value){int h;return value == null ? 0 : Math.abs(seed * (cap -1) & ((h =value.hashCode()) ^ (h >>>16)));}}
}

测试用例

public class BloomFilterTest {public static void main(String[] args) {MyBloomFilter myBloomFilter = new MyBloomFilter();myBloomFilter.add(131);myBloomFilter.add(110);myBloomFilter.add(120);myBloomFilter.add(119);myBloomFilter.add(114);System.out.println(myBloomFilter.contains(112));}
}

测试结果

{2, 129, 130, 131}
{2, 36, 40, 66, 98, 106, 108, 129, 130, 131}
{2, 32, 36, 40, 56, 66, 80, 98, 106, 108, 112, 120, 129, 130, 131}
{2, 32, 36, 37, 40, 49, 56, 66, 80, 82, 98, 106, 108, 112, 114, 115, 117, 120, 129, 130, 131}
{2, 32, 36, 37, 40, 48, 49, 56, 66, 80, 82, 98, 106, 108, 112, 114, 115, 117, 120, 129, 130, 131}
true

在此, “位数组” 中的每个元素都为1,这个元素可能存在于布隆过滤器中的说法 得到了验证。

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

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

相关文章

用虚拟机安装FydeOS,体验国内版ChromeOS首选!

前言 前段时间小白写了在实体机上安装FydeOS系统&#xff0c;发现有很多小伙伴在后台获取了FydeOS的镜像。 国内版ChromeOS&#xff1f;让旧机器焕发第二春的FydeOS安装教程 也有一些小伙伴看到是安装在实体机上的教程&#xff0c;所以就直接放弃了。其实FydeOS也可以用VM…

面试笔记——MySQL(事务:事务特性、并发事务、事务隔离、Redo Log与Undo Log、MVCC)

事务 概念与特性 事务&#xff08;Transaction&#xff09;指的是一组数据库操作&#xff0c;这些操作要么全部成功执行&#xff0c;要么全部不执行&#xff0c;保证了数据库的一致性和完整性&#xff0c;它使得数据库操作可以按照逻辑上的单元进行组织和执行&#xff0c;提高…

Flink:Lookup Join 实现与示例代码

本文要演示的是:在流上关联一张外部表(例如 MySQL 数据库中的一张维表),用于丰富流上的数据,实际上,这正是最普遍的 ”维表 Join“ 的实现方式。通过这种方式和外部维表关联时,依然能关联到最新变化的维度数据,所以才说这是 ”维表 Join“。Lookup Join 与 《Flink Tem…

中等职业学校大数据课程建设方案

大数据产业是以数据及数据所蕴含的信息价值为核心生产要素&#xff0c;通过数据技术、数据产品、数据服务等形式&#xff0c;使数据与信息价值在各行业经济活动中得到充分释放的赋能型产业。 大数据产业定义一般分为核心业态、关联业态、衍生业态三大业态。 一、专…

进程的概念介绍

一、进程 进程是计算机中运行的程序的实例。每个进程都有自己的内存空间、代码、数据和系统资源。进程可以独立运行&#xff0c;相互之间不会影响。 进程的基本概念包括&#xff1a; 1. 程序&#xff1a;进程是程序的一次执行&#xff0c;程序是存储在磁盘上的静态文件&#x…

Nginx实现原理全解析:构建高效Web服务器的关键

1、Nginx是什么 Nginx&#xff08;engine X&#xff09;是一个开源的轻量级的HTTP服务器&#xff0c;能够提供高性能的HTTP和反向代理服务。与传统的Apache服务器相比&#xff0c;在性能上Nginx占用系统资源更小、支持高并发&#xff0c;访问效率更高&#xff1b;在功能上&…

大学 Python 程序设计实验报告:字符串的输入和输出

一、实验目的 编写 Python程序&#xff0c;实现对简单文本的处理&#xff0c;掌握列表、元组、字典等组合类型的应用。 二、实验要求 掌握字符串的输入和输出。掌握使用切片的方式访问字符串中的值。掌握常见的字符串内建函数的应用。掌握列表、元组的应用。掌握字典、集合的…

Doris实战——工商信息查询平台的湖仓一体建设

目录 前言 一、架构1.0&#xff1a;传统Lambda架构 二、OLAP引擎调研 三、架构2.0&#xff1a;数据服务层All in Apache Doris 四、架构 3.0&#xff1a;基于Doris Multi-Catalog的湖仓一体架构 五、实践经验 5.1 引入Merge-on-Write&#xff0c;百亿级单表查询提速近三…

谷歌DeepMind推出3D游戏AI代理SIMA,实现自然语言操控游戏新纪元

近日&#xff0c;谷歌DeepMind研究团队推出了一款名为SIMA的创新AI代理&#xff0c;专为3D游戏环境设计。这款代理独树一帜&#xff0c;无需访问游戏源代码或依赖定制API&#xff0c;仅通过输入图像和简单的自然语言文本指令&#xff0c;便能实现与人类玩家相当的游戏操作。 AI…

LangChain教程 | langchain 文件加载器使用教程 | Document Loaders全集

提示&#xff1a; 想要了解更多有关内置文档加载器与第三方工具集成的文档&#xff0c;甚至包括了&#xff1a;哔哩哔哩网站加载器、区块链加载器、汇编音频文本、Datadog日志加载器等。 本文主要收集与讲解日常使用的加载器&#xff0c;足够咱们平时开发人工智能的工作使用&am…

【前端性能】前端性能指标和测量方法总结

文章目录 前端性能指标和测量方法总结重要指标名词概念指标测量方法performance APIChrome PerformanceChrome Lighthouseweb-vitals 前端性能指标和测量方法总结 重要指标名词概念 图源 https://dev.to/xnimorz/hitchhiker-s-guide-to-frontend-performance-optimization-460…

在Windows检查打开的TCP/IP端口可以使用内置工具,也可以使用第三方应用程序

前言 每当应用程序希望通过网络访问自己时,它都会声明TCP/IP端口,这意味着该端口不能被其他任何东西使用。那么,如何检查打开的端口以查看哪些应用程序已经在使用它? 我们已经测试了该过程,并确认所有步骤都是最新的,并且它们也都可以在Windows 11中工作。 端口如何工…

计算机+任何行业都等于王炸!

最近笔者刷到一则消息&#xff0c;一位测试员在某乎上分享&#xff0c;从月薪5K到如今的20K&#xff0c;他总共跳了10次槽&#xff0c;其中还经历过两次劳动申诉&#xff0c;拿到了大几万的赔偿&#xff0c;被同事们称为“职场碰瓷人”。 虽说这种依靠跳槽式的挣钱法相当奇葩&a…

Java微服务分布式事务框架seata的TCC模式

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

3/21作业

#include <myhead.h> int do_add(sqlite3 *ppDb) { int add_numb 0; char add_name[20] {0}; double add_score 0; printf("请输入学号:"); scanf("%d",&add_numb); printf("请输入姓名:"); scanf(&q…

Python机器学习019:sklearn中如何找到测试集中预测错误的样本在原数据中所在的索引位置

原理 要查看预测错误的 X_test 在原始数据集中的索引,你可以首先找到预测错误的样本索引,然后将这些索引映射回原始数据集的索引。 案例 from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metric…

鸿蒙ArkTS实战开发-Native XComponent组件的使用

介绍 本篇Codelab主要介绍如何使用XComponent组件调用NAPI来创建EGL/GLES环境&#xff0c;实现在主页面绘制一个正方形&#xff0c;并可以改变正方形的颜色。本篇CodeLab使用Native C模板创建。 如图所示&#xff0c;点击绘制矩形按钮&#xff0c;XComponent组件绘制区域中渲…

Sketch软件:重塑UI/UX设计流程的革命性工具

Sketch是一款在Mac操作系统上运行的矢量图形设计软件&#xff0c;其功能特色丰富多样&#xff0c;深受设计师们的喜爱。以下是Sketch软件的主要功能特色介绍&#xff1a; 专业矢量图形设计&#xff1a;Sketch为UI设计、移动应用设计和Web设计等领域提供了强大的支持。它支持线条…

了解OGC

什么是OGC OGC&#xff08;Open Geospatial Consortium&#xff09;是一个国际性的组织&#xff0c;专注于制定和发布开放的地理信息标准&#xff0c;以促进地理空间数据和服务的互操作性和共享。其目标是在全球范围内推动地理信息系统&#xff08;GIS&#xff09;和地理空间技…

串口控制LED灯

uart.c #include "uart4.h"void uart4_init() {//使能GPIOB GPIOG UART4外设时钟RCC->MP_AHB4ENSETR | (0x1<<1);//GPIOBRCC->MP_AHB4ENSETR | (0x1<<6);//GPIOGRCC->MP_APB1ENSETR | (0X1<<16);//UART4//设置PB2和PG11管脚复用//PB2GPI…