sort set (zset) 简述
前面提到,set 这种数据类型具有 无序性 和 不可重复性(或者称 唯一性) ,即在 set 数据类型的底层中,其仅存储 key(string 类型),不存储 value(因为都是 nil)
sort set (有序集合)的说明:
- 会对集合中的每一个成员进行排序。因为 sort set 中的每一个成员都关联一个 score 分值,按照分值的从小到大排序也就实现了对每一个成员的排序。
- 集合中的成员具有唯一性,但 score 分值可以允许有重复的。
- 当遇到了多个成员的 score 分值相同时,按照字典排序(一种字符串排序方法,来源于英语字典,即第一个字母按照 a-z 的方式排序,如果第一个字母相同,则比较第二个字母,以此类推。比如 apple 就排在 banana 前面,因为 a 在 b 前面 )
- 每个成员都是 string 类型,score 分值都是 double 类型(双精度浮点数)
- 由于所有的命令都是以 z 开头,因此有些资料也将 sort set 数据类型称为 zset 数据类型
- 一个有序集合最大可以有 2^32 – 1 个成员
zadd
命令
用来往有序集合中添加单个或多个成员,也可以用来更新已存在成员的分值。
192.168.100.3:6379> select 4
OK
192.168.100.3:6379[4]> keys *
(empty array)
192.168.100.3:6379[4]> help zadd
ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
summary: Adds one or more members to a sorted set, or updates their scores. Creates the key if it doesn't exist.
since: 1.2.0
group: sorted-set
NX 可选参数:当这个 key 不存在时,用来添加新 key 和新成员。
XX 可选参数:当这个 key 存在时,用来更新集合中的已有成员。
GT 可选参数:当新分值大于当前分值时才更新现有成员。若现有成员不存在,则新增成员。
LT 可选参数:当新分值小于当前分值时才更新现有成员。若现有成员不存在,则新增成员。
CH 可选参数:默认情况下,使用 zadd 命令返回新添加成员的总数量;若使用 CH ,则返回变更的成员总数。「变更的成员」指的是新添加的成员和已经更新分数的成员。
INCR 可选参数:针对一个成员,让数值型的成员自增。
# 比如新添加一些游戏玩家的分数数据
192.168.100.3:6379[4]> zadd player:name 60 frank 90 jack 36.5 tom 100 allen 90 jace 90 jade 50 alexander 60 truman 80 jango
(integer) 9
# 查看所有的成员
## tom 分数最低,排在最前面;jack、jace、jade的分数相同,按照字典排序;allen 分数最高,排在最后面
192.168.100.3:6379[4]> zrange player:name 0 -1
1) "tom"
2) "alexander"
3) "frank"
4) "truman"
5) "jango"
6) "jace"
7) "jack"
8) "jade"
9) "allen"
# 使用 XX 可选参数,更新已有成员的分数
192.168.100.3:6379[4]> zadd player:name XX 70 frank
(integer) 0
192.168.100.3:6379[4]> zrange player:name 0 -1
1) "tom"
2) "alexander"
3) "truman"
4) "frank"
5) "jango"
6) "jace"
7) "jack"
8) "jade"
9) "allen"
zrange
命令
用来查看范围内的成员以及其分数。使用 0 下标表示第一个成员,使用 1 下标表示第二个成员,以此类推;使用 -1 下标表示倒数第一个成员,-2 下标表示倒数第二个成员,以此类推。
# 查看所有的成员
## 用 0 表示起始范围的第一个成员,用 -1 表示结束范围的最后一个成员,这样就指定了一个范围区间
192.168.100.3:6379[4]> ZRANGE player:name 0 -1
1) "tom"
2) "alexander"
3) "truman"
4) "frank"
5) "jango"
6) "jace"
7) "jack"
8) "jade"
9) "allen"
# 查看所有成员以及它们的分数
192.168.100.3:6379[4]> ZRANGE player:name 0 -1 withscores
1) "tom"
2) "36.5"
3) "alexander"
4) "50"
5) "truman"
6) "60"
7) "frank"
8) "70"
9) "jango"
10) "80"
11) "jace"
12) "90"
13) "jack"
14) "90"
15) "jade"
16) "90"
17) "allen"
18) "100"
zrevrange
命令
同 zrange
命令,只不过将分值按照从大到小的方式对成员进行排序。
192.168.100.3:6379[4]> zrevrange player:name 0 -1 withscores
1) "allen"
2) "100"
3) "jade"
4) "90"
5) "jack"
6) "90"
7) "jace"
8) "90"
9) "jango"
10) "80"
11) "frank"
12) "70"
13) "truman"
14) "60"
15) "alexander"
16) "50"
17) "tom"
18) "36.5"
zrangebyscore
命令
通过指定分数范围筛选出对应成员及其分数。请注意!默认分值范围是闭区间,即 [start-score,stop-score]
# 筛选出分值在 [50,80] 范围内的成员以及其分数
192.168.100.3:6379[4]> ZRANGEBYSCORE player:name 50 80 withscores
1) "alexander"
2) "50"
3) "truman"
4) "60"
5) "frank"
6) "70"
7) "jango"
8) "80"
# 您也可以使用 "(" 符号将闭区间变成开区间,例如 (50,80]
192.168.100.3:6379[4]> ZRANGEBYSCORE player:name (50 80 withscores
1) "truman"
2) "60"
3) "frank"
4) "70"
5) "jango"
6) "80
# 全开区间
192.168.100.3:6379[4]> ZRANGEBYSCORE player:name (50 (80 withscores
1) "truman"
2) "60"
3) "frank"
4) "70"
# 您也可以通过数学中的 负无穷(-inf) 和 正无穷(+inf) 来显示出所有的成员以及对应分数
192.168.100.3:6379[4]> ZRANGEBYSCORE player:name -inf +inf withscores
1) "tom"
2) "36.5"
3) "alexander"
4) "50"
5) "truman"
6) "60"
7) "frank"
8) "70"
9) "jango"
10) "80"
11) "jace"
12) "90"
13) "jack"
14) "90"
15) "jade"
16) "90"
17) "allen"
18) "100"
# 您还可以通过 limit 关键字在分值范围的基础上进一步筛选
## 注:limit 是从 0 开始记。例如 "limit 2 3" 表示从第三个成员开始并往后显示3个成员
192.168.100.3:6379[4]> ZRANGEBYSCORE player:name -inf +inf withscores limit 2 3
1) "truman"
2) "60"
3) "frank"
4) "70"
5) "jango"
6) "80"
zrevrangebyscore
命令
同 zrangebyscore
命令,只不过将分值按照从大到小的方式对成员进行排序。
192.168.100.3:6379[4]> zrevrangebyscore player:name 80 30
1) "jango"
2) "frank"
3) "truman"
4) "alexander"
5) "tom"
# limit 关键字也同样适用
192.168.100.3:6379[4]> zrevrangebyscore player:name 80 30 withscores limit 1 3
1) "frank"
2) "70"
3) "truman"
4) "60"
5) "alexander"
6) "50"
zcard
命令
查看集合里的成员个数。当 key 不存在时,命令执行后返回 0
192.168.100.3:6379[4]> zcard player:name
(integer) 9
192.168.100.3:6379[4]> zcard player:test
(integer) 0
zcount
命令
指定 score 分值的范围并返回这个分值范围内的成员个数。
# 默认的数字是闭区间,即 [50,80]
192.168.100.3:6379[4]> zcount player:name 50 80
(integer) 4
# 你也可以使用 "(" 符号将其变成开区间
192.168.100.3:6379[4]> zcount player:name (50 (80
(integer) 2
# 也支持负无穷和正无穷的方式
192.168.100.3:6379[4]> zcount player:name -inf +inf
(integer) 9
zscore
命令
查看单个成员的分值。当 key 不存在或成员不存在时,返回 (nil)
# 成员不存在时
192.168.100.3:6379[4]> zscore player:name franl
(nil)
# key 不存在时
192.168.100.3:6379[4]> zscore player1:name frank
(nil)
192.168.100.3:6379[4]> zscore player:name frank
"70"
zrank
命令
依据从小到大的分值对成员进行排序并返回单个成员所在的索引排名(索引排名从 0 开始记)
192.168.100.3:6379[4]> zrange player:name 0 -1
1) "tom"
2) "alexander"
3) "truman"
4) "frank"
5) "jango"
6) "jace"
7) "jack"
8) "jade"
9) "allen
# 返回的索引排名为 6,即在第 7 位置
192.168.100.3:6379[4]> zrank player:name jack
(integer) 6
# 加上 withscore 参数,可以查看该成员的分值
192.168.100.3:6379[4]> zrank player:name jack withscore
1) (integer) 6
2) "90"
zrevrank
命令
同 zrank
命令,依据从大到小的分值对成员进行排序并返回单个成员所在的索引排名(索引排名从 0 开始记)
192.168.100.3:6379[4]> zrevrange player:name 0 -1 withscores
1) "allen"
2) "100"
3) "jade"
4) "90"
5) "jack"
6) "90"
7) "jace"
8) "90"
9) "jango"
10) "80"
11) "frank"
12) "70"
13) "truman"
14) "60"
15) "alexander"
16) "50"
17) "tom"
18) "36.5"
192.168.100.3:6379[4]> zrevrank player:name tom
(integer) 8
zincrby
命令
您除了可以使用 zadd
更新已有成员的分数外,还可以使用 zincyby
命令将单个成员的分数增加或减少。
# 比如将 tom 这名玩家的分值增加 20.5
192.168.100.3:6379[4]> ZINCRBY player:name 20.5 tom
"57"
# 或者减少 10
192.168.100.3:6379[4]> ZINCRBY player:name -10 tom
"47"
与移除成员相关的命令
有三种方式(或三个命令)可以对成员进行移除,它们是:
zrem
– 以成员的名称进行移除,支持对单个或多个成员的移除zremrangebyrank
– 依据索引排名的范围对成员进行移除zremrangebyscore
– 依据分值的范围对成员进行移除,支持使用 -inf 和 +inf,也支持使用 "(" 开区间符号
以下为命令演示:
# 删除 frank 和 tom 这两个成员
192.168.100.3:6379[4]> zrem player:name frank tom
(integer) 2
# 删除索引排名 1~3 范围的成员
192.168.100.3:6379[4]> zrange player:name 0 -1
1) "alexander"
2) "truman"
3) "jango"
4) "jace"
5) "jack"
6) "jade"
7) "allen"
192.168.100.3:6379[4]> zremrangebyrank player:name 1 3
(integer) 3
192.168.100.3:6379[4]> zrange player:name 0 -1 withscores
1) "alexander"
2) "50"
3) "jack"
4) "90"
5) "jade"
6) "90"
7) "allen"
8) "100"
# 删除位于 [90,100] 分值区间内的成员
192.168.100.3:6379[4]> zremrangebyscore player:name 90 100
(integer) 3
192.168.100.3:6379[4]> zrange player:name 0 -1 withscores
1) "alexander"
2) "50"
特殊情况下的命令
有时,一个有序集合当中的所有成员都有着相同的分值,则它们会按照字典执行排序。zrangebylex
、zlexcount
、zremrangebylex
这三个命令就被使用在这种特殊情况。
zrangebylex
(从 6.2.0 开始被弃用)- 通过字典区间返回集合中的成员,仅用在分值相同的集合当中,已被弃用,可以使用 zrange
的 bylex 参数作为替代。该命令用法为——ZRANGEBYLEX key min max [LIMIT offset count] 。这里的 min 和 max 指的是字典序,闭区间使用 "[" 符号,开区间使用 "(" 符号,负无穷和正无穷使用 "-" 和 "+" 。limit 从 0 开始记。
zlexcount
– 指定字典序的 min 和 max,返回位于这个区间范围内的成员数量。用法为——ZLEXCOUNT key min max。min 和 max 支持 "[" 符号、"(" 符号以及 "-" "+" 符号。
zremrangebylex
– 指定字典序的 min 和 max,删除位于这个区间范围内的成员。用法为——ZREMRANGEBYLEX key min max。min 和 max 支持 "[" 符号、"(" 符号以及 "-" "+" 符号。
为了方便演示,新增 key 以及新成员:
192.168.100.3:6379[4]> zadd test:1 100 ab 100 ac 100 bd 100 dz 100 ji 100 lo 100 km
(integer) 7
192.168.100.3:6379[4]> zrange test:1 0 -1 withscores
1) "ab"
2) "100"
3) "ac"
4) "100"
5) "bd"
6) "100"
7) "dz"
8) "100"
9) "ji"
10) "100"
11) "km"
12) "100"
13) "lo"
14) "100"
# 指定 min 和 max ,查看位于这个区间内的成员
## 下面两条命令等价
192.168.100.3:6379[4]> zrangebylex test:1 [a (f
1) "ab"
2) "ac"
3) "bd"
4) "dz"
192.168.100.3:6379[4]> zrange test:1 [a (f bylex
1) "ab"
2) "ac"
3) "bd"
4) "dz"
192.168.100.3:6379[4]> zrangebylex test:1 - +
1) "ab"
2) "ac"
3) "bd"
4) "dz"
5) "ji"
6) "km"
7) "lo"
# 使用 - 和 +,并使用 limit 关键字进一步筛选
## 下面两条命令等价
192.168.100.3:6379[4]> zrangebylex test:1 - + limit 0 2
1) "ab"
2) "ac"
192.168.100.3:6379[4]> zrange test:1 - + bylex limit 0 2
1) "ab"
2) "ac"
# 使用 zlexcount 命令
192.168.100.3:6379[4]> zlexcount test:1 [a (f
(integer) 4
192.168.100.3:6379[4]> zlexcount test:1 - +
(integer) 7
# 使用 zremrangebylex 命令
192.168.100.3:6379[4]> zremrangebylex test:1 [a (f
(integer) 4
192.168.100.3:6379[4]> zrange test:1 0 -1
1) "ji"
2) "km"
3) "lo"
请注意!在成员分值相同的情况下时,比如有类似 d、doe、e、end、f、find 这样的成员,d 成员是排在 doe 的前面,请看下面的例子:
192.168.100.3:6379[4]> zadd test:2 100 d 100 doe 100 e 100 end 100 f 100 find
(integer) 6
192.168.100.3:6379[4]> zrange test:2 0 -1
1) "d"
2) "doe"
3) "e"
4) "end"
5) "f"
6) "find"
# doe、e、end 这三个成员会被删除
192.168.100.3:6379[4]> zremrangebylex test:2 (d (f
(integer) 3
192.168.100.3:6379[4]> zrange test:2 0 -1
1) "d"
2) "f"
3) "find"