布隆过滤器原理介绍和典型应用案例

整理自己过去使用布隆过滤器的应用案例和理解

基本介绍

        1970年由布隆提出的一种空间效率很高的概率型数据结构,它可以用于检索一个元素是否在一个集合中,由只存0或1的位数组和多个hash算法, 进行判断数据   【一定不存在或者可能存在的算法】

如果这些bit数组 有任何一个0,则被判定的元素一定不在;  如果都是1则被检元素很可能在

对比bitmap位图,布隆过滤器适合更多类型元素,通过hash值转换

原理:将元素添加到一个bitmap数组中,每个散列函数将元素映射到bitmap数组中的一个位置。如果该位置已经被占用,则将该位置置为1,否则置为0。当要查询一个元素是否存在时,只需要计算该元素的散列值,并检查bitmap数组中对应的位置是否已经被置为1。如果都是1,则该元素可能存在,否则肯定不存在。不存在的一定不存在,存在的不一定存在

优点:占用空间小,查询速度快,空间效率和查询时间都远远超过一般的算法。

缺点:有一定的误识别率,有一定的误识别率,即某个元素可能存在,但实际上并不存在。删除困难,因为无法确定某个位置是由哪个元素映射而来的。

 在线案例:Bloom Filters

布隆过滤器存在误判率,数组越小,所占的空间越小,误判率越高;如果要降低误判率,则数组越长,但所占空间越大
最大限度的避免误差, 选取的位数组应尽量大, hash函数的个数尽量多, 但空间占用的浪费和性能的下降
业务选择的时候, 需要误判率与bit数组长度和hash函数数量的平衡
布隆过滤器不能直接删除元素,因为所属的bit可能多个元素有使用
如果要删除则需要重新生成布隆过滤器,或者把布隆过滤器改造成带引用计数的方式 

应用场景

解决海量数据下非精确过滤的业务场景 

1)垃圾邮件解决方案(垃圾短信、黑名单同理)

        收集一组具有特定特征的垃圾邮件样本,这些样本可以是文本内容或其他特征,比如发件人、收件人等,将这些样本的特征信息进行哈希处理,并将处理后的结果存储在布隆过滤器中。接下来,当有新的电子邮件到达时,将该邮件的特征信息也进行哈希处理,并且与布隆过滤器中的信息进行比较。如果布隆过滤器中存在该邮件的特征信息,则判断该邮件为垃圾邮件;如果不存在,则判断该邮件为正常邮件

2)解决缓存穿透解决方案

        什么是缓存穿透(查询不存在数据),查询一个不存在的数据,由于缓存是不命中的,如发起为id为“-1”不存在的数据。如果从存储层查不到数据则不写入缓存,导致这个不存在的数据每次请求都要到存储层去查询,大量查询不存在的数据,可能DB就挂掉了,是黑客利用不存在的key频繁攻击应用的一种方式。

       方案就是将所有要【缓存的数据】经过处理后存储布隆过滤器中,即对应的bit上是1,当外部请求发起时,首先会把请求的参数通过哈希算法处理,获得相应的哈希值;根据哈希值计算出位数组中的位置。

如果全部计算的hash值对于的bit存储都是1,则表示数据在合理中,从缓存读出(缓存失效则从数据库中取出);

如果计算的hash值对于的bit存储存在一个是0或以上,则表示这条数据不合理,直接返回数据不存在,不查缓存和数据库,如果布隆过滤器认为值不存在,那么值一定是不存在的,无需查询缓存也无需查询数据库;

3)爬虫URL去重解决方案

        需求:大量的网页爬取,通过解析已经爬取页面中的网页链接,然后再爬取这些链接对应的网页,同一个网页链接有可能被包含在多个页面中,会导致爬虫在爬取的过程中,重复爬取相同的网页;

        方案:创建布隆过滤器,根据业务数据量设置位数组的大小,将位数组全部设置为0;
将每个URL地址通过哈希算法处理,获得相应的哈希值;
根据哈希值计算出位数组中的位置,将位数组中的位置设置为1;
当新的URL地址进入时,重复上述步骤计算出对应的位置,检查位数组中的位置是否为0,如果是0,则表示该URL地址一定没被爬取过;
如果URL地址不存在,经过爬虫处理后,则将其对应的位置设置为1,以表示该URL地址已经存在;
重复上述步骤,直到所有的URL地址都处理完毕,完成去重。

POM 依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency></dependencies>
 @Testpublic void testGeneUrl() {try{File file = new File("urls.txt");if (!file.exists()) {file.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖}FileOutputStream fos = new FileOutputStream(file, true);OutputStreamWriter osw = new OutputStreamWriter(fos);BufferedWriter bw = new BufferedWriter(osw);StringBuilder builder = new StringBuilder();for (int i = 0; i < 5000000; i++) {String name = RandomStringUtils.randomAlphabetic(5);String fileName = "https://www." + name + ".com" + i + "\n";builder.append(fileName);}bw.write(String.valueOf(builder));bw.newLine();bw.flush();bw.close();osw.close();fos.close();} catch (FileNotFoundException e1) {e1.printStackTrace();} catch (IOException e2) {e2.printStackTrace();}}

