1、简介
- Redis的四种统计模式包括聚合统计、排序统计、二值状态统计和基数统计。
2、聚合统计
2.1概述
- 定义:聚合统计是指统计多个集合元素的聚合结果,包括交集统计、差集统计和并集统计。
- 场景:在移动应用中,可以统计每天的新增用户数和第二天的留存用户数;在电商网站的商品评论中,可以统计评论列表中的最新评论;在签到打卡中,可以统计一个月内连续打卡的用户数;在网页访问记录中,可以统计独立访客(UV)量。
- 实现方式:Redis的Set类型支持集合内的增删改查操作,并且支持多个集合间的交集、并集、差集操作。但在数据量较大的情况下,直接执行这些计算可能会导致Redis实例阻塞。为了避免阻塞,可以从主从集群中选择一个从库专门负责聚合计算,或者将数据读取到客户端,在客户端完成聚合统计。
2.2主要方法和数据结构
2.2.1数据结构
- Set(集合)
- 应用场景:适用于聚合计算(并集、交集、差集)场景,如点赞、共同关注、抽奖活动等。
- 底层实现:由哈希表或整数集合实现。如果集合中的元素都是整数且元素个数小于512个(默认值,可通过
set-maxintset-entries
配置),Redis会使用整数集合作为Set类型的底层数据结构;否则,使用哈希表。 - 主要命令:
SUNIONSTORE
:计算多个集合的并集,并将结果存储在新的集合中。SDIFFSTORE
:计算一个集合与另一个集合的差集,并将结果存储在新的集合中。SINTERSTORE
:计算多个集合的交集,并将结果存储在新的集合中。
- Zset(有序集合)
- 应用场景:适用于需要按照特定分数进行排序的场景,如排行榜、电话和姓名排序等。
- 底层实现:由压缩列表或跳表实现。如果有序集合的元素个数小于128个,并且每个元素的值小于64字节时,Redis会使用压缩列表作为Zset类型的底层数据结构;否则,使用跳表。
- 主要命令:
ZADD
:向有序集合中添加一个或多个元素,或者更新已存在元素的分数。ZRANGE
、ZREVRANGE
:根据分数范围获取有序集合中的元素,前者按分数升序排列,后者按分数降序排列。ZRANGEBYSCORE
、ZREVRANGEBYSCORE
:通过分数范围查询有序集合中的元素,并返回结果。
2.2.2主要方法
- 交集统计:使用
SINTERSTORE
命令计算多个集合的共有元素。 - 差集统计:使用
SDIFFSTORE
命令统计一个集合相对于另一个集合独有的元素。 - 并集统计:使用
SUNIONSTORE
命令统计多个集合的所有元素。 - 有序集合排序统计:利用Zset的分数属性,通过
ZRANGE
、ZREVRANGE
、ZRANGEBYSCORE
、ZREVRANGEBYSCORE
等命令,根据分数进行排序并获取元素。
3、排序统计
3.1概述
- 定义:排序统计涉及到数据的排名和顺序。
- 场景:排行榜、按收藏或点赞数排序的场景等。
- 实现方式:Redis的List和Sorted Set类型属于有序集合。List是按照元素进入List的顺序进行排序的,而Sorted Set可以根据元素的权重来排序。在需要分页显示或数据更新频繁的场景中,Sorted Set是一个更好的选择,因为它能根据元素的实际权重来排序和获取数据。
3.2主要方法和数据结构
3.21数据结构
- List(列表):
- 列表是简单的字符串列表,按照插入顺序排序。可以从头部(左边)或尾部(右边)添加元素。
- 底层基于链表实现,头尾操作效率高,中间操作效率低。
- 可以使用LPUSH、RPUSH、LINDEX等命令进行排序和访问操作。
- Set(集合):
- Set是String类型的无序集合,基于哈希表实现。
- 本身就是一个键值对集合,键为元素值,值为null。
- 集合中的元素不重复,可以使用SORT命令进行排序,但需要注意,对Set类型排序时会忽略元素的分数,只针对元素自身的值进行排序。
- Zset(有序集合):
- Zset和Set一样也是String类型元素的集合,但每个元素都会关联一个double类型的分数(score)。
- 通过分数来为集合中的成员进行从小到大的排序。
- 成员是唯一的,但分数可以重复。
- 底层数据结构采用SkipList和哈希表(HT/Dict)组合方式实现。
- 可以使用ZADD、ZRANGE、ZREVRANGEBYSCORE等命令进行添加、排序和访问操作。
3.2.2主要方法
- List排序:
- 通过LPUSH、RPUSH等命令向列表中添加元素。
- 使用LINDEX命令根据索引获取元素。
- 使用LLEN命令获取列表长度。
- 可以通过SORT命令对列表进行排序,但通常List本身并不直接支持高效的排序操作,因为它主要是基于链表实现的。
- Set排序:
- 使用SADD命令向集合中添加元素。
- 使用SMEMBERS命令获取集合中所有元素。
- 使用SORT命令对集合进行排序,但会忽略元素的分数,只根据元素值排序。
- Zset排序:
- 使用ZADD命令向有序集合中添加元素,并指定分数。
- 使用ZRANGE、ZREVRANGE等命令根据分数范围获取元素。
- 使用ZRANGEBYSCORE、ZREVRANGEBYSCORE等命令根据分数进行排序并获取元素。
- 分数可以用于实现高效的排序功能,因为有序集合既可以根据分数进行排序,又可以保持插入顺序。
4、二值状态统计
4.1概述
- 定义:二值状态统计是指集合元素的取值只有0和1两种状态,通常用于表示某个事件是否发生或某个条件是否成立。
- 场景:例如每天的签到打卡信息,用户要么打卡了(1),要么没打卡(0)。
- 实现方式:对于二值状态统计,Redis中的Bitmap是一个有效的工具。用户一天的打卡状态可以用1个bit位来表示(0或1),这样可以有效地节省内存空间。
4.2主要方法和数据结构
4.2.1数据结构:Bitmap
- 基本概念:Bitmap可以看作是一个bit数组,其中每个bit位表示一个元素的二值状态(0或1)。在Redis中,String类型会保存为二进制的字节数组,Redis则利用这些字节数组的每个bit位来表示二值状态。
- 内存效率:由于每个元素的状态只需要一个bit位来表示,因此Bitmap在存储大量二值状态时非常节省内存。例如,一亿个用户的二值状态只需要大约12MB的内存(100000000 / 8 / 1024 / 1024 = 12MB)。
4.2.2主要方法
- SETBIT:设置或清除指定key的value在offset处的bit值(只能是0或1)。
- 语法:
SETBIT key offset value
- 示例:
SETBIT uid:sign:3000:20200803 2 1
(表示用户ID为3000在2020年8月3日的某个时刻签到了,用bit位的第3位(从0开始计数)来表示)
- 语法:
- GETBIT:获取指定key的value在offset处的bit位的值。
- 语法:
GETBIT key offset
- 示例:
GETBIT uid:sign:3000:20200803 2
(获取用户ID为3000在2020年8月3日的签到状态)
- 语法:
- BITCOUNT:统计指定key的value中值为1的bit位的数量。
- 语法:
BITCOUNT key [start] [end]
- 示例:
BITCOUNT uid:sign:3000:202008
(统计用户ID为3000在2020年8月的签到次数)
- 语法:
- BITOP:对多个Bitmap按位进行“与”、“或”和“异或”操作,并将结果保存到一个新的Bitmap中。
- 语法:
BITOP operation destkey key [key ...]
- 示例:使用
BITOP AND resmap bm1 bm2 bm3
将bm1、bm2和bm3进行按位与操作,结果保存到resmap中
- 语法:
5、基数统计
5.1概述
- 定义:基数统计是指统计一个集合中不重复的元素个数,例如统计UV(独立访客)。
- 场景:在网页访问记录中,需要统计独立访客的数量。
- 实现方式:Redis的Set类型默认支持去重,但在数据很多时,Set类型也会消耗很大的内存空间。此时,可以使用Redis提供的HyperLogLog。HyperLogLog是一种用于统计基数的数据集合类型,它的最大优势在于当集合元素数量非常多时,它计算基数所需的空间总是固定的,而且还很小。每个HyperLogLog只需要花费12KB内存,就可以计算接近2^64个元素的基数。但请注意,HyperLogLog的统计结果是有一定误差的,标准误算率是0.81%。
5.2主要方法和数据结构
5.2.1HyperLogLog数据结构
HyperLogLog是Redis提供的一种特殊数据结构,用于高效地估计数据集的基数(即不重复元素的数量)。它具有以下特点:
- 内存效率:HyperLogLog使用固定大小的内存来存储估计值,不受集合中元素数量的影响。这使得它适用于处理大规模数据集,内存占用是固定的。
- 误差率:HyperLogLog提供的是一种近似计数,而不是精确计数。其标准误差率约为0.81%,这对于许多应用场景来说已经足够准确。
- 合并操作:HyperLogLog支持多个集合的合并操作,可以方便地计算多个数据源的并集基数。
5.2.2主要方法
HyperLogLog在Redis中提供了以下几个主要命令:
- PFADD:将一个或多个元素添加到HyperLogLog中。
- 语法:
PFADD key element [element ...]
- 示例:
PFADD myloglog user1 user2 user3
- 语法:
- PFCOUNT:返回HyperLogLog的基数估计值,即估计的不同元素的数量。
- 语法:
PFCOUNT key [key ...]
- 示例:
PFCOUNT myloglog
- 语法:
- PFMERGE:将多个HyperLogLog合并为一个新的HyperLogLog。
- 语法:
PFMERGE destkey sourcekey [sourcekey ...]
- 示例:
PFMERGE mergedloglog myloglog1 myloglog2 myloglog3
- 语法: