本篇博客我们主要介绍如何用Redis实现布隆过滤器,但是在介绍布隆过滤器之前,我们首先介绍一下,为啥要使用布隆过滤器。

1、布隆过滤器使用场景

  比如有如下几个需求:

  ①、原本有10亿个号码,现在又来了10万个号码,要快速准确判断这10万个号码是否在10亿个号码库中?

  解决办法一:将10亿个号码存入数据库中,进行数据库查询,准确性有了,但是速度会比较慢。

  解决办法二:将10亿号码放入内存中,比如Redis缓存中,这里我们算一下占用内存大小:10亿*8字节=8GB,通过内存查询,准确性和速度都有了,但是大约8gb的内存空间,挺浪费内存空间的。

  ②、接触过爬虫的,应该有这么一个需求,需要爬虫的网站千千万万,对于一个新的网站url,我们如何判断这个url我们是否已经爬过了?

  解决办法还是上面的两种,很显然,都不太好。

  ③、同理还有垃圾邮箱的过滤。

  那么对于类似这种,大数据量集合,如何准确快速的判断某个数据是否在大数据量集合中,并且不占用内存,布隆过滤器应运而生了。

2、布隆过滤器简介

  带着上面的几个疑问,我们来看看到底什么是布隆过滤器。

  布隆过滤器:一种数据结构,是由一串很长的二进制向量组成,可以将其看成一个二进制数组。既然是二进制,那么里面存放的不是0,就是1,但是初始默认值都是0。

  如下所示:

  

  ①、添加数据

  介绍概念的时候,我们说可以将布隆过滤器看成一个容器,那么如何向布隆过滤器中添加一个数据呢?

  如下图所示:当要向布隆过滤器中添加一个元素key时,我们通过多个hash函数,算出一个值,然后将这个值所在的方格置为1。

  比如,下图hash1(key)=1,那么在第2个格子将0变为1(数组是从0开始计数的),hash2(key)=7,那么将第8个格子置位1,依次类推。

  

  ②、判断数据是否存在?

  知道了如何向布隆过滤器中添加一个数据,那么新来一个数据,我们如何判断其是否存在于这个布隆过滤器中呢?

  很简单,我们只需要将这个新的数据通过上面自定义的几个哈希函数,分别算出各个值,然后看其对应的地方是否都是1,如果存在一个不是1的情况,那么我们可以说,该新数据一定不存在于这个布隆过滤器中。

  反过来说,如果通过哈希函数算出来的值,对应的地方都是1,那么我们能够肯定的得出:这个数据一定存在于这个布隆过滤器中吗?

  答案是否定的,因为多个不同的数据通过hash函数算出来的结果是会有重复的,所以会存在某个位置是别的数据通过hash函数置为的1。

  我们可以得到一个结论:布隆过滤器可以判断某个数据一定不存在,但是无法判断一定存在。

  ③、布隆过滤器优缺点

  优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。

  缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点,无法删除数据。

3、Redis实现布隆过滤器

①、bitmaps

  我们知道计算机是以二进制位作为底层存储的基础单位,一个字节等于8位。

  比如“big”字符串是由三个字符组成的,这三个字符对应的ASCII码分为是98、105、103,对应的二进制存储如下:

  

  在Redis中,Bitmaps 提供了一套命令用来操作类似上面字符串中的每一个位。

  一、设置值

setbit key offset value

  

  我们知道"b"的二进制表示为0110 0010,我们将第7位(从0开始)设置为1,那0110 0011 表示的就是字符“c”,所以最后的字符 “big”变成了“cig”。

  二、获取值

gitbit key offset

  

  三、获取位图指定范围值为1的个数

bitcount key [start end]

  如果不指定,那就是获取全部值为1的个数。

  注意:start和end指定的是字节的个数,而不是位数组下标。

  

②、Redisson

  Redis 实现布隆过滤器的底层就是通过 bitmap 这种数据结构,至于如何实现,这里就不重复造轮子了,介绍业界比较好用的一个客户端工具——Redisson。

  Redisson 是用于在 Java 程序中操作 Redis 的库,利用Redisson 我们可以在程序中轻松地使用 Redis。

  下面我们就通过 Redisson 来构造布隆过滤器。

 package com.ys.rediscluster.bloomfilter.redisson;

 import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config; public class RedissonBloomFilter { public static void main(String[] args) {
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.14.104:6379");
config.useSingleServer().setPassword("123");
//构造Redisson
RedissonClient redisson = Redisson.create(config); RBloomFilter<String> bloomFilter = redisson.getBloomFilter("phoneList");
//初始化布隆过滤器:预计元素为100000000L,误差率为3%
bloomFilter.tryInit(100000000L,0.03);
//将号码10086插入到布隆过滤器中
bloomFilter.add("10086"); //判断下面号码是否在布隆过滤器中
System.out.println(bloomFilter.contains("123456"));//false
System.out.println(bloomFilter.contains("10086"));//true
}
}

  这是单节点的Redis实现方式,如果数据量比较大,期望的误差率又很低,那单节点所提供的内存是无法满足的,这时候可以使用分布式布隆过滤器,同样也可以用 Redisson 来实现,这里我就不做代码演示了,大家有兴趣可以试试。

4、guava 工具

  最后提一下不用Redis如何来实现布隆过滤器。

  guava 工具包相信大家都用过,这是谷歌公司提供的,里面也提供了布隆过滤器的实现。

 package com.ys.rediscluster.bloomfilter;

 import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.Funnels; public class GuavaBloomFilter {
public static void main(String[] args) {
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),100000,0.01); bloomFilter.put("10086"); System.out.println(bloomFilter.mightContain("123456"));
System.out.println(bloomFilter.mightContain("10086"));
}
}

Redis详解(十三)------ Redis布隆过滤器的更多相关文章

  1. Redis 详解 (二) redis的配置文件介绍

    目录 1.开头说明 2.INCLUDES 3.MODULES 4.NETWORK 5.GENERAL 6.SNAPSHOTTING 7.REPLICATION 8.SECURITY 9.CLIENTS ...

  2. Redis 详解 (一) redis的简介和安装

    目录 1.Redis 的简介 2.Redis 下载 3.安装环境 4.编译安装 5.启动Redis 6.关闭Redis 7.注意事项 工作中一直在用 Redis,但是一直没有进行系统的总结,这个系列的 ...

  3. Redis 详解 (五) redis的五大数据类型实现原理

    目录 1.对象的类型与编码 ①.type属性 ②.encoding 属性和 *prt 指针 2.字符串对象 3.列表对象 4.哈希对象 5.集合对象 6.有序集合对象 7.五大数据类型的应用场景 8. ...

  4. Redis 详解 (四) redis的底层数据结构

    目录 1.演示数据类型的实现 2.简单动态字符串 3.链表 4.字典 5.跳跃表 6.整数集合 7.压缩列表 8.总结 上一篇博客我们介绍了 redis的五大数据类型详细用法,但是在 Redis 中, ...

  5. Redis 详解 (三) redis的五大数据类型详细用法

    目录 1.string 数据类型 2.hash 数据类型 3.list 数据类型 4.set 数据类型 5.zset 数据类型 6.系统相关命令 7.key 相关命令 我们说 Redis 相对于 Me ...

  6. redis缓存穿透穿透解决方案-布隆过滤器

    redis缓存穿透穿透解决方案-布隆过滤器 我们先来看一段代码 cache_key = "id:1" cache_value = GetValueFromRedis(cache_k ...

  7. 基础拾遗------redis详解

    基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...

  8. Spring Data操作Redis详解

    Spring Data操作Redis详解 Redis是一种NOSQL数据库,Key-Value形式对数据进行存储,其中数据可以以内存形式存在,也可以持久化到文件系统.Spring data对Redis ...

  9. .Net使用Redis详解之ServiceStack.Redis(七) 转载https://www.cnblogs.com/knowledgesea/p/5032101.html

    .Net使用Redis详解之ServiceStack.Redis(七)   序言 本篇从.Net如何接入Reis开始,直至.Net对Redis的各种操作,为了方便学习与做为文档的查看,我做一遍注释展现 ...

  10. Redis详解入门篇

    Redis详解入门篇 [本教程目录] 1.redis是什么2.redis的作者3.谁在使用redis4.学会安装redis5.学会启动redis6.使用redis客户端7.redis数据结构 – 简介 ...

随机推荐

  1. spring对websocket的集成和使用

    WebSocket是HTML5提出的一个用于通信的协议规范,该协议通过一个握手机制,在客户端和服务端之间建立一个类似于TCP的连接,从而方便客户端和服务端之间的通信. WebSocket协议本质上是一 ...

  2. 1、Hbase原理分析

    一.Hbase介绍 1.1.对Hbase的认识 HBase作为面向列的数据库运行在HDFS之上,HDFS缺乏随机读写操作,HBase正是为此而出现. HBase参考 Google 的 Bigtable ...

  3. CF#358 D. Alyona and Strings DP

    D. Alyona and Strings 题意 给出两个字符串s,t,让找出最长的k个在s,t不相交的公共子串. 思路 看了好几个题解才搞懂. 代码中有注释 代码 #include<bits/ ...

  4. python语法学习第六天--字典

    字典:可变容器类型,用键值对的形式采用花括号储存(键唯一) 语法:d={key1:value1,key2:value2} 访问字典中的值: 字典名[键名]#若字典中不存在则报错 更改字典: 添加值:字 ...

  5. [hdu5164]ac自动机

    中文题目:http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=563&pid=1003 首先贴一下bc的题解 ...

  6. ES6,ES7,ES8 常用

    ES6常用新特性 let && const let 命令也用于变量声明,但是作用域为局部 { let a = 10; var b = 1; } 在函数外部可以获取到b,获取不到a,因此 ...

  7. python中minepy包的下载

    minepy包的下载 今天在做机器学习的时候,需要使用到互信息的有关内容,而python包下正好有处理互信息的包,想直接下一个,没想到遇到了不少问题: 基本指令很简单了: pip install mi ...

  8. Java并发编程:线程池ThreadPoolExecutor

    多线程的程序的确能发挥多核处理器的性能.虽然与进程相比,线程轻量化了很多,但是其创建和关闭同样需要花费时间.而且线程多了以后,也会抢占内存资源.如果不对线程加以管理的话,是一个非常大的隐患.而线程池的 ...

  9. 「雕爷学编程」Arduino动手做(35)——模拟量声音传感器

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  10. spark机器学习从0到1奇异值分解-SVD (七)

      降维(Dimensionality Reduction) 是机器学习中的一种重要的特征处理手段,它可以减少计算过程中考虑到的随机变量(即特征)的个数,其被广泛应用于各种机器学习问题中,用于消除噪声 ...