//参数一: 指定布隆过滤器中存的是什么类型的数据,有 IntegerFunnel,LongFunnel,StringCharsetFunnel
//参数二: 预期需要存储的数据量
//参数三: 误判率,默认是 0.03
BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), 5000000, 0.01);

 4)分库分表下手机号重复注册解决方案

        一般业务里面的partitionKey是不可变动的,所以不能用手机号作为分片键(换手机号需求是存在的),所以业务里面的分片键,多数是固定的业务id,比如user_id

创建布隆过滤器,根据业务数据量设置位数组的大小,将位数组全部设置为0;
把要注册的手机号通过通过哈希算法处理,获得相应的哈希值;
根据哈希值计算出位数组中的位置,如果对应的位数组中的位置有存在0,则一定是未注册的
如果经过多个hash函数处理,对应的位数组中都是1,则认为是注册过的
最后如果用户注册成功后,将位数组中的位置设置为1

@Beanpublic Set set() throws IOException {Set<String> set = new LinkedHashSet<>();FileInputStream inputStream = new FileInputStream(new File("urls.txt"));InputStreamReader streamReader = new InputStreamReader(inputStream);BufferedReader reader = new BufferedReader(streamReader);String line = null;while (true) {line = reader.readLine();if (line != null) {set.add(line);} else {break;}}inputStream.close();return set;}@Beanpublic BloomFilter bloomFilter() throws IOException {BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF-8")), 5000000, 0.01);FileInputStream inputStream = new FileInputStream(new File("urls.txt"));InputStreamReader streamReader = new InputStreamReader(inputStream);BufferedReader reader = new BufferedReader(streamReader);String line = null;while (true) {line = reader.readLine();if (line != null) {bloomFilter.put(line);} else {break;}}inputStream.close();return bloomFilter;}@RestController
@RequestMapping("/api")
public class FilterController {@Autowiredprivate BloomFilter<String> bloomFilter;@Autowiredprivate Set set;@GetMapping("/bloom")public String list() throws IOException {//判断是否包含这个内容if (bloomFilter.mightContain("https://www.dhVrX.com5")) {return "命中了";} else {return "没命中";}}@GetMapping("/set")public String set() {if (set.contains("httssps://www.shncb.com999663")) {return "命中了";} else {return "没命中";}}}

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

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

相关文章

【机器学习300问】43、回归模型预测效果明明很好,为什么均方根误差很大?

一、案例描述 假设我们正在构建一个房地产价格预测模型&#xff0c;目标是预测某个城市各类住宅的售价。模型基于大量房屋的各种特征&#xff08;如面积、地段、房龄、楼层等&#xff09;进行训练。 回归模型在大部分情况下对于住宅价格预测非常精准&#xff0c;用户反…

java Flink(四十三)Flink Interval Join源码解析以及简单实例

背景 之前我们在一片文章里简单介绍过Flink的多流合并算子 java Flink&#xff08;三十六&#xff09;Flink多流合并算子UNION、CONNECT、CoGroup、Join 今天我们通过Flink 1.14的源码对Flink的Interval Join进行深入的理解。 Interval Join不是两个窗口做关联&#xff0c;…

2.Redis有五种主要的数据类型

Redis有五种主要的数据类型 String&#xff08;字符串&#xff09;&#xff1a;String类型是最简单的数据类型&#xff0c;可以存储任意类型的数据&#xff0c;例如整数、浮点数、字符串等。String类型支持一些基本的操作&#xff0c;如设置值、获取值、增减值等。 Hash&#…

论文笔记:Llama 2: Open Foundation and Fine-Tuned Chat Models

导语 Llama 2 是之前广受欢迎的开源大型语言模型 LLaMA 的新版本&#xff0c;该模型已公开发布&#xff0c;可用于研究和商业用途。本文记录了阅读该论文的一些关键笔记。 链接&#xff1a;https://arxiv.org/abs/2307.09288 1 引言 大型语言模型&#xff08;LLMs&#xff…

cesium Clock JulianDate 日照分析

cesium在初始化的时候会自动把Clock对象挂载到容器上Clock内部以JulianDate维护时间&#xff0c;比北京时间慢8个小时&#xff0c;想显示北京时间需要计算时差JulianDate的日期部分和秒数部分是分开的 julianDayNumber&#xff1a;指整数天&#xff0c;记录从公元前4713年正午以…

【蓝桥杯】第15届蓝桥杯青少组stema选拔赛C++中高级真题答案(20240310)

一、选择题 第 1 题 第 2 题 表达式1000/3的结果是( A )。 A.333 B.333.3 C.334 D.333.0 第 3 题 下列选项中&#xff0c;判断a等于1并且b等于1正确的表达式是( B )。 A.!((a!1)&&(b!1)) B.!((a!1)||(b!1)) C.!(a1)&&(b1) D.(a1)&&(b1) 【解析】 A…

我的春招求职面经

智能指针在面试时经常被问到&#xff0c;最近自己也在写&#xff0c;有一点思考&#xff0c;于是找到了这样一个题目&#xff0c;可以看看&#xff0c;上面这个代码有什么问题&#xff1f;留言区说出你的答案吧&#xff01; 最后分享一下之前的实习->春招->秋招等文章汇总…

huggingface的transformers训练bert

目录 理论 实践 理论 https://arxiv.org/abs/1810.04805 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是一种自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;由Google在2018年提出。它是基于Transformer模型的预训练方法…

YOLOv9有效改进|CVPR2023即插即用的到残差注意力机制(轻量化注意力机制)Inverted Residual Mobile Block

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 在YOLOv9中加入CVPR2023即插即用的到残差注意力机制。 二、模块详解 2.1 模块简介 Inverted Residual Mobile Block结合了倒置残差块…

JavaEE企业开发新技术3

目录 2.11 Method的基本操作-1 文字性概念描述 代码&#xff1a; 2.12 Method的基本操作-2 2.13 Method的基本操作-3 2.14 数组的反射操作-1 文字性概念&#xff1a; 代码&#xff1a; 2.15 数组的反射操作-2 学习内容 2.11 Method的基本操作-1 文字性概念描述 Me…

SSM整合Springboot

1.0 概述 1.1 持久层&#xff1a; DAO层&#xff08;mapper&#xff09; DAO层&#xff1a;DAO层主要是做数据持久层的工作&#xff0c;负责与数据库进行联络的一些任务都封装在此 DAO层的设计首先是设计DAO的接口&#xff0c; 然后在spring-mapper.xml的配置文件中定义此接…

“低代码+平台”:驱动企业数字化转型与创新的新引擎

“低代码平台”作为一种新兴的软件开发范式&#xff0c;正逐渐成为企业快速响应市场变化、优化业务流程、提升数字化水平的重要手段。它的价值在于&#xff0c;将传统软件开发的复杂性大大降低&#xff0c;赋予了非技术人员或轻量级开发者快速构建应用的能力&#xff0c;并能灵…

【vue-小知识】var、let 和 const之间的区别

文章目录 结论1、重复定义变量名var&#xff1a;允许重复定义变量名let和const&#xff1a;不可以重复定义变量名 2、修改值var&#xff1a;允许修改值let&#xff1a;允许修改值const&#xff1a;不允许修改值&#xff0c;会报错 3、变量提升var : 支持变量提升let和const&…

吃瓜Grok大模型

段子区 今年当地时间2月29日晚&#xff0c;马斯克闹出来一件大事——正式起诉OpenAI和Sam Altman&#xff0c;并要求OpenAI 恢复开源GPT-4等模型。国际流量大师我只付服马斯克和川宝!&#xff01; 当大家觉得这扯皮的故事就此结束后&#xff0c;马斯克“不负众望”的整了一个大…

【网络取证箱】网络取证在线分析工具箱

【网络取证箱】网络取证在线分析工具箱 在线网站查询工具箱&#xff0c;没什么介绍的&#xff0c;所见即所得&#xff0c;在本文档里补充了其它一些网络安全资源&#xff0c;请忽用于非法活动&#xff0c;仅供学习研究—【蘇小沐】 &#xff08;一&#xff09;Whois查询 主要…

docker 进入容器内部命令

docker容器运行了&#xff0c;怎么进入容器内部查看内部的文件情况呢&#xff1f; 答&#xff1a;可以通过docker exec 的命令查看。 docker exec --help 可以查看命令介绍 &#xff1a; docker exec -it XXX /bin/bash XX为容器ID 进入容器内部 /bin/bash是需要添加的 不…

Java NIO和IO之间的区别

前言 NIO&#xff08;New IO&#xff09;&#xff0c;这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的&#xff0c;但实现方式不同&#xff0c;NIO主要用到的是块&#xff0c;所以NIO的效率要比IO高很多。在Java API中提供了两套NIO&#xff0c;一套是针对标准输入输出…

Vue3中基本数据类型为什么需要.value,,,引用类型不需要.value

1、在v3中使用基本数据类型&#xff08;如数字、字符串、布尔值&#xff09;时&#xff0c;如果你希望响应式地更新数据并触发视图更新,需要使用ref包裹基本数据类型,然后将基本数据类型转化为响应式对象;- - - 因此当你使用ref包裹基本数据类型时,实际上得到的是一个包含.valu…

B002-springcloud alibaba 微服务环境搭建

目录 创建父工程创建基础模块创建用户微服务创建商品微服务创建订单微服务微服务调用 创建父工程 新建项目springcloud-alibaba&#xff0c;本工程不需要写代码&#xff0c;删除src 导包 <parent><groupId>org.springframework.boot</groupId><artifact…

Linux上Mysql安装和部署(图文结合超详细)

1、首先将虚拟机装成功&#xff08;这里不做演示&#xff09; 2、df-h 查看光盘是否挂载&#xff0c;已挂载进行下一步&#xff0c;未挂载手动挂载 2.1、手动挂载 mount -o ro /dev/sr0 /media3、进入etc/yum.repos.d目录查看仓是否配置&#xff0c;若配置进行下一一步&#…