Redis布隆过滤器

一:什么是布隆过滤器

  布隆过滤器(Bloom Filter)是 Redis 4.0 版本提供的新功能,它被作为插件加载到 Redis 服务器中,给 Redis 提供强大的去重功能。

当布隆过滤器判定某个值存在时,这个值只是有可能存在;当它说某个值不存在时,那这个值肯定不存在。所以布隆会有一定的误判率,但是误判率极低。

 

二:布隆过滤器使用场景

  虽然这种结构的去重率并不完全精确,但和其他结构一样都有特定的应用场景,比如当处理海量数据时,就可以使用布隆过滤器实现去重。

1、垃圾邮件过滤功能

2、爬虫url过滤

3、解决缓存穿透问题

 

三:布隆过滤器原理

   布隆过滤器(Bloom Filter)是一个高空间利用率的概率性数据结构,由二进制向量(即位数组)和一系列随机映射函数(即哈希函数)两部分组成。其中位数组的初始状态都为 0。

 

当使用布隆过滤器添加 key 时,会使用不同的 hash 函数对 key 存储的元素值进行哈希计算,从而会得到多个哈希值。根据哈希值计算出一个整数索引值,将该索引值与位数组长度做取余运算,最终得到一个位数组位置,并将该位置的值变为 1。每个 hash 函数都会计算出一个不同的位置,然后把数组中与之对应的位置变为 1。通过上述过程就完成了元素添加(add)操作。

简单理解:元素添加到布隆过滤器的时候,内部会进行一系列计算,将过滤器的数组位上的对于值修改为1。

这样也就理解了为什么布隆过滤器会存在误判,假设元素1占据1,2,3号位,而元素2应该占据1,2号位。那么添加的时候计算出的位置已经被元素1占据,那么就会认为已存在。

 1、布隆和哈希表比较

哈希表查询效率可以达到O(1),但是哈希存储比较消耗内存,会随着数据的增大而不但增大。

布隆过滤器在前期确定数据大小之后不会随着数据的改变而改变。

2、布隆过滤器误判率统计

如果m代表位向量长度,n代表需要判断的元素个数, k代表hash函数个数。
下表是m与n比值在k个hash函数下面的误判率
m/n k=1 k=2 k=3 k=4 k=5 k=6 k=7 k=8
2 0.393 0.400            
3 0.283 0.237 0.253          
4 0.221 0.155 0.147 0.160        
5 0.181 0.109 0.101 0.092 0.092      
6 0.154 0.080 0.060 0.056 0.057 0.063    
7 0.133 0.061 0.042 0.035 0.034 0.036    
8 0.118 0.048 0.030 0.024  0.021 0.021 0.022  
9 0.105 0.039 0.022 0.016 0.014 0.013 0.013 0.014
10 0.095 0.032 0.017 0.011 0.009 0.008  0.008 0.008
11 0.086 0.027  0.013 0.008 0.006 0.005 0.005 0.005
12 0.080 0.023 0.010 0.006 0.004 0.003 0.003 0.003 

3、Bit数组的大小选择

根据预估数据量n以及误判率fpp,bit数组大小的m的计算方式:

4、哈希函数的量选择

​ 由预估数据量n以及bit数组长度m,可以得到一个hash函数的个数k:

 

四:布隆过滤器的使用

1、通过redis hash (setbit | getbit)  + hash (多个) 函数 实现

2、安装redis 布隆插件  bloom-fifilter (https://github.com/RedisBloom/RedisBloom)

使用Redis 布隆过滤器主要就2个命令:

# bf.add 将元素添加到布隆过滤器
bf.add key value
# bf.add 判断元素是否存在布隆过滤器
bf.exists key value

 

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

  • error_rate :允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间也就越大。

  • initial_size :布隆过滤器可以储存的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降。

# 设置错误率 和 存储元素个数, 当key存在时不可设置
bf.reserve key 0.01 10000

实际中如何使用呢?

  先查询布隆是否存在,若不存在则直接处理数据,如果存在查询mysql再根据结果处理数据。 

 

五:Laravel 中的调用

# 设置布隆过滤器
Redis::rawCommand('bf.reserve', 'course', '0.01', '10000');
# 查询值是否存在
Log::info(Redis::rawCommand('bf.exists', 'course', 'php'));
# 加入一个值到过滤器
Redis::rawCommand('bf.add', 'course', 'php');
Log::info(Redis::rawCommand('bf.exists', 'course', 'php'));
Log::info(Redis::rawCommand('bf.exists', 'course', 'java'));

 

六:布隆过滤器的缺点

无法删除元素

需要定期做补偿机制

posted @ 2023-02-03 09:42  wish_yang  阅读(891)  评论(0编辑  收藏  举报