11.Reids的特殊数据类型

Reids中,集合是一个常见的数据类型

而集合中经常面对一些常见操作

手机APP上的用户登录信息,一天对应一系列用户ID或者移动设备ID

电商网站上商品的评论列表

用户在手机APP上的签到打卡记录,一天对应多个用户的记录

应用网站上的网页访问信息,一个网站对应一系列的访问信息

对于这些常见的业务场景,通常会延伸会一些对集合中数据进行统计的操作

比如移动应用中,统计每天新增用户数和留存用户数

电商网站评论中,统计最新的评论

签到打卡中,统计一个月内连续打开的用户数

网页的访问记录中,需要统计独立访客数

这样,我们就需要对集合进行不同的操作,包含聚合统计,排序统计,二值状态统计,基数统计

我们按照上面的顺序,依次说明不同的统计方式及其Reids中的实现

1.聚合统计

比如常见的统计APP中每天的新增用户数和第二天留存用户数,

对于这个任务,我们可以先使用一个集合记录所有登录过APP的用户ID,然后使用另一个集合记录每天登陆的APP的用户ID,然后进行聚合

对于这种需要去重用户ID的操作,首选的数据结构就是Set

首先先使用一个集合统计所有登录过App的用户ID,直接使用Set类型,将key设置为user-login,记录的是用户ID,value是一个Set集合,保存了所有登录过App的用户Id

图片

除此外,我们还需要保存每一天登录的用户ID,记录到一个新集合中,将这个集合叫做每日用户Set

key一般为: user-login-{date},value是Set集合,记录当前登录过的用户ID

统计每天新增的用户的时候,只需要计算每日用户Set和全用户Set的差集就可以了

比如如下的操作

SDIFFSTORE user-login-new user-login-20210804 user-login

获取到差集,这样user-loign-new就记录了新增的用户Id

然后再将新增的加入到user-login中

SUNIONSTORE user-login user-login user-login-20210804

计算留存也很简单了

只需要保存今天和前一天的交集就可以了

SINTERSTORE user-login-rem user-login-20210803 user-login-20210804

这些都是常见的交集差集的统计方式,但是由于Reids的单线程,可能会导致Reids实例阻塞

2.然后排序统计

比如查找电商网站上的最新评论列表

在Reids的常用的集合数据结构中 List 和 Sorted Set就是有序的集合

List是保证了元素进入的顺序,Sorted Set则可以根据权重进行排序,在元素中插入Sorted Set确定权重值,先插入的权重小,后插入的权重大

但是List有一些缺陷,比如在查询评论分页的时候,如果查询第二页,可以执行如下的命令

LRANGE producet 5,9

获取第二页的数据,但是在展示第二页的时候,产生了一个新的评论G,评论G就会被LPUSH命令插入到List的对头,这样第二页会将第一页原本不在的数据展示出来

这就是Sorted Set的优点,其实根据元素的实际权重来排序并获取数据的

我们可以按照时间的先后给每个评论设置一个权重值,然后保存到Sorted Set,并利用ZRANGEBYSCORE命令进行返回规定的数据

比如下面的操作

ZRANGEBYSCORE comments X Y

3.二值状态统计

有一种场景就是集合元素的取值就只有0和1两种,在签到记录中,记录签到就只有签到(1)或者未签到(0),这就是二值状态

统计签到的时候,一天的签到用一个bit位就表示,一年的签到也就365个bit位

对于这种bit的操作,Redis提供了Bitmap,利用String作为底层数据结构,将字节数组的每个bit利用起来,表示一个元素的二值状态,Bitmap就可以看做是一个bit数组

其提供了GETBIG 和 SETBIT操作,根据偏移量来对一个bit位进行读写,Bitmap的偏移量是从0开始的,这是操作中需要记住的,Bitmap还提供了BITCOUNT,来统计这个bit数组中所有 ”1″的个数

比如,我们先对一个用户进行记录

SETBIT user-sigin-3000-202108  2 1

表示id为3000的用户在8月3号签到了

BITCOUNT user-sign-3000-202108

这样就知道这个用户在8月份的签到记录了

而且Bitmap支持利用BITOP命令对多个Bitmap做 与 或 异或这类操作,并保存在一个Bitmap中

我们按照与的操作为例讲解一下

三个Bitmap bm1 bm2 bm3对应Bit位做与的操作,保存到一个新的Bitmap中

BITOP AND resmap bm1 bm2 bm3

图片

在记录数据的二值状态的地方,使用Bitmap是一个非常高效的方式,记录海量数据时候能够有效的节省内存空间

3.基数统计

相对来说比较简单的一个统计方案,对应到之前说的场景,就是统计网页的UV

统计UV的时候,需要进行用户层面的去重,常见的默认支持去重的集合类型,就是Set

Set的去重功能就能保证不会记录重复的用户,而且支持SCARD去返回一个集合中的元素个数

但是如果页面成千上千万,每个页面都有一个Set,消耗的内存可能很大

或者使用Hash类型记录UV,将用户ID作为key,利用HSET将用户ID记录一个值

HSET page1:uv user1 1

但是也存在一个内存消耗大的问题

那么是否Redis提供了相对好用的数据类型?其中就是HyperLogLog了

HyperLogLog是一个统计基数的数据集合类型,当集合元素数量多的时候,计算基数所需的空间是固定的,而且很小

统计UV的时候,可以使用PFADD命令将新访问的用户添加到HyperLogLog中

PFADD page1:uv user1 user2 user3 user1

而且可以使用PFCOUNT命令来直接获取page1的UV值了,其作用就是返回HyperLogLog的统计结果

PFCOUNT page1:uv

但是HyperLogLog的统计是基于概率的,所以统计数据有一定的误差,但是误差不会很大

将不同的数据类型的支持总结在了下面

图片

最后说一句

如果在统计用户签到的时候

将使用命令改为

SETBIT uid:sign:20200803 3000 1

是不是方便统计呢,有没有弊端?

发表评论

邮箱地址不会被公开。 必填项已用*标注