布隆过滤器的原理和应用场景
目录
1 原理
2 代码示例
3 位数组
4 布隆过滤器的实际应用场景
1 原理
布隆过滤器(Bloom Filter)是一种数据结构,用于快速判断一个元素是否存在于一个集合中,具有高效的插入和查询操作。它的设计目的是在空间效率和查询效率之间寻求一种折衷方案。
布隆过滤器基于位向量(bit array)和一系列的哈希函数。它适用于需要进行高速判断的场景,例如缓存系统、拼写检查、垃圾邮件过滤等。
布隆过滤器的原理如下:
-
初始化:创建一个大小为 m 的位向量,所有位初始化为 0。
-
插入:当要插入一个元素时,对该元素进行 k 次哈希函数计算,将对应的 k 个位设为 1。
-
查询:当要查询一个元素是否存在时,同样对该元素进行 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 位数组
这里提下位数组的概念以及与普通数组的区别
-
存储方式:
- 位数组:位数组中的每个元素只占用一个位(0 或 1),因此在存储上非常紧凑。它使用的是比特位来表示数据。
- 普通数组:普通数组中的每个元素可以是任意数据类型,比如整数、浮点数、对象等。根据数据类型的不同,存储占用的空间可能会更多。
-
存储内容:
- 位数组:通常用于表示某种状态、存在与否、开关等,每个位代表一个二进制信息,例如布尔值。
- 普通数组:存储任意数据类型,可以包含数字、字符串、对象等。
-
内存占用:
- 位数组:由于每个元素只占用一个位,因此在相同存储空间下,可以存储更多的元素,适用于需要存储大量布尔信息的情况。
- 普通数组:根据元素的数据类型和数量,占用的内存空间会更大。
-
使用场景:
- 位数组:适用于需要紧凑地表示某种状态或标记,如布隆过滤器、位图索引等。
- 普通数组:适用于存储多种数据类型的数组,如整数数组、字符串数组、对象数组等。
总之,位数组和普通数组的主要区别在于存储方式和存储内容。位数组通常用于紧凑地存储标志、状态等信息,而普通数组可以存储多种类型的数据。选择使用哪种类型的数组取决于具体的应用场景和需求。
4 布隆过滤器的实际应用场景
背景:我们知道,现如今的电商系统特别是像阿里旗下的、京东等肯定是需要面对高并发请求问题的,这时避免不了用到中间件技术例如Redis、MQ。而以某宝为例,即使在用户不登录的情况下,它是需要有一些开放的API供未登录用户去看的,如“/product/{id}”,表示界面上对应的商品。当商品特别多,且用户同时点击作请求的次数太大时,Redis作为缓存是让服务器能够稳定运行的前提。这看起来似乎是解决了高并发问题,且能够避免最影响整个系统服务性能的数据库被频繁访问。但对于黑客来说,这其中有个漏洞可钻。既然id是指商品的标识符,那我不断输入不存在的商品id,而Redis又发现缓存中没有这样的id,就会转向数据库作请求,如此这般,便造成了缓存穿透。所以,一个新的问题是:我要如何识别并处理这些不存在的id,避免让它们频繁“骚扰”数据库呢?这时布隆过滤器就这样闪亮登场了。
解决:
上面提到的缓存穿透,总结来讲是指在缓存中找不到所需的数据,导致每次请求都需要访问数据库或其他数据源,从而造成系统负担过大。这种情况可能是由于恶意请求、非法输入或者业务逻辑问题导致的。
布隆过滤器可以在缓存层面起到一定的预防作用,减轻缓存穿透带来的影响。具体来说,以下是布隆过滤器如何用于防止缓存穿透的细节:
-
在查询缓存前进行判断: 在查询缓存之前,先将查询的参数进行布隆过滤器的检查。如果布隆过滤器判断这个参数不在缓存的可能存在集合中,那么就不会去查询缓存,避免了不必要的数据库或其他数据源访问。
-
合法参数和非法参数的判断: 布隆过滤器可以帮助区分合法参数和非法参数。如果一个参数不在布隆过滤器中,说明它肯定是非法的,可以直接返回一个错误或默认值,而不会继续访问后端数据源。
-
动态更新布隆过滤器: 当缓存中的数据更新时,需要相应地更新布隆过滤器中的信息,以确保布隆过滤器的准确性。否则,布隆过滤器可能会误判某个参数在缓存中不存在。
需要注意的是,布隆过滤器虽然可以减轻缓存穿透问题,但并不是完全解决方案。它可以用来过滤掉一部分明显无效的请求,但不能保证百分之百防止缓存穿透。在实际应用中,布隆过滤器通常与其他技术一起使用,如合理设置缓存过期时间、使用缓存预热等,来综合解决缓存穿透问题。
其它的应用场景包括拼写检查、垃圾邮件过滤等
相关文章:
布隆过滤器的原理和应用场景
目录 1 原理 2 代码示例 3 位数组 4 布隆过滤器的实际应用场景 1 原理 布隆过滤器(Bloom Filter)是一种数据结构,用于快速判断一个元素是否存在于一个集合中,具有高效的插入和查询操作。它的设计目的是在空间效率和查询效率之…...

ElasticSearch学习
一,简介 ES(elaticsearch简写), Elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据…...
软件测试基础篇——Redis
Redis Redis数据库的配置与连接 解压redis数据库的安装包(建议把解压后的安装包放到磁盘的根目录,方便访问操作)打开【命令行窗口】:winR在命令行窗口,进入到redis安装目录中 格式一:cd /d redis目录…...

