Java开发 - 布隆过滤器初体验
创始人
2025-05-28 21:38:23
0

目录

前言

布隆过滤器

什么是布隆过滤器

布隆过滤器的作用

布隆过滤器原理

怎么设计布隆过滤器

布隆过滤器使用案例

安装布隆过滤器

添加依赖

添加配置

添加工具类

添加测试代码

简单测试

特别提醒​​​​​​​

结语


前言

前面三篇,已经把消息队列和其所包含的Kafka和RabbitMQ做了说明,并用案例演示了如何使用,今天这一篇,我们要讲解的内容是布隆过滤器,布隆过滤器不同于过滤器Filter,想知道布隆过滤器是什么,和怎样使用布隆过滤器吗?今天这篇博客,将带你了解这些,学完这篇,你将能独立使用布隆过滤器,了解其工作原理。下面,就让我们一起来学习吧。

布隆过滤器

说起过滤器,我们总是想起两种:一种是Filter过滤器,一种是布隆过滤器。Filter过滤器用于在全局捕捉请求,并在请求前后做一些事情,比如:统一编码,URL级别的权限访问控制,过滤敏感词汇,压缩请求信息等。那么布隆过滤器是做什么的呢?这里先卖个关子,我们继续往下看。

什么是布隆过滤器

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

布隆过滤器不保存元素,之判断是否存在,不保存,所以也无法取出元素。

布隆过滤器的作用

布隆过滤器主要应用于网页URL的去重,垃圾邮件的判别,集合重复元素的判别,查询加速(比如基于key-value的存储系统)、数据库防止查询击穿, 使用BloomFilter来减少不存在的行或列的磁盘查找。

在Java开发 - Redis初体验一文中,我们曾提到过布隆过滤器,在缓存击穿的预防上面它是很好的效果的。刚好,学完此篇,你就可以在Redis项目中尝试添加布隆过滤器来防止缓存击穿,因为在当时写那篇博客时,我们采用的方法是给null值,在文中也提到,这是不合适的,因为当时还没有讲解布隆过滤器,学完此篇,大家可以去做个尝试。

布隆过滤器原理

常规检查元素是否存在我们会怎么做?一般是遍历集合,判断元素是否相等,但这种查询的方式在数据量庞大的情况下效率太低,想要实现快速的查找,前面学过的Java开发 - 树(二叉树,二叉排序树,红黑树)中曾经讲解过的数据结构或许会有一些帮助,其Hash散列或类似算法可以保证高效判断元素是否存在,但也存在消耗内存较多的问题,布隆过滤器的存在,正好解决了这个问题。

当要向布隆过滤器中添加一个元素时,该元素会经过N个哈希函数的计算并最终产生k个哈希值,布隆过滤器是个位数组,假设每一位是0,这些值就会根据计算出来的下标放入这个数组中,为1。在查询时,会判断这几个哈希值所在的位置,只要有一个为0就不存在于布隆过滤器中。

下面,我们通过几张图来说明布隆过滤器查询的原理:

假设这是一个空的布隆过滤器:

现在添加了coding单词在布隆过滤器中的状态:

coding算法1加密:1

coding算法2加密:3

coding算法3加密:5

现在添加了fire单词在布隆过滤器中的状态:

fire算法1加密:2

fire算法2加密:4

fire算法3加密:6

现在添加了codingfire单词在布隆过滤器中的状态:

codingfire算法1加密:1

codingfire算法2加密:4

codingfire算法3加密:6

问题来了,我还没添加呢,1,4,6的位置已经有东西了,这时候,布隆过滤器就会误判,认为codingfire已存在于布隆过滤器中。

布隆过滤器误判特点:

  • 布隆过滤器判断不存在的元素,一定不在集合中
  • 布隆过滤器判断存在的元素,有可能不存在集合中

这是因为我们做测试时布隆过滤器太短了,假设就10格,会导致每个位置值都是1,我们就不用存东西了,误判会很严重,啥都存在,那这就是个失败的布隆过滤器。所以,合适的大小对布隆过滤器非常重要。

怎么设计布隆过滤器

布隆过滤器在启动时需要分配合适的内存大小,这直接决定了它是否准确。设置的大小要满足这几个条件:

  • 可接受范围的大小
  • 既节省内存,又不会有很高的误判率

关于这两个条件,有一个公式用于计算误判率:

这是根据误判率计算布隆过滤器长度的公式:

n :是已经添加元素的数量;

k :哈希的次数;

m :布隆过滤器的长度(位数的大小)

最终结果结果就是误判率。

反着来也是可以的,知道误判率,反推布隆过滤器长度:

推荐一个在线计算布隆过滤器大小的网站,可以正推,也可以反推:Bloom filter calculator 

布隆过滤器使用案例

安装布隆过滤器

布隆过滤器安装推荐这篇博客:Redis 布隆过滤器命令的使用详解

