拿今日头条来说,它会不停的给我们推荐新的新闻,每次推荐都要去重,过滤掉我们之前看过的内容,今日头条如何做到去重呢,我们上面的HyperLogLog虽然能去重,但是没有办法确认这个新闻有没有被浏览 过,没有pfcontains的方法。有没有更好的解决方案呢?
Redis为我们准备了布隆过滤器,是专门用来解决这种去重问题的,它在起去重功能的同时,空间上还可以节约90%,只是稍微有一定的误判率。
什么是布隆过滤器
布隆过滤器可以理解为稍微不精确的set结构,当你使用他的contains方法判断某个对象是否存在时,它可能会误判,但是布隆过滤器也不是特别的不精准,只要参数设置合理,是可以将误差控制在范围之内的。
当布隆过滤器说某个值存在时,这个值可能不存在,当它说不存在时,那一定是不存在。也就是说当你说认识某个人时,你可能不认识,当你说不认识时,那一定是不认识。套上面的使用场景,布隆过滤器可以精准的过滤掉那些已经看过的内容,那些没有看过的也可能过滤掉一部分,这样就能保证不会给用户推荐已经看过的内容。
Redis的布隆过滤器
布隆过滤器是Redis4.0以插件的形式提供的
基本使用
布隆过滤器有两个基本指令,bf.add添加元素,bf.exists查询元素是否存在,bf.add 一次只能插入一个元素,如果想插入多个,就用到了,bf.madd指令,如果判断多个元素是否存在,可以使用bf.mexists检查。
127.0.0.1:6379> bf.add codehole user1
(integer) 1
127.0.0.1:6379> bf.add codehole user2
(integer) 1
127.0.0.1:6379> bf.add codehole user3
(integer) 1
127.0.0.1:6379> bf.exists codehole user1
(integer) 1
127.0.0.1:6379> bf.exists codehole user2
(integer) 1
127.0.0.1:6379> bf.exists codehole user3
(integer) 1
127.0.0.1:6379> bf.exists codehole user4
(integer) 0
127.0.0.1:6379> bf.madd codehole user4 user5 user6
1) (integer) 1
2) (integer) 1
3) (integer) 1
127.0.0.1:6379> bf.mexists codehole user4 user5 user6 user7
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 0
自定义参数
布隆过滤器在add的时候会自动创建默认参数,Redis还提供了自定义参数的设置方法,需要我们在add之前使用,bf.reserve指令显式创建,如果之前已经创建过,就会报错。自定义参数有三个,key,error_rate和initial_size,错误率越低,使用的空间就越大,initial_size是预计放入元素的大小,当实际超过这个大小时,错误率就会上升。
redis提供的默认参数是error_rate是0.01 默认initial_size是100
布隆过滤器原理
学习了基本使用,我们再看一下它的实现原理。
每个布隆过滤器其实就是一个大的位数组和无偏hash。当add时,会使用多个hash函数对key进行hash运算出一个整数索引值对位数组元素进行取模运算得到一个位置,每个hash函数都能算不同的位置,将这几个位置全部设置为1.
网友评论