Redis Sorted Set类型介绍
Sorted set是Redis的一种数据类型,与set类型和hash类型的混合相似。同set类型一样,sorted set中的元素都是惟一的,不能重复的字作串元素。所以在某些场景下,sorted set类型同set类型一样。
但是set类型对象中元素是无序的,而sorted set类型对象中的每个元素都与一个叫做score的浮点值相关联(这也是为什么说它与hash类型相似,因为它的每个元素同样都映射一个值)。
此外,sorted set中的元素是按次序被取出的(所以他们不是基于请求被排序的,有序性是sorted set数据结构的一个特征)。sorted set中的元素按照如下规则排序:
- 如果A元素与B元素对应的score值不一样,那么对应score大的那个元素大。
- 如果A元素与B元素对应的score值相同,那么按字典顺序比较A与B字符串(A字符串与B字符串是不可能相等的,因为sorted set中元素惟一)。
让我们以一个简单的例子开始,添加一些黑客的名字作为sorted set的元素,用他们的出生的年作为score值:
>zadd hackers 1940 "Alan Kay"
(integer) 1
>zadd hackers 1957 "Sophie Wilson"
(integer) 1
>zadd hackers 1949 "Anita Borg"
(integer) 1
>zadd hackers 1965 "Yukihiro Matsumoto"
(integer) 1
>zadd hackers 1914 "Hedy Lamarr"
(integer) 1
>zadd hackers 1916 "Claude Shannon"
(integer) 1
>zadd hackers 1969 "Linus Torvalds"
(integer) 1
>zadd hackers 1912 "Alan Turing"
(integer) 1
正如你看到的,ZADD命令与SADD命令类似,但是多取了一个参数(放在要添加元素之前),就是score。ZADD命令也支持批量操作,所以即使上面的例子没用,你也可以自由的指定多个score-value对。
对于此sorted set,要返回一个按照黑客出生年排序的黑客列表是无意义的,因为实际上,他们已结排过序了。
注:Redis Sorted set是通过双端品数据结构实现的,包含一个skip list 和 一个hash组成,所以我们在sorted set上添加一个元素操作的时间复杂度为O(log(N))。这样虽然很好,但是当我们请求对元素进行排序的时候,redis将什么都不会做,因为已经排过序了:
>zrange hackers 0 -1
1)"Alan Turing"
2)"Hedy Lamarr"
3)"Claude Shannon"
4)"Alan Kay"
5)"Anita Borg"
6)"Richard Stallman"
7)"Sophie Wilson"
8)"Yukihiro Matsumoto"
9)"Linus Torvalds"
注:0和-1表示从索引为0的元素到最后一个元素(同LRANGE命令相似)。
如果想要与现有排序相反,如从年轻到到最老的,可以使用ZREVRANGE命令。
>zrevrange hackers 0 -1
1)"Linus Torvalds"
2)"Yukihiro Matsumoto"
3)"Sophie Wilson"
4)"Richard Stallman"
5)"Anita Borg"
6)"Alan Kay"
7)"Claude Shannon"
8)"Hedy Lamarr"
9)"Alan Turing"
也可以连同score一块输出,使用WITHSCORES参数:
>zrange hackers 0 -1 withscores
1)"Alan Turing"
2)"1912"
3)"Hedy Lamarr"
4)"1914"
5)"Claude Shannon"
6)"1916"
7)"Alan Kay"
8)"1940"
9)"Anita Borg"
10)"1949"
11)"Richard Stallman"
12)"1953"
13)Sophie Wilson"
14)"1957"
15)"Yukihiro Matsumoto"
16)"1965"
17)"Linus Torvalds"
18)"1969"
范围操作
ZRANGEBYSCORE命令可用于范围查询操作,如获取出生的年小于等于1950的个体:
>zrangebyscore hackers -inf 1950
1)"Alan Turing"
2)"Hedy Lamarr"
3)"Claude Shannon"
4)"Alan Kay"
5)"Anita Borg"
这个命令或解释为我们向Redis请求返回所有score值在负无穷和1950(两端边界都包含)之间的元素。-inf表示负无穷。
ZREMRANGEBYSCORE命令可用于范围删除操作,如要删除出生年在1940和1960之间的黑客:
>zremrangebyscore hackers 1940 1960
(integer) 4
ZREMRANGEBYSCORE也许不是最好命令名称,但却非常有用,并且返回被删除元素的个数。
另外一个对于sorted set元素极其有用的操作ZRANK是获取排名操作,用于获取元素在sorted set集合中的位置:
>zrank hackers "Linus Torvalds"
(integer) 4
同样的,ZREVRANK命令为获取元素从相反方向开始的位置。
Lexicographical(词典顺序的) scores
在Redis 2.8中,新增了一个可以按词典顺序排序的功能。sorted set所有元素的词典顺序比较使用C语言的memcmp函数,没有做任何调整,可以放心使用,任何Redis实例都会给出相同的结果。
用于sorted set词典相关命令主要有:ZRANGEBYLEX,ZREVRANGEBYLEX,ZREMRANGEBYLEX和ZLEXCOUNT。
>zadd hackers01 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0 "Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon" 0 "Linus Torvalds" 0 "Alan Turing"
(integer) 9
由于Sorted set的排序规则,这上面的元素都已经按照词典顺序排序过了:
>zrange hackers 0 -1
1)"Alan Kay"
2)"Alan Turing"
3)"Anita Borg"
4)"Claude Shannon"
5)"Hedy Lamarr"
6)"Linus Torvalds"
7)"Richard Stallman"
8)"Sophie Wilson"
9)"Yukihiro Matsumoto"
我们可以使用ZRANGEBYLEX命令根据词典顺序获取一定范围的值:
>zrangebylex hackers [B [P
1)"Claude Shannon"
2)"Hedy Lamarr"
3)"Linus Torvalds"
更新score:排行榜
关于sorted set集合最后要注意的是:Sorted set的scores在任何时候都可能被更改。仅仅需要调用ZADD添加一个集合中已存在的元素,Redis就会自动做一个时间复杂度为O(log(N))的更改sorted set的scores和位置的操作。因此,sorted set适用于需要大量更新操作的场景。
注:因为这个特征,一个通常使用场景就是排行榜。