Google布隆过滤器与Redis布隆过滤器详解

Stella981
• 阅读 562

一、什么是布隆过滤器?

布隆过滤器可以用来判断一个元素是否在一个集合中。它的优势是只需要占用很小的内存空间以及有着高效的查询效率。

对于布隆过滤器而言,它的本质是一个位数组:位数组就是数组的每个元素都只占用1bit ,并且每个元素只能是0或者1

布隆过滤器除了一个位数组,还有 K 个哈希函数。当一个元素加入布隆过滤器中的时候,会进行如下操作:

  • 使用K个哈希函数对元素值进行K次计算,得到K个哈希值
  • 根据得到的哈希值,在位数组中把对应下标的值置为1

下图表示有三个hash函数,比如一个集合中有x、y、z三个元素,分别用三个hash函数映射到二进制序列的某些位上,假设我们判断w是否在集合中,同样用三个hash函数来映射,结果发现取得的结果不全为1,则表示w不在集合里面。 Google布隆过滤器与Redis布隆过滤器详解 数组的容量即使再大,也是有限的。那么随着元素的增加,插入的元素就会越多,位数组中被置为1的位置因此也越多,这就会造成一种情况:当一个不在布隆过滤器中的元素,经过同样规则的哈希计算之后,得到的值在位数组中查询,有可能这些位置因为之前其它元素的操作先被置为1了

所以,有可能一个不存在布隆过滤器中的会被误判成在布隆过滤器中。这就是布隆过滤器的一个缺陷。但是,如果布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就一定不在布隆过滤器中。总结就是:

  • 布隆过滤器说某个元素在,可能会被误判
  • 布隆过滤器说某个元素不在,那么一定不在

二、Google布隆过滤器基本使用

  1. 引入依赖 > > > com.google.guava > guava > 21.0 > >

  2. BloomFilterService

> > @Service > > public class BloomFilterService { > > @Autowired > private UserMapper userMapper; > > private BloomFilter bf; > > /** > * 创建布隆过滤器 > * > * @PostConstruct:程序启动时候加载此方法 > / > @PostConstruct > public void initBloomFilter() { > List userList = userMapper.selectAllUser(); > if (CollectionUtils.isEmpty(userList)) { > return; > } > //创建布隆过滤器(默认3%误差) > bf = BloomFilter.create(Funnels.integerFunnel(), userList.size()); > for (User user : userList) { > bf.put(user.getId()); > } > } > > /* > * 判断id可能存在于布隆过滤器里面 > * > * @param id > * @return > */ > public boolean userIdExists(int id) { > return bf.mightContain(id); > } > } > >

  1. BloomFilterController

> @RestController > public class BloomFilterController { > > @Autowired > private BloomFilterService bloomFilterService; > > @RequestMapping("/bloom/idExists") > public boolean ifExists(int id) { > return bloomFilterService.userIdExists(id); > } > } >

三、Google布隆过滤器与Redis布隆过滤器对比

  1. Google布隆过滤器的缺点

基于JVM内存的一种布隆过滤器 重启即失效 本地内存无法用在分布式场景 不支持大数据量存储

  1. Redis布隆过滤器

可扩展性Bloom过滤器:一旦Bloom过滤器达到容量,就会在其上创建一个新的过滤器 不存在重启即失效或者定时任务维护的成本:基于Google实现的布隆过滤器需要启动之后初始化布隆过滤器 缺点:需要网络IO,性能比Google布隆过滤器低

四、Redis布隆过滤器安装和基本使用

1)使用Docker安装 > > [root@localhost ~]# docker run -d -p 6379:6379 --name bloomfilter redislabs/rebloom > 2)基本使用 > > [root@localhost ~]# docker exec -it bloomfilter /bin/bash > root@7a06a3528556:/data# redis-cli -p 6379 > 127.0.0.1:6379> >

Redis布隆过滤器命令:

bf.add:添加元素到布隆过滤器中,只能添加一个元素,如果想要添加多个使用bf.madd命令 bf.exists:判断某个元素是否在过滤器中,只能判断一个元素,如果想要判断多个使用bf.mexists > > 127.0.0.1:6379> bf.add urls www.taobao.com > (integer) 1 > 127.0.0.1:6379> bf.exists urls www.taobao.com > (integer) 1 > 127.0.0.1:6379> bf.madd urls www.baidu.com www.tianmao.com > 1) (integer) 1 > 2) (integer) 1 > 127.0.0.1:6379> bf.mexists urls www.baidu.com www.tianmao.com > 1) (integer) 1 > 2) (integer) 1 >

上面使用的布隆过滤器只是默认参数的布隆过滤器,它在我们第一次add的时候自动创建。Redis还提供了自定义参数的布隆过滤器,需要在add之前使用bf.reserve指令显式创建。如果对应的key已经存在,bf.reserve会报错(error) ERR item exists bf.reserve 过滤器名 error_rate initial_size

布隆过滤器存在误判的情况,在Redis中有两个值决定布隆过滤器的准确率:

  • error_rate:允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间也就越大
  • initial_size:布隆过滤器可以储存的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降

> 127.0.0.1:6379> bf.reserve user 0.01 100 > > OK

五、会员转盘抽奖

Google布隆过滤器与Redis布隆过滤器详解

实现思路:在判断用户是否是会员的时候,第一步先通过布隆过滤器过滤掉99%的非会员(误码率为1%的情况下),由于布隆过滤器有可能将一个不存在布隆过滤器中的误判成在布隆过滤器中,也就是有可能会把非会员判断为会员,所以第二步查询数据库中用户对应的数据库信息判断该用户是否是会员

声明:本号所有文章除特殊注明,都为原创,公众号读者拥有优先阅读权,未经作者本人允许不得转载,否则追究侵权责任。

关注我的公众号,后台回复【JAVAPDF】获取200页面试题! 5万人关注的大数据成神之路,不来了解一下吗? 5万人关注的大数据成神之路,真的不来了解一下吗? 5万人关注的大数据成神之路,确定真的不来了解一下吗?

欢迎您关注《大数据成神之路》

Google布隆过滤器与Redis布隆过滤器详解

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
HashMap 的底层实现原理
HashMap是一个用于存储KeyValue键值对的集合,每一个键值对也叫做Entry。这些个Entry分散存储在一个数组当中,这个数组就是HashMap的主干。HashMap数组每一个元素的初始值都是Null。 !(https://oscimg.oschina.net/oscnet/8495d30fe00a2865dd74088d2
Wesley13 Wesley13
2年前
ES6 新增的数组的方法
给定一个数组letlist\//wu:武力zhi:智力{id:1,name:'张飞',wu:97,zhi:10},{id:2,name:'诸葛亮',wu:55,zhi:99},{id:3,name:'赵云',wu:97,zhi:66},{id:4,na
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这