大数据扫盲(1): 数据仓库与ETL的关系及ETL工具推荐
在数字化时代,数据成为了企业决策的关键支持。然而,随着数据不断增长,有效地管理和利用这些数据变得至关重要。数据仓库和ETL工具作为数据管理和分析的核心,将帮助企业从庞杂的数据中提取有价值信息。 一、ETL是什么? …...

spring的aop动态代理对象注入时机
bean生命周期: bean实例化populateBean填充属性invokeAwareMethods调用aware方法postProcessBeforeInitialization后置处理器before方法initializeBean初始化beanpostProcessAfterAfterInitialization后置处理器after方法 代理对象注入有两种情况:提前和…...

idea集成svn
一、注意 安装svn客户端的时候一定要勾选,否则在idea上集成svn的时候会找不到 svn.exe 而报错。 如果当初安装时忘记勾选,重新运行安装包,选择modify,勾选command line client tools项中的内容。 二、配置idea集成svn 三、检出(c…...

RedisDesktopManage
RDM 简介下载安装 简介 RedisDesktopManager(RDM)是一个开源的跨平台图形界面工具,用于管理和操作 Redis 数据库。它提供了一个用户友好的界面,使用户能够轻松地连接、浏览、查询和修改 Redis 数据,而无需使用命令行界…...

《Vue.js实战》——基础篇(1)
目录 资源:🌟 一、初识Vue.js👋 Vue.js是什么?🙇 MVVM模式 ✍ Vue.js有什么不同 ☔ 如何使用Vue.js? ☁ 传统的前端开发模式 ☀ Vue.js的开发模式 🗻 二、数据绑定和第一个Vue应用 Ὗ…...

R语言 列表中嵌套列名一致的多个数据框如何整合为一个数据框
在批量建模后容易得到list,list中的每个元素都是单个的tibble 或者 dataframe,如何将这些数据整合为一张表呢? 载入R包 library(broom) library(tidyverse) 模拟数据 models <- txhousing %>% group_by(city) %>% do(modlm(lo…...

PyQt5利用QTextEdit控件输入多行文本
1、总代码 #!/usr/bin/env python # -*- coding: utf-8 -*- import sys from PyQt5.QtWidgets import QApplication,QWidget from PyQt5 import QtCore, QtWidgetsclass Ui_Form(object):def setupUi(self, Form):Form.setObjectName("Form")Form.resize(320, 240)s…...

【数据结构】二叉树常见题目
文章目录 前言二叉树概念满二叉树完全二叉树二叉搜索树(二叉排序树)平衡⼆叉搜索树存储⽅式 二叉树OJ二叉树创建字符串二叉树的分层遍历1二叉树的分层遍历2给定一个二叉树, 找到该树中两个指定节点的最近公共祖先二叉树搜索树转换成排序双向链表二叉树展开为链表根据一棵树的前…...

树莓派使用 ENC28J60
前言 一些老的、Mini 的 ARM 开发板上没有预留网口,这样在调试升级内核或应用程序时很不方便。纵使有串口下载工具,但其速度也是慢地捉急。这种情况下,使用其它接口来扩展出一个网口无疑是一个比较好的方法。 ENC28J60 就是一个使用 SPI 接口…...
跟我学C++中级篇——模板友元的应用
一、友元 友元在以前分析过,而且一般编程是不推荐使用友元的,原因是友元破坏了类的封装性。但凡事总有例外,在某些情况下,用友元还是比较方便的,那么该用还得用,不能因噎废食。普通的友元,各种…...

软件测试基础篇——MySQL
MySQL 1、数据库技术概述 数据库database:存放和管理各种数据的仓库,操作的对象主要是【数据data】,科学的组织和存储数据,高效的获取和处理数据SQL:结构化查询语言,专为**关系型数据库而建立的操作语言&…...

FreeRTOS(二值信号量)
资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、信号量的概念 1、信号量的基本概念 2、信号量的分类 二、二值信号量的定义与应用 1、二值信号量的定义 2、二值信号量的应用 三、二值信号量的运作机制 1、FreeRTOS任务间二值…...
leetcode面试题:动物收容所(考查对队列的理解和运用)
题目: 有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时…...

【Linux命令行与Shell脚本编程】第十八章 文本处理与编辑器基础
Linux命令行与Shell脚本编程 第十八章 文本处理与编辑器基础 文章目录 Linux命令行与Shell脚本编程第十八章 文本处理与编辑器基础 文本处理与编辑器基础8.1.文本处理8.1.1.sed编辑器8.1.1.1.在命令行中定义编辑器命令8.1.1.2.在命令行中使用多个编辑器命令8.1.1.3.从文件中读…...

2023牛客暑期多校训练营7
Beautiful Sequence 贪心,二进制,构造 Cyperation 模拟 ,数学 We Love Strings 分块,二进制枚举,二进制容斥dp Writing Books 签到 根据相邻两个异或值B,因为前小于等于后,故从高到低遍历B的每一…...

centos7升级glibc2.28
1 概述 centos7自带的glibc对于某些软件是太旧的,决定将glibc升级至2.28。 2 安装过程 2.1 下载glibc源码 mkdir -p /opt/third-party && cd /opt/third-party wget http://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.gz tar -xf glibc-2.28.tar.gz cd glibc…...

腾讯云香港服务器租用_2核2G20M_2核4G30M
腾讯云香港服务器租用费用表,目前中国香港地域轻量应用服务器可选配置2核2G20M、2核2G30M、2核4G30M,操作系统可选Windows和Linux,不只是香港云服务器,新加坡、硅谷、法兰克福和东京服务器均有活动,腾讯云服务器网分享…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...