不过,它里面提到的布隆过滤器我个人不推荐,因为官方也推出了一个结合了Redis和布隆过滤器的软件工具:redis/redis-stack

网址在:Docker

安装方法和推荐博客里是一样的,由于比较简单,博主就不带大家一步步安装了,安装完请回到这里,我们继续。

安装完记得启动:

由于我们是教程,所以密码不设置,端口采用默认,实际可是要改的。 我们在上一篇RabbitMQ所在的子工程stock中继续集成,做一个简单的测试。

添加依赖

org.springframework.bootspring-boot-starter-data-redis

添加配置

spring:redis:host: localhostport: 6379password:

添加工具类

在stock包下建utils包,包下新建一个类,代码如下:

package com.codingfire.cloud.stock.utils;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.List;@Component
public class RedisBloomUtils {@Autowiredprivate StringRedisTemplate redisTemplate;private static RedisScript bfreserveScript = new DefaultRedisScript<>("return redis.call('bf.reserve', KEYS[1], ARGV[1], ARGV[2])", Boolean.class);private static RedisScript bfaddScript = new DefaultRedisScript<>("return redis.call('bf.add', KEYS[1], ARGV[1])", Boolean.class);private static RedisScript bfexistsScript = new DefaultRedisScript<>("return redis.call('bf.exists', KEYS[1], ARGV[1])", Boolean.class);private static String bfmaddScript = "return redis.call('bf.madd', KEYS[1], %s)";private static String bfmexistsScript = "return redis.call('bf.mexists', KEYS[1], %s)";public Boolean hasBloomFilter(String key){return redisTemplate.hasKey(key);}/*** 设置错误率和大小(需要在添加元素前调用,若已存在元素,则会报错)* 错误率越低,需要的空间越大* @param key* @param errorRate 错误率,默认0.01* @param initialSize 默认100,预计放入的元素数量,当实际数量超出这个数值时,误判率会上升,尽量估计一个准确数值再加上一定的冗余空间* @return*/public Boolean bfreserve(String key, double errorRate, int initialSize){return redisTemplate.execute(bfreserveScript, Arrays.asList(key), String.valueOf(errorRate), String.valueOf(initialSize));}/*** 添加元素* @param key* @param value* @return true表示添加成功,false表示添加失败(存在时会返回false)*/public Boolean bfadd(String key, String value){return redisTemplate.execute(bfaddScript, Arrays.asList(key), value);}/*** 查看元素是否存在(判断为存在时有可能是误判,不存在是一定不存在)* @param key* @param value* @return true表示存在,false表示不存在*/public Boolean bfexists(String key, String value){return redisTemplate.execute(bfexistsScript, Arrays.asList(key), value);}/*** 批量添加元素* @param key* @param values* @return 按序 1表示添加成功,0表示添加失败*/public List bfmadd(String key, String... values){return (List)redisTemplate.execute(this.generateScript(bfmaddScript, values), Arrays.asList(key), values);}/*** 批量检查元素是否存在(判断为存在时有可能是误判,不存在是一定不存在)* @param key* @param values* @return 按序 1表示存在,0表示不存在*/public List bfmexists(String key, String... values){return (List)redisTemplate.execute(this.generateScript(bfmexistsScript, values), Arrays.asList(key), values);}private RedisScript generateScript(String script, String[] values) {StringBuilder sb = new StringBuilder();for(int i = 1; i <= values.length; i ++){if(i != 1){sb.append(",");}sb.append("ARGV[").append(i).append("]");}return new DefaultRedisScript<>(String.format(script, sb.toString()), List.class);}}

代码都是模版,使用时直接添加此类即可。 

添加测试代码

我们quartz包下有个QuartzJob类,我们曾在里面测试Quartz功能和RabbitMQ,现在,我们来添加布隆过滤器的测试代码:

package com.codingfire.cloud.stock.quartz;import com.codingfire.cloud.stock.utils.RedisBloomUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;import java.time.LocalDateTime;public class QuartzJob implements Job {// RabbitTemplate就是amqp框架提供的发送消息的对象@Autowiredprivate RabbitTemplate rabbitTemplate;@Autowiredprivate RedisBloomUtils redisBloomUtils;@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {//输出当前时间System.out.println("--------------"+ LocalDateTime.now() +"---------------");// 先简单的发送一串文字
//        rabbitTemplate.convertAndSend(RabbitMQConfig.STOCK_EX,RabbitMQConfig.STOCK_ROUT,"黄河之水天上来,奔流到海不复还。");//  首先确定要向布隆过滤器中保存的元素String[] numbers={"zero","one","two","three","four","five","six","seven","eight","nine","ten"};//  使用RedisBloomUtils类将上面的数组元素保存在Redis(布隆过滤器)中redisBloomUtils.bfmadd("numberBloom",numbers);// 下面就可以判断一个元素是否在这个布隆过滤器中了String elm="six";System.out.println("布隆过滤器判断"+elm+"是否存在:"+ redisBloomUtils.bfexists("numberBloom",elm));}
}

