前言
接上篇:用户浏览过数据排重 - A表查B表中不存在的数据(mysql),随着我们的数据量越来越大,需要排重过滤的数据越来越多,我们再去使用mysql来进行过滤排重,效率将会变得逐渐低下,最终我们需要一个新的解决方案:
数据库:数据量大、查询效率较低,必要时需要分库分表。
redis set(集合)排重:访问效率高,但是随着数据越来越大,需要的内存也会越来越多。
bloom filter(布隆过滤器):占用内存小,支持过期,但具有一定的误判率,100w数据,万分之一的误判率,才消耗7M左右的内存空间,。
最终我们可以考虑使用redis布隆过来器来实现,关于布隆过来器的介绍如下:
布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
原理:当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。
优点:相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。布隆过滤器存储空间和插入/查询时间都是常数(O(k))。而且它不存储元素本身,在某些对保密要求非常严格的场合有优势。
缺点:一定的误识别率和删除困难。
安装redis bloom filter 扩展
在网络上有很多不同的语言版本(php、go、java)布隆过滤器实现,这里我们统一使用redis bloom filter 来演示,因为使用redis bloom filter更为方便,无需定义相关的储存逻辑和以及序列化、反序列化操作。
自从redis4.0起,redis便有了专门支持bloom filter的扩展了
# 拉下来redis的布隆过滤器扩展
git clone https://github.com/RedisBloom/RedisBloom.git
cd RedisBloom
# 编译后,会生成一个redisbloom.so文件
make
# 载入布隆过滤器扩展
redis-server --loadmodule ./redisbloom.so
redis bloom filter 操作命令
bf.add 添加元素到布隆过滤器
bf.exists 判断元素是否在布隆过滤器
bf.madd 添加多个元素到布隆过滤器,bf.add只能添加一个
bf.mexists 判断多个元素是否在布隆过滤器
bf.reserve 自定义布隆过滤器
bf.info 布隆过滤器的使用信息:初始化大小、误判率、当前使用数量(默认大小为:100,错误率2%)
127.0.0.1:6379> bf.add user:likes user:1:article:3
(integer) 1
127.0.0.1:6379> bf.add user:likes user:1:article:3
(integer) 1
127.0.0.1:6379> bf.add user:likes user:1:article:3
(integer) 1
127.0.0.1:6379> bf.exists user:likes user:1:article:3
(integer) 1
127.0.0.1:6379> bf.exists user:likes user:1:article:3
(integer) 1
127.0.0.1:6379> bf.exists user:likes user:1:article:3
(integer) 1
127.0.0.1:6379> bf.exists user:likes user:1:article:3
(integer) 0
127.0.0.1:6379> bf.madd user:likes user:1:article:3 user:1:article:4 user:1:article:5
(integer) 1
(integer) 1
(integer) 1
127.0.0.1:6379> bf.mexists user:likes user:1:article:3 user:1:article:4 user:1:article:5 user:1:article:5
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 0
127.0.0.1:6379> bf.info user:likes
Capacity 100
Size 290
Number of filters 1
Number of items inserted 1
Expansion rate 2
127.0.0.1:6379> bf.reserve test:like 0.0001 1000000
OK
通过布隆过滤器实战:用户是否浏览过某篇文章。
首先建立一个过滤器,用于储存所有的浏览数据,我们预计大概浏览量最终会达到10W,误判率为:0.0001,10W条数据中,将会有10条会被误判。
bf.reserve user:visits 0.0001 1000000
将用户浏览过的文章,通过一个字符串添加到过滤器中如: user:1:arctile:3,就是id为1的用户点赞的id为3的文章,如果有多条点赞内容,可以通过madd批量进行添加。
bf.add user:visits user:1:article:3
通过bf.exists命令判断用户是否浏览过该文章,浏览过的内容将会返回1,否则返回0。
bf.exists user:visits user:1:article:3