Redis 7.x 系列【10】数据类型之有序集合(ZSet)

发布于:2024-06-28 ⋅ 阅读:(20) ⋅ 点赞:(0)

有道无术,术尚可求,有术无道,止于术。

本系列Redis 版本 7.2.5

源码地址:https://gitee.com/pearl-organization/study-redis-demo

1. 概述

ZSet 是一种有序集合类型,可以存储不重复的元素,并且给每个元素赋予一个 double 类型的排序权重值(score)。

2. 常用命令

ZSet 相关所有命令:

命名 描述
BZMPOP 按照指定的排序方式推出多个队列中指定数量的元素
BZPОPMAX ZPOPMAX 的阻塞版本,作用相同,只是在目标集合中没有元素时会阻塞,timeout 参数指定了过期时间 (0 表示永不超时)
BZPOPMIN ZPOPMAX 一样,只是返回 score 最小的
ZADD 向有序集合添加一个或多个成员,或者更新已存在成员的分数
ZCARD 获取有序集合的成员数
ZCOUNT 计算在有序集合中指定区间分数的成员数
ZDIFF 返回集合之间的差集
ZDIFFSTORE 返回集合之间的差集,并将结果存储在另一个新的有序集合中
ZINCRBY 有序集合中对指定成员的分数加上增量 increment
ZINTER 用于计算多个有序集合的交集
ZINTERCARD 用于计算多个有序集合的交集,并返回成员个数
ZINTERSTORE 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key
ZLEXCOUNT 计算有序集合中指定区间内成员的数量
ZMPOP 弹出一个或多个成员
ZMSCORE 从有序集合中获取多个成员的分数(score
ZPOPMAX 用于删除并返回集合中分数(score)最高的一个或多个元素。如果集合为空,则命令不执行任何操作
ZPOPMIN 用于删除并返回集合中分数(score)最低的一个或多个元素。如果集合为空,则命令不执行任何操作
ZRANDMEMBER 随机获取一个或多个元素
ZRANGE 获取指定范围内的成员
ZRANGEBYLEX 根据成员名称的字典顺序来返回有序集合中指定区间的成员。注意是基于成员名称的字典顺序,而不是分数(score)的大小
ZRANGEBYSCORE 返回有序集中指定分数区间内的成员,分数从高到低排序
ZRANGESTORE 绍 返回集合中指定排名范围内的成员,并将结果存储到指定key
ZRANK 返回有序集合中指定成员的索引
ZREM 移除有序集合中的一个或多个成员
ZREMRANGEBYLEX 移除有序集合中给定的字典区间的所有成员
ZREMRANGEBYRANK 移除有序集合中给定的排名区间的所有成员
ZREMRANGEBYSCORE 移除有序集合中给定的分数区间的所有成员
ZREVRANGE 返回有序集中指定区间内的成员,通过索引,分数从高到底
ZREVRANGEBYLEX 根据字典范围返回成员,返回的成员顺序是反向的,即从高到低的字典顺序
ZREVRANGEBYSCORE 返回指定分数范围内的成员,并按照分数从高到低进行排序
ZREVRANK 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
ZSCAN 迭代有序集合中的元素(包括元素成员和元素分值)
ZSCORE 返回有序集中,成员的分数值
ZUNION 计算一个或多个有序集的并集
ZUNIONSTORE 计算一个或多个有序集的并集,并存储在新的 key

2.1 ZADD

ZADD 命令用于将一个或多个元素及其 score 值加入到有序集 key 中。

注意事项:

  • 如果某个 member 已经是有序集的成员,那么更新这个 memberscore 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。
  • 如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
  • key 存在但不是有序集类型时,返回一个错误。
  • score 值可以是整数值或双精度浮点数,score 可为正也可以为负。
  • 获取一个成员当前的分数可以使用 ZSCORE 命令,也可以用它来验证成员是否存在。

基本语法:

ZADD key [NX|XX] [CH] [INCR] score member [score member …]

添加单个元素:

redis> ZADD page_rank 10 google.com
(integer) 1

添加多个元素:

redis> ZADD page_rank 9 baidu.com 8 redis.com.cn
(integer) 2

redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "redis.com.cn"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"

添加已存在元素,且 score 值不变:

redis> ZADD page_rank 10 google.com
(integer) 0

redis> ZRANGE page_rank 0 -1 WITHSCORES  # 没有改变
1) "redis.com.cn"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"

