Redis的sorted_set的用法,看完这一篇就够了

各位小伙伴们,我们上次讲过Redis中Set的相关操作,以及适用的一些场景,例如抽奖等。今天要讲的sorted_set,其实也是set的一种,也具有set去重的特点。和set不同的是,sorted_set是有序的,从字面意思也可以看得出来。

 那sorted_set是怎么排序的,根据什么规则排序呢?往下看。

我们先来看下sored_set提供了哪些命令。

 

127.0.0.1:6379> help @sorted_set

  BZPOPMAX key [key ...] timeout
  summary: Remove and return the member with the highest score from one or more sorted sets, or block until one is available
  since: 5.0.0

  BZPOPMIN key [key ...] timeout
  summary: Remove and return the member with the lowest score from one or more sorted sets, or block until one is available
  since: 5.0.0


  ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
  summary: Add one or more members to a sorted set, or update its score if it already exists
  since: 1.2.0

  ZCARD key
  summary: Get the number of members in a sorted set
  since: 1.2.0

  ZCOUNT key min max
  summary: Count the members in a sorted set with scores within the given values
  since: 2.0.0

  ZINCRBY key increment member
  summary: Increment the score of a member in a sorted set
  since: 1.2.0

  ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
  summary: Intersect multiple sorted sets and store the resulting sorted set in a new key
  since: 2.0.0

  ZLEXCOUNT key min max
  summary: Count the number of members in a sorted set between a given lexicographical range
  since: 2.8.9

  ZPOPMAX key [count]
  summary: Remove and return members with the highest scores in a sorted set
  since: 5.0.0

  ZPOPMIN key [count]
  summary: Remove and return members with the lowest scores in a sorted set
  since: 5.0.0

  ZRANGE key start stop [WITHSCORES]
  summary: Return a range of members in a sorted set, by index
  since: 1.2.0

  ZRANGEBYLEX key min max [LIMIT offset count]
  summary: Return a range of members in a sorted set, by lexicographical range
  since: 2.8.9

  ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
  summary: Return a range of members in a sorted set, by score
  since: 1.0.5

  ZRANK key member
  summary: Determine the index of a member in a sorted set
  since: 2.0.0

  ZREM key member [member ...]
  summary: Remove one or more members from a sorted set
  since: 1.2.0

  ZREMRANGEBYLEX key min max
  summary: Remove all members in a sorted set between the given lexicographical range
  since: 2.8.9

  ZREMRANGEBYRANK key start stop
  summary: Remove all members in a sorted set within the given indexes
  since: 2.0.0

  ZREMRANGEBYSCORE key min max
  summary: Remove all members in a sorted set within the given scores
  since: 1.2.0

  ZREVRANGE key start stop [WITHSCORES]
  summary: Return a range of members in a sorted set, by index, with scores ordered from high to low
  since: 1.2.0

  ZREVRANGEBYLEX key max min [LIMIT offset count]
  summary: Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.
  since: 2.8.9

  ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
  summary: Return a range of members in a sorted set, by score, with scores ordered from high to low
  since: 2.2.0

  ZREVRANK key member
  summary: Determine the index of a member in a sorted set, with scores ordered from high to low
  since: 2.0.0

  ZSCAN key cursor [MATCH pattern] [COUNT count]
  summary: Incrementally iterate sorted sets elements and associated scores
  since: 2.8.0

  ZSCORE key member
  summary: Get the score associated with the given member in a sorted set
  since: 1.2.0

  ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
  summary: Add multiple sorted sets and store the resulting sorted set in a new key
  since: 2.0.0

可以看到,sorted_set 中的命令大多以 Z 开头,因为set占用 S 了嘛。还有某些命令中有REV关键字,代表Reverse,反向的意思。

另外,还有两个命令以B开头,这里B代表Blocked,即阻塞的,上述帮助文档里也有说明(block until one is available)。

 命令看起来挺多,我们大致做个分类。

 

 Redis的sorted_set的用法,看完这一篇就够了

 

 

 


 

sorted_set的基本用法

 

下面,我们来看下常用命令的具体用法。

 

一、基本操作

 

 从ZADD命令可以看出,向key中添加元素时,有个参数score。没错,sorted_set 对每个元素都设定了分值,并在add时,根据这个分值进行升序排序。

 
 
 ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
  summary: Add one or more members to a sorted set, or update its score if it already exists
  since: 1.2.0
/* 将笔试成绩(tom-100,jack-60,tony-80)放入名为 writtenTestScore 的
有序集合里,返回元素个数3*/
127.0.0.1:6379> zadd writtenTestScore 100 tom 60 jack 80 tony
(integer) 3
/面试成绩*/
127.0.0.1:6379> zadd interviewScore 70 tom 80 jack 60 tony
(integer) 3
/*zrange列出所有元素*/
127.0.0.1:6379> zrange writtenTestScore 0 -1
1) "jack"
2) "tony"
3) "tom"
/*zrange列出所有元素(笔试成绩),带分值*/
127.0.0.1:6379> zrange writtenTestScore 0 -1 withscores
1) "jack"
2) "60"
3) "tony"
4) "80"
5) "tom"
6) "100"
/*列出面试成绩*/
127.0.0.1:6379> zrange interviewScore 0 -1 withscores
1) "tony"
2) "60"
3) "tom"
4) "70"
5) "jack"
6) "80"

 

 

下面是删除元素的一些操作,包括 

ZPOPMAX/BZPOPMAX,ZPOPMIN/BZPOPMIN、ZREM等。

 

127.0.0.1:6379> ZADD testREM 1 a 2 b 3 c 4 d
(integer) 4
127.0.0.1:6379> zpopmax testREM 
1) "d"
2) "4"
127.0.0.1:6379> zrem testREM a
(integer) 1
/*删除10个最大的元素并返回*/
127.0.0.1:6379> zpopmax testREM 10
1) "c"
2) "3"
3) "b"
4) "2"
/*元素为空,阻塞1s后,返回空*/
127.0.0.1:6379> BZPOPMAX testREM 1
(nil)
(1.01s
/*取某个元素的分值*/
127.0.0.1:6379> ZSCORE interviewScore tony
"60"

 

 

二、统计类操作

 

统计类操作大致包括两类,一类是取元素的个数或排名,一类是取元素的列表。

/*列出80-100分数段的元素个数*/
127.0.0.1:6379> zcount writtenTestScore 80 100
(integer) 2
/*返回集合中元素个数*/
127.0.0.1:6379> zcard writtenTestScore 
(integer) 3
/*取jack的排名*/
127.0.0.1:6379> ZRANK writtenTestScore jack
(integer) 0
/*取出80-100分数段的元素*/
127.0.0.1:6379> ZRANGEBYSCORE writtenTestScore 80 100 withscores
1) "tony"
2) "80"
3) "tom"
4) "100"
/*取笔试分数最高的前两名*/
127.0.0.1:6379> ZREVRANGE writtenTestScore 0 1 withscores
1) "tom"
2) "100"
3) "tony"
4) "80"

 

 

三、运算类操作

 

127.0.0.1:6379> ZRANGE writtenTestScore 0 -1 withscores
1) "jack"
2) "60"
3) "tony"
4) "80"
5) "tom"
6) "100"

 

 

对jack的分值进行加法运算后,jack排到了第二个位置。

 

127.0.0.1:6379> ZINCRBY writtenTestScore 30 jack
"90"
127.0.0.1:6379> ZRANGE writtenTestScore 0 -1 withscores
1) "tony"
2) "80"
3) "jack"
4) "90"
5) "tom"
6) "100"

 

也就是说,sorted_set 对集合的每一次变更,都随时维护着一个按分值排序的顺序。

 

下面来看并集与交集的操作。

 

为了方便理解交集和并集,我们分别对writtenTestScore和

interview_Score进行增加元素的操作。即polly只参加了笔试,lucy只参加了面试。

 

127.0.0.1:6379> zadd writtenTestScore 50 polly 
(integer) 1
127.0.0.1:6379> ZRANGE writtenTestScore 0 -1 withscores
1) "polly"
2) "50"
3) "tony"
4) "80"
5) "jack"
6) "90"
7) "tom"
8) "100"
127.0.0.1:6379> zadd interviewScore 50 lucy
(integer) 1
127.0.0.1:6379> ZRANGE interviewScore 0 -1 withscores
1) "lucy"
2) "50"
3) "tony"
4) "60"
5) "tom"
6) "70"
7) "jack"
8) "80"

 

 

假设现在要根据笔试(权重0.6)和面试(权重0.4)的总分数进行排序,可以用 ZUNIONSTORE 来实现。

 

127.0.0.1:6379> ZUNIONSTORE result 2 writtenTestScore interviewScore weights 0.6 0.4 aggregate sum
(integer) 5
/*lucy只参加了面试,50*0.4=20; tony笔试80*0.6+面试60*0.4=72*/
127.0.0.1:6379> ZRANGE result 0 -1 withscores
 1) "lucy"
 2) "20"
 3) "polly"
 4) "30"
 5) "tony"
 6) "72"
 7) "jack"
 8) "86"
 9) "tom"
10) "88"

  


 

 

假设需求有变化,增加条件限制:面试和笔试都参加的。此时,可以使用集合交集运算 ZINTERSTORE。

 

127.0.0.1:6379> ZINTERSTORE result 2  writtenTestScore interviewScore weights 0.6 0.4 aggregate sum
(integer) 3
127.0.0.1:6379> ZRANGE result 0 -1 withscores
1) "tony"
2) "72"
3) "jack"
4) "86"
5) "tom"
6) "88"

 

 

 

关于sorted_set的排序算法

 

sorted_set对于集合变更的操作,例如zadd,zrem,zpop,zincrby等,都随时维护着一个排序。

 

简单理解,这里的排序算法是用skipList(跳表)实现的。举个例子,跳表的算法类似于,我们找书上的某一页,会先找到目录一样。当然,跳表的“目录”可能不止一层。

 

 


 

总结

 

稍微总结一下,本次分享了sorted_set的三种类型的操作,分别是基本操作(包括添加、删除)、统计类(集合中符合某些条件的元素个数、排名、元素列表)操作以及运算类(交集、并集、加法)操作。

sorted_set一般适用于排行榜,例如按照动态的点赞数(作为set中key的分值)、帖子的点击率排名等场景。

简单理解,sorted_set使用跳表实现的。

 

好了,本次分享就是这样,我们下次见。

 

请关注风哥公众号,持续输出更多干货技术内容。

 Redis的sorted_set的用法,看完这一篇就够了

 

上一篇:python leetcode 俄罗斯套娃信封问题 动态规划算法


下一篇:分享刷LeetCode算法题pdf笔记,看完你就是面试官