大阿甲不用纠结代码为什么写在这个类里,随便你写在哪里,写在测试类中也行,只要你项目能运行我们写的测试方法,随便你写在哪。 

简单测试

下面我们来简单测试下布隆过滤器的使用,看情况启动服务,如果十一路学习过来,和博主用的是相同工程的同学,请启动nacos,seata,mysql,还有最重要的redisbloom,可能还要启动RabbitMQ,否则会报错,启动后,运行项目,查看控制台输出:

能输出图中内容的就是测试成功了。

特别提醒

设置错误率和大小在使用前记得调用,不设置默认0.01,自己看哈。  

QuartzJob中布隆过滤器虽然进行了测试,但我们要知道QuartzJob的工作驱动,还有一个类叫QuartzConfig,这里面的代码相当于是注册+触发条件。我这么说,大家懂吗?不懂得可以去看看驱动QuartzJob运行的触发器的设置:Java开发 - Quartz初体验。

结语

简单来说,布隆过滤器就是用来判断某个元素是否存在于某一个集中的东西,而且,其判断效率非常高,是一个在大数据情况下常用的工具,但它本身代码量并不大,但要注意布隆过滤器存在误判率,所以使用起来,在设置重要参数时还是要注意些的。今天的布隆过滤器介绍到此结束, 不知道大家对最近的博客还满意吗?欢迎留言沟通交流。

相关内容

热门资讯

农村经典母亲祭文 农村经典母亲祭文范文(通用6篇)  祭文,文体名。 祭祀或祭奠时表示哀悼或祷祝的文章。 体裁有韵文和...
建党百年句子 建党百年句子  一、中国共产党建党日  中国共产党于1921年7月23日成立后,在反动军阀政府的残暴...
学史增信心得体会 学史增信心得体会  一、什么是党史  中共党史是政党史,是专史,它研究建国后中国共产党作为执政党的历...
优秀团干部简要事迹材料 优秀团干部简要事迹材料  事迹材料是指党政军机关为了弘扬正气,表彰先进,推动工作,对本单位具有突出事...
建党一百周年绘画作品 建党一百周年绘画作品  一、建党一百周年关于党的历史简介  中国共产党创建于1921年,中国共产党破...
安全生产知识培训的内容 安全生产知识培训的内容  安全生产是安全与生产的统一,其宗旨是安全促进生产,生产必须安全。以下是小编...
贫困救助申请书 贫困救助申请书  在这个高速发展的时代,各种申请书频频出现,利用申请书我们可以表达自己的愿望和诉求。...
2021年支部书记讲党课材料 2021年支部书记讲党课材料  一、什么是党课  党课,是中国共产党的组织对党员和入党积极分子进行教...
宋江简介 宋江简介宋江  中文名称: 宋江  性  别: 男  朝  代: 宋代  生 卒 年: ?~约112...
寒假社区服务记录表 寒假社区服务记录表 服务主题 xx社区  服务时间 xx--xx  服务社区 xxx社区  组织者 ...
有一种爱情叫兄弟5(结局篇)... 有一种爱情叫兄弟5(结局篇)我命如此我转身,慢慢腾腾地顺着楼梯往楼上走着,走过2楼的时候,我听见有人...
安全生产工作的简报 安全生产工作的简报范文(精选11篇)  在快速变化和不断变革的今天,简报起到的作用越来越大,简报一般...
师德师风学习材料 师德师风学习材料  师德师风学习材料(精选8篇)  师德建设决定我国教师队伍建设的成败,也就决定我国...
励志成才优秀大学生事迹材料 励志成才优秀大学生事迹材料(精选12篇)  在学习、工作乃至生活中,大家都不可避免地要接触到事迹材料...
收入证明范本 收入证明范本  收入证明范本(精选16篇)  在生活、工作和学习中,大家都不可避免地要接触到证明吧,...
骨干教师申报事迹材料 骨干教师申报事迹材料(通用5篇)  在日常生活或是工作学习中,大家都尝试过写事迹吧,根据范围的不同,...
党史教育组织生活会个人对照检... 党史教育组织生活会个人对照检查材料  党史教育组织生活会个人对照检查材料(精选18篇)  组织生活一...
工作承诺书 【实用】工作承诺书三篇  在生活中,接触并使用承诺书的人越来越多,不同的承诺书内容同样也是不同的。那...
感动中国人物的事迹 感动中国人物的事迹  感动中国人物的事迹(精选27篇)  “感动中国”节目被媒体誉为“中国人的年度精...
家访记录内容学生在家表现 家访记录内容学生在家表现  一、家访的重要性  1、家访是“教育即服务”的现代教育观的具体表现,是一...