API的理解和使用——有序集合
命令 | 功能 |
zadd key score member [score member … ] | 添加元素 |
zcard key | 计算成员个数 |
zscore key member | 计算某个成员分数 |
zrank key member zrevrank key member |
计算成员排名 |
zrem key member [member …] | 删除成员 |
zincrby key increment member | 增长成员分数 |
zrange key start end [withscores] zrevrabge key start end [withscores] |
返回指定排名范围内的成员 |
zrangebyscore key min max [withscores] zrevrangebyscore key max min [withscores] |
返回指定分数范围内的成员 |
zcount | 返回指定分数范围内成员个数 |
zremrangebyrank key start end | 删除指定排名内的升序元素 |
zremrangebyscore key min max | 删除指定分数范围内的成员 |
zinterstore destination numkeys key [key …] | 交集 |
zunionstore destination numkeys key [key …] | 并集 |
有序集合相对于哈希、列表、集合来说会有一点点陌生,但既然叫有序集合,那么它和集合必然有着联系,
它保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。
但是它和列表使用索引小标作为排序依据不同的是,它给每个元素设置一个分数(score)作为排序的依据。
有序集合提供了获取指定分数和元素范围查询、计算成员排名等功能,合理的利用有序集合,能帮助我们在实际开发中解决很多问题。
有序集合中的元素不能重复,但是score可以重复,就和一个班里的同学学号不能重复,但是考试成绩可以相同一样。
下面给出列表、集合、有序集合三者的异同点。
数据结构 | 是否允许重复元素 | 是否有序 | 有序实现方式 | 应用场景 |
列表 | 是 | 是 | 索引 | 时间轴、消息队列 |
集合 | 否 | 否 | 无 | 标签 |
有序集合 | 否 | 是 | score | 排行榜系统 |
下面按照集合内和集合外两个维度对有序集合的命令进行介绍。
先给出一个有序集合:NBA某一天的排名
胜差 | 球队 |
0 | BOS |
1.5 | CLE |
3.5 | TOR |
5 | WAS |
6.5 | DET |
7.5 | IND |
7.5 | NY |
8 | MIL |
1.集合内操作
(1)添加成员
命令:zadd key score member [score member … ]
127.0.0.1:6379> zadd NBA:east 0 BOS 1.5 CLE 3.5 TOR 5 WAS 6.5 DET (integer) 5 #返回结果为成功添加成员个数 127.0.0.1:6379> zadd NBA:east 7.5 IND 7.5 NY 8 MIL (integer) 3
有关zadd命令有两点需要注意:
第一,Redis3.2为zadd命令添加了nx、xx、ch、incr4个选项:
- nx:member必须不存在,才可以设置成功,用于添加
- xx:member必须存在,才可以设置成功,用于更新
- ch:返回此次操作后,有序集合元素和分数发生变化的个数
- incr:对score做增加,相当于后面介绍的zincrby
第二,有序集合相比集合提供了排序字段,但是也产生了代价,zadd的时间复杂度为O(log(n)),sadd的时间复杂度为O(1)。
127.0.0.1:6379> zcard NBA:east (integer) 8
(2)计算成员个数
命令:zcard key
与集合类型scard命令一样,返回集合的个数,zcard的时间复杂度为O(1)。
127.0.0.1:6379> zcard NBA:east (integer) 8
(3)计算某个成员的分数
命令:zscore key member
返回某个成员的分数,注意与排名分开,如果成员不存在则返回nil:
127.0.0.1:6379> zscore NBA:east IND "7.5" 127.0.0.1:6379> zscore NBA:east DET "6.5"
(4)计算成员的排名
命令:
zrank key member
zrevrank key member
zrank是分数从低到高返回排名。zrevrank反之。
127.0.0.1:6379> zrank NBA:east CLE (integer) 1 127.0.0.1:6379> zrank NBA:east BOS #从0开始 (integer) 0 127.0.0.1:6379> zrevrank NBA:east BOS (integer) 7 127.0.0.1:6379> zrevrank NBA:east CLE (integer) 6
(5)增加成员的分数
命令:zincrby key increment member
zincrby返回元素修改之后的分数:
127.0.0.1:6379> zscore NBA:east TOR "3.5" 127.0.0.1:6379> zincrby NBA:east 1 TOR #又输了场 "4.5"
(6)返回指定排名范围内的成员
命令:
zrange key start end [withscores]
zrevrange key start end [withscores]
有序集合是按照分值排名的,zrange是从低到高返回,zrevrange反之。
下面返回胜差最小,排名前三的,如果加上withscores选项,同时会返回成员分数:
127.0.0.1:6379> zrange NBA:east 0 2 #取前三个 1) "BOS" 2) "CLE" 3) "TOR" 127.0.0.1:6379> zrange NBA:east 0 2 withscores #附带分数 1) "BOS" 2) "0" 3) "CLE" 4) "1.5" 5) "TOR" 6) "4.5" 127.0.0.1:6379> zrevrange NBA:east 0 2 withscores #反向取 1) "MIL" 2) "8" 3) "NY" 4) "7.5" 5) "IND" 6) "7.5"
(7)返回指定分数范围内的成员
命令:
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
其中zrangebyscore按照分数从低到高返回,zrevrangebyscore反之。
127.0.0.1:6379> zrangebyscore NBA:east 3 6 #正着取分数3-6 1) "TOR" 2) "WAS" 127.0.0.1:6379> zrangebyscore NBA:east 3 6 withscores 1) "TOR" 2) "4.5" 3) "WAS" 4) "5" 127.0.0.1:6379> zrevrangebyscore NBA:east 2 0 withscores 1) "CLE" 2) "1.5" 3) "BOS" #反着取也就反着显示 4) "0"
同时min和max还支持开区间(小括号)和闭区间(中括号),-inf和+inf分别代表无限小和无限大:
127.0.0.1:6379> zrangebyscore NBA:east (6 +inf withscores 1) "DET" 2) "6.5" 3) "IND" 4) "7.5" 5) "NY" 6) "7.5" 7) "MIL" 8) "8"
(8)返回指定分数范围内的成员个数
命令:zcount key min max
127.0.0.1:6379> zcount NBA:east 2 5 (integer) 2 127.0.0.1:6379> zrangebyscore NBA:east 2 5 1) "TOR" 2) "WAS"
(9)删除成员
命令:zrem key member [member … ]
127.0.0.1:6379> zrem NBA:east MIL (integer) 1
(10)删除指定排名内的升序元素
命令:zremrangebyrank key start end
127.0.0.1:6379> zremrangebyrank NBA:east 0 2 #按照排名删,包含两边,所以是3 (integer) 3 127.0.0.1:6379> zcard NBA:east (integer) 4
(11)删除指定分数范围内的成员
命令:zremrangebyscore key min max
#删除大于八个胜场的球队 127.0.0.1:6379> zremrangebyscore NBA:east (7 +inf (integer) 2
2.集合间操作
将下面两个有序集合导入到Redis中。
127.0.0.1:6379> zadd user:ranking:1 1 kris 91 mike 200 frank 220 tim 250 martin 251 tom (integer) 6 127.0.0.1:6379> zadd user:ranking:2 8 james 77 mike 625 martin 888 tom (integer) 4
(1)交集
命令:
zinterstore destination numkeys key [key...] [weights weight [weight ... ]] [aggregate sum|min|max]
参数说明:
- destination:交集计算结果保存到这个键。
- numkeys:需要做交集计算键的个数。
- key [key … ]:需要做交集计算的键。
- weights weight [weight …]:每个键的权重,在做交集计算时,每个键中的每个member会将自己分数乘以这个权重,每个键的权重默认是1。
- aggregate sum|min|max:计算成员交集后,分值可以按照sum(和)、min(最小值)、max(最大值)做汇总,默认值是sum。
下面对两个集合取交集,weights和aggregate使用默认值:
127.0.0.1:6379> zinterstore user:ranking:1_inter_2 2 user:ranking:1 user:ranking:2 (integer) 3
如果想让user:ranking:2的权重变为0.5,并且集合效果使用max,可以执行如下操作:
127.0.0.1:6379> zinterstore user:ranking:1_inter_2 2 user:ranking:1 user:ranking:2 weights 1 0.5 aggregate max (integer) 3 127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores 1) "mike" 2) "91" 3) "martin" 4) "312.5" 5) "tom" 6) "444" 888/2
(2)并集
命令:
zunionstore destination numkeys key [key ... ] [weights weight [weight ... ]] [aggregate sum|min|max]
该命令的所有参数和zinterstore是一致的,只不过是做并集计算。
下面对两个集合取并集,weights和aggregate使用默认配置
127.0.0.1:6379> zunionstore user:ranking:1_union_2 2 user:ranking:1 user:ranking:2 (integer) 7
下面会介绍这些命令的时间复杂度,开发人员在使用对应的命令进行开发时,不仅要考虑功能性,
还要了解相应的时间复杂度,防止由于使用不当造成应用方效率下降以及Redis阻塞。
命令 | 时间复杂度 |
zadd key score member [score member … ] | O(kxlog(n)),k是添加成员的个数,n是当前有序集合成员个数 |
zcard key | O(1) |
zscore key member | O(1) |
zrank key member
zrevrank key member
O(log(n)),n是当前有序集合成员的个数
zrem key member [member …]
O(k*log(n)),k是删除成员的个数,n是当前有序集合成员的个数
zincrby key increment member
O(log(n)),n是当前有序集合成员个数
zrange key start end [withscores]
zrevrabge key start end [withscores]
O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员的个数
zrangebyscore key min max [withscores]
zrevrangebyscore key max min [withscores]
O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员的个数
zcount
O(log(n)),n是当前有序集合成员个数
zremrangebyrank key start end
O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员的个数
zremrangebyscore key min max
O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员的个数
zinterstore destination numkeys key [key …]
O(n*k)+O(m*log(m)),n是成员数最小的有序集合成员个数,
k是有序集合的个数,m是结果集中成员个数
zunionstore destination numkeys key [key …]
O(n)+O(m*log(m)),n是所有有序集合成员个数和,m是结果集中成员个数