添加已存在元素,但是改变 score 值:

redis> ZADD page_rank 6 redis.com.cn
(integer) 0

redis> ZRANGE page_rank 0 -1 WITHSCORES  # redis.com.cn 元素的 score 值被改变
1) "redis.com.cn"
2) "6"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"

ZADD 命令支持参数,参数位于 key 名字和第一个 score 参数之间(GTLTNX 三者互斥不能同时使用):

  • XX: 仅更新存在的成员,不添加新成员。
  • NX:不更新存在的成员,只添加新成员。
  • LT: 更新新的分值比当前分值小的成员,不存在则新增。
  • GT: 更新新的分值比当前分值大的成员,不存在则新增。
  • CH:返回变更成员的数量。变更的成员是指新增成员 和 score 值更新的成员,命令指明的和之前 score 值相同的成员不计在内。 在通常情况下,`ZADD 返回值只计算新添加成员的数量。
  • INCRZADD 使用该参数与 ZINCRBY 功能一样。一次只能操作一个 score-element 对。

Redis 有序集合的分数使用双精度 64 位浮点数表示。在 Redis 所支持的平台上,称为 IEEE 754 floating point number,它能包括的整数范围是-(2^53) +(2^53)。或者说是-90071992547409929007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。

有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。 分数可以通过 ZADD 命令进行更新或者也可以通过 ZINCRBY 命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。

有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。当多个成员有相同的分数时,他们将是按字典排序(ordered lexicographically)(仍由分数作为第一排序条件,然后,相同分数的成员按照字典序排序)。

字典顺序排序用的是二进制,它比较的是字符串的字节数组。如果用户将所有元素设置相同分数(例如 0 ),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用 ZRANGEBYLEX 命令(注:范围查询分数可以使用ZRANGEBYSCORE 命令)。

2.2 ZCARD

ZCARD 命令用于返回有序集的成员个数,当 key 不存在时,返回 0 。

基本语法:

ZCARD key 

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZCARD myzset
(integer) 2

2.3 ZSCORE

ZSCORE 命令用于返回有序集 key.中成员 member 的分数,返回值为字符串格式的双精度浮点数。如果有不存在的 member ,或者 key 不存在,返回 nil

基本语法:

ZSCORE key member

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZSCORE myzset "one"
"1"

2.4 ZRANGE

ZRANGE 命令返回有序集中指定区间内的成员,其中成员的按分数值递增(从小到大)来排序,具有相同分数值的成员按字典序排列。

注意事项:

  • 如果你需要成员按值递减来排列,请使用 ZREVRANGE命令。
  • 下标参数 startstop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
  • 也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
  • startstop 都是包含在内的区间,因此例如 ZRANGE myzset 0 1 将会返回有序集合的第一个和第二个元素。
  • 超出范围的索引不会产生错误。 如果 start 参数的值大于有序集合中的最大索引,或者 start > stop ,将会返回一个空列表。 如果 stop 的值大于有序集合的末尾,会将其视为有序集合的最后一个元素。
  • 可以传递 WITHSCORES 选项,以便将元素的分数与元素一起返回。这样返回的列表将包含 value1,score1,...,valueN,scoreN ,而不是 value1,...,valueN 。 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或元组)。

基本语法:

ZRANGE key start stop [WITHSCORES]

简单示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"
redis> ZRANGE myzset 2 3
1) "three"
redis> ZRANGE myzset -2 -1
1) "two"
2) "three"

WITHSCORES 示例:

redis> ZRANGE myzset 0 1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"

2.5 ZREVRANGE

ZREVRANGE 命令返回有序集中,指定区间内的成员。其中成员的位置按 score 值递减(从高到低)来排列。除了成员排序相反外,其他方面和 ZRANGE 命令一样。

基本语法:

ZREVRANGE key start stop [WITHSCORES]

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREVRANGE myzset 0 -1
1) "three"
2) "two"
3) "one"
redis> ZREVRANGE myzset 2 3
1) "one"
redis> ZREVRANGE myzset -2 -1
1) "two"
2) "one"

2.6 ZRANK

ZRANK 命令返回有序集中成员的排名,其中有序集成员按 score 值从低到高排列。排名从 0 开始,也就是说,分值最低的成员排名为 0

基本语法:

ZRANK key member

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZRANK myzset "three"
(integer) 2
redis> ZRANK myzset "four"
(nil)

2.7 ZREM

ZREM 命令用于从有序集合中删除指定的成员,如果 member 不存在则被忽略。当 key 存在,但是不是有序集合类型时,返回类型错误。

基本语法:

ZREM key member [member ...]

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREM myzset "two"
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "three"
4) "3"

2.8 ZPOPMIN

ZPOPMIN 删除并返回最多 count 个有序集合 key 中最低得分的成员。返回值为删除的元素和分数列表。

注意事项:

  • 如未指定,count 的默认值为 1
  • 指定一个大于有序集合的候选总数的 count 不会产生错误。
  • 当返回多个元素时候,得分最低的元素将是第一个元素,然后是分数较高的元素。

基本语法:

ZPOPMIN key [count]

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZPOPMIN myzset
1) "one"
2) "1"

2.9 ZPOPMAX

ZPOPMAX 删除并返回最多 count 个有序集合 key 中的最高得分的成员。返回值为删除的元素和分数列表。

注意事项:

  • 如未指定,count 的默认值为 1
  • 指定一个大于有序集合的候选总数的 count 不会产生错误。
  • 当返回多个元素时候,得分最高的元素将是第一个元素,然后是分数较低的元素。

基本语法:

ZPOPMAX key [count]

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZPOPMAX myzset
1) "three"
2) "3"

2.10 ZINCRBY

ZINCRBY 为有序集 key 的成员 memberscore 值加上增量 increment 。返回值为以字符串形式表示的成员的新 score 值(双精度浮点数)。

注意事项:

  • key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member
  • key 不是有序集类型时,返回"ERR WRONGTYPE Operation against a key holding the wrong kind of value"
  • score 值可以是字符串形式表示的整数值或双精度浮点数。
  • 可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -2 member ,就是让 memberscore 值减去 2

基本语法:

ZINCRBY key increment member

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZINCRBY myzset 2 "one"
"3"
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "two"
2) "2"
3) "one"
4) "3"

2.11 集合运算

Set 一样,也支持集合运算:

    • ZINTER
    • ZINTERCARD
    • ZINTERSTORE
    • ZUNION
    • ZUNIONSTORE
    • ZDIFF
    • ZDIFFSTORE

3. 应用场景

ZSetSet 的基础上增加了分值排序,常用于排行榜场景,比如热搜、成绩排名等。
在这里插入图片描述

例如,添加搜索消息,并初始化访问值为 1

localhost:0>ZADD msg_rank 1 msg_1
"1"
localhost:0>ZADD msg_rank 1 msg_2
"1"
localhost:0>ZADD msg_rank 1 msg_3
"1"

用户点击消息时,增加访问次数:

"1"
localhost:0>ZINCRBY msg_rank 1 msg_2
"1"
localhost:0>ZINCRBY msg_rank 1 msg_3
"2"
localhost:0>ZINCRBY msg_rank 1 msg_3
"3"

显示热搜前十排行榜:

localhost:0>ZREVRANGE msg_rank 0 9 WITHSCORES
 1)  "msg_3"
 2)  "3"
 3)  "msg_2"
 4)  "1"
 5)  "msg_1"
 6)  "1"