学习目标:
1、了解bloom filter布隆过滤器
2、掌握bloom filter布隆过滤器在redis中的使用
学习过程:
HyperLogLog只能作为统计使用,如果我们需要判断一个值是否存在,那么需要使用布隆过滤器了。布隆过滤器的功能就是用来快速判断一个元素是否出现在给定集合中的重要工具,而且比哈希表更节省空间。缺点和HyperLogLog一样,有一定的误识别率,它可能会把不是集合内的元素判定为存在于集合内,不过这样的概率相当小,在大部分的生产环境中是可以接受的。
布隆过滤器原理S集合中有n个元素,利用k个哈希函数,将S中的每个元素映射到一个长度为m的位(bit)数组B中不同的位置上,这些位置上的二进制数均置为1,如果待检测的元素经过这k个哈希函数的映射后,发现其k个位置上的二进制数不全是1,那么这个元素一定不在集合S中,反之,该元素可能是S中的某一个元素,也就是说布隆过滤器判断一个值不在集合中是100%准确的,但是判断当一个值在集合中时就有可能误判。
Redis官方提供的布隆过滤器到4.0提供插件功能后才正式登场,布隆过滤器作为一个插件加载到Redis Server中,给Redis提供了强大的布隆去重功能。
一、安装和基本使用
1、安装
[root@localhost ~]# cd /usr/local/redis/
[root@localhost redis]# mkdir module
[root@localhost redis]# cd module/
[root@localhost module]# git clone git://github.com/RedisLabsModules/rebloom
[root@localhost module]# cd rebloom/
[root@localhost rebloom]# make
生成一个rebloom.so
[root@localhost rebloom]# ls
contrib docs Makefile ramp.yml rebloom.so tests
Dockerfile LICENSE mkdocs.yml README.md src
我们可以在启动命令加上这个so文件
redis-server --loadmodule /path/to/rebloom.so
也可以在redis.conf中添加,这里我们选择在redis.conf添加
[root@localhost rebloom]# vim /etc/redis.conf
loadmodule /usr/local/redis/module/rebloom/rebloom.so
保存退出,重启redis
2、布隆过滤器基本指令
布隆过滤器基本指令,bf.add 添加元素,bf.exists 查询元素是否存在,bf.madd 指令可以同时添加多个, bf.mexists 指令可以判断多个元素是否存在。
127.0.0.1:6379> bf.add name liu
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> bf.add computer liu
(integer) 1
127.0.0.1:6379> bf.add computer daier
(integer) 1
127.0.0.1:6379> bf.madd computer shenzhou lenovo
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> bf.exists computer liu
(integer) 1
127.0.0.1:6379> bf.exists computer cc
(integer) 0
127.0.0.1:6379> bf.mexists computer liu shenzhou abc
1) (integer) 1
2) (integer) 1
3) (integer) 0
可以看到确实非常简单,而且目前为止也没有出现误判的情况,下面我们使用Java操作一下,添加更多的数据。Jedis2.X并不支持扩展命令,所以我们之前使用的项目的Redis需要升级为Jdeis3.0.0,同时引入JReBloom,地址是:
https://github.com/redisbloom/JReBloom
引入包,并改为Jedis的版本
redis.clients
jedis
3.0.0
com.redislabs
jrebloom
1.0.1
这里我们并不打算使用JReBloom的Client,只是使用了一下它定义好的命令而已,编写一个简单的添加的命令
public class RedisBoolm {
@Test
public void testRedis() {
Jedis jedis = new Jedis("192.168.137.101", 6379);
jedis.auth("123456");
Connection client = jedis.getClient();
client.sendCommand(Command.ADD, "computer", "baobaobb");
long reply=client.getIntegerReply();
System.out.println(reply);
client.close();
}
}
该扩展命令确实可以成功了,那么下面我们添加10000个。
我们添加10000的数据也没有出现误判,原来布隆过滤器对于已经见过的元素是不会误判,它只会误判那些没见过的元素。我们修改一下上面的代码,让其判断一些没有见过的值。
3、如何降低误判率
上面说过布隆过滤器存在误判的情况,在 redis 中有两个值决定布隆过滤器的准确率:
•error_rate :允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间也就越大。
•initial_size :布隆过滤器可以储存的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降。
redis 中有一个命令可以来设置这两个值:
127.0.0.1:6379> bf.reserve webs 0.0001 100000
OK
三个参数的含义:
•第一个值是过滤器的名字。
•第二个值为 error_rate 的值。
•第三个值为 initial_size 的值。
后面我们再汪这个webs添加值时,误判率就会明显的降低了。
如果不使用 bf.reserve,默认的error_rate
是 0.01,默认的initial_size
是 100。布隆过滤器的initial_size
估计的过大,会浪费存储空间,估计的过小,就会影响准确率,用户在使用之前一定要尽可能地精确估计好元素数量,还需要加上一定的冗余空间以避免实际元素可能会意外高出估计值很多。
我们怎么知道到底占用了多少空间呢,我们可以通过这个网站计算一下所需要的空间:
https://krisives.github.io/bloom-calculator/
在真是场景下,自己可以按照需要进行调正。我们看一下修改后的代码,我们可以调正其错误率等信息,
127.0.0.1:6379> bf.reserve buses 0.0001 100000
OK
Java测试代码如下:
@Test
public void testBfadds() {
int max=10000;
String [] baoes=new String[max+1];
baoes[0]="buses";
for(int i=1;i<=max;i++) {
baoes[i]="bao"+i;
}
Jedis jedis = new Jedis("192.168.137.101", 6379);
jedis.auth("123456");
Connection client = jedis.getClient();
//client.sendCommand(Command.RESERVE, "buses","0.0001","100000");
//批量添加
client.sendCommand(Command.MADD, baoes);
//在添加的时候事实上有很多添加错误了,这些添加错误事实上就是因为误判了已经存在了导致的。
List replay=client.getIntegerMultiBulkReply();
for(int j=0;j