SORT:对键的值进行排序
用户可以通过执行 SORT
命令,对列表元素、集合元素或者有序集合成员进行排序。为了让用户能够以不同的方式进行排序,Redis 为 SORT
命令提供了非常多的可选项,如果我们以不给定任何可选项的方式直接调用 SORT
命令,那么命令将对指定键储存的元素执行数字值排序:
- SORT key
在默认情况下,SORT
命令将按照从小到大的顺序,依次返回排序后的各个值。
比如说,以下例子就展示了如何对 lucky-numbers
集合储存的六个数字值进行排序:
- redis> SMEMBERS lucky-numbers -- 以乱序形式储存的集合元素
- 1) "1024"
- 2) "123456"
- 3) "10086"
- 4) "3.14"
- 5) "888"
- 6) "256"
- redis> SORT lucky-numbers -- 排序后的集合元素
- 1) "3.14"
- 2) "256"
- 3) "888"
- 4) "1024"
- 5) "10086"
- 6) "123456"
而以下例子则展示了如何对 message-queue
列表中的数字值进行排序:
- redis> LRANGE message-queue 0 -1 -- 根据插入顺序进行排列的列表元素
- 1) "1024"
- 2) "256"
- 3) "128"
- 4) "512"
- 5) "64"
- redis> SORT message-queue -- 排序后的列表元素
- 1) "64"
- 2) "128"
- 3) "256"
- 4) "512"
- 5) "1024"
指定排序方式
在默认情况下,SORT
命令执行的是升序排序操作:较小的值将被放到结果的较前位置,而较大的值则会被放到结果的较后位置。
通过使用可选的 ASC
选项或者 DESC
选项,用户可以指定 SORT
命令的排序方式,其中 ASC
表示执行升序排序操作,而 DESC
则表示执行降序排序操作:
- SORT key [ASC|DESC]
降序排序操作的做法跟升序排序操作的做法正好相反,它会把较大的值放到结果的较前位置,而较小的值则会被放到结果的较后位置。
举个例子,如果我们想要对 lucky-numbers
集合的元素实施降序排序,那么只需要执行以下代码就可以了:
- redis> SORT lucky-numbers DESC
- 1) "123456"
- 2) "10086"
- 3) "1024"
- 4) "888"
- 5) "256"
- 6) "3.14"
因为 SORT
命令在默认情况下进行的就是升序排序,所以 SORT key
命令和 SORT key ASC
命令产生的效果是完全相同的,因此我们在一般情况下并不会用到 ASC
选项 ——除非你有特别的理由,需要告诉别人你正在进行的是升序排序。
对字符串值进行排序
SORT
命令在默认情况下进行的是数字值排序,如果我们尝试直接使用 SORT
命令去对字符串元素进行排序,那么命令将产生一个错误:
- redis> SMEMBERS fruits
- 1) "cherry"
- 2) "banana"
- 3) "apple"
- 4) "mango"
- 5) "dragon fruit"
- 6) "watermelon"
- redis> SORT fruits
- (error) ERR One or more scores can't be converted into double
为了让 SORT
命令能够对字符串值进行排序,我们必须让 SORT
命令执行字符串排序操作而不是数字值排序操作,这一点可以通过使用 ALPHA
选项来实现:
- SORT key [ALPHA]
作为例子,我们可以使用带 ALPHA
选项的 SORT
命令去对 fruits
集合进行排序:
- redis> SORT fruits ALPHA
- 1) "apple"
- 2) "banana"
- 3) "cherry"
- 4) "dragon fruit"
- 5) "mango"
- 6) "watermelon"
又或者使用以下命令,对 test-record
有序集合的成员进行排序:
- redis> ZRANGE test-record 0 -1 WITHSCORES -- 在默认情况下,有序集合成员将根据分值进行排序
- 1) "ben"
- 2) "70"
- 3) "aimee"
- 4) "86"
- 5) "david"
- 6) "99"
- 7) "cario"
- 8) "100"
- redis> SORT test-record ALPHA -- 但使用 SORT 命令可以对成员本身进行排序
- 1) "aimee"
- 2) "ben"
- 3) "cario"
- 4) "david"
只获取部分排序结果
在默认情况下,SORT
命令将返回所有被排序的元素,但如果我们只需要其中一部分排序结果的话,那么可以使用可选的 LIMIT
选项:
- SORT key [LIMIT offset count]
其中 offset
参数用于指定返回结果之前需要跳过的元素数量,而 count
参数则用于指定需要获取的元素数量。
举个例子,如果我们想要知道 fruits
集合在排序之后的第 3 个元素是什么,那么只需要执行以下调用就可以了:
- redis> SORT fruits ALPHA LIMIT 2 1
- 1) "cherry"
注意,因为 offset
参数的值是从 0
开始计算的,所以这个命令在获取第三个被排序元素时使用了 2
而不是 3
来作为偏移量。
获取外部键的值作为结果
在默认情况下,SORT
命令将返回被排序的元素作为结果,但如果用户有需要的话,也可以使用 GET
选项去获取其他别的值作为排序结果:
- SORT key [[GET pattern] [GET pattern] ...]
一个 SORT
命令可以使用任意多个 GET pattern
选项,其中 pattern
参数的值可以是:
包含
*
符号的字符串;包含
*
符号和->
符号的字符串;一个单独的
#
符号;
接下来的三个小节将分别介绍这三种值的用法和用途。
1. 获取字符串键的值
当 pattern
参数的值是一个包含 符号的字符串时,
SORT
命令将把被排序的元素与 符号实行替换,构建出一个键名,然后使用
GET
命令去获取该键的值。
表 11-2 储存水果价格的各个字符串键,以及它们的值
字符串键 | 值 |
---|---|
"apple-price" | 8.5 |
"banana-price" | 4.5 |
"cherry-price" | 7 |
"dragon fruit-price" | 6 |
"mango-price" | 5 |
"watermelon-price" | 3.5 |
举个例子,假设数据库里面储存着表 11-2 所示的一些字符串键,那么我们可以通过执行以下命令,对 fruits
集合的各个元素进行排序,然后根据排序后的元素去获取各种水果的价格:
- redis> SORT fruits ALPHA GET *-price
- 1) "8.5"
- 2) "4.5"
- 3) "7"
- 4) "6"
- 5) "5"
- 6) "3.5"
这个 SORT
命令的执行过程可以分为以下三个步骤:
对
fruits
集合的各个元素进行排序,得出一个由"apple"
、"banana"
、"cherry"
、"dragon fruit"
、"mango"
、"watermelon"
组成的有序元素排列。将排序后的各个元素与
*-price
模式进行匹配和替换,得出键名"apple-price"
、"banana-price"
、"cherry-price"
、"dragon fruit-price"
、"mango-price"
和"watermelon-price"
。使用
GET
命令去获取以上各个键的值,并将这些值依次放入到结果列表里面,最后把结果列表返回给客户端。
图 11-2 以图形方式展示了整个 SORT
命令的执行过程。
图 11-2 SORT fruits ALPHA GET *-price
命令的执行过程
2. 获取散列中的键值
当 pattern
参数的值是一个包含 符号和
->
符号的字符串时,SORT
命令将使用 ->
左边的字符串为散列名,->
右边的字符串为字段名,调用 HGET
命令,从散列里面获取指定字段的值。此外,用户传入的散列名还需要包含 符号,这个
*
符号将被替换成被排序的元素。
表 11-3 储存着水果信息的散列
散列名 | 散列中 inventory 字段的值 |
---|---|
apple-info | “1000” |
banana-info | “300” |
cherry-info | “50” |
dragon fruit-info | “500” |
mango-info | “250” |
watermelon-info | “324” |
举个例子,假设数据库里面储存着表 11-3 所示的 apple-info
、 banana-info
等散列,而这些散列的 inventory
键则储存着相应水果的存货量,那么我们可以通过执行以下命令,对 fruits
集合的各个元素进行排序,然后根据排序后的元素去获取各种水果的存货量:
- redis> SORT fruits ALPHA GET *-info->inventory
- 1) "1000"
- 2) "300"
- 3) "50"
- 4) "500"
- 5) "250"
- 6) "324"
这个 SORT
命令的执行过程可以分为以下三个步骤:
对
fruits
集合的各个元素进行排序,得出一个由"apple"
、"banana"
、"cherry"
、"dragon fruit"
、"mango"
、"watermelon"
组成的有序元素排列。将排序后的各个元素与
*-info
模式进行匹配和替换,得出散列名"apple-info"
、"banana-info"
、"cherry-info"
、"dragon fruit-info"
、"mango-info"
和"watermelon-info"
。使用
HGET
命令,从以上各个散列中取出inventory
字段的值,并将这些值依次放入到结果列表里面,最后把结果列表返回给客户端。
图 11-3 以图形方式展示了整个 SORT
命令的执行过程。
图 11-3 SORT fruits ALPHA GET *-info->inventory
命令的执行过程
3. 获取被排序元素本身
当 pattern
参数的值是一个 #
符号时,SORT
命令将返回被排序的元素本身。
因为 SORT key
命令和 SORT key GET #
命令返回的是完全相同的结果,所以单独使用 GET #
并没有任何实际作用:
- redis> SORT fruits ALPHA
- 1) "apple"
- 2) "banana"
- 3) "cherry"
- 4) "dragon fruit"
- 5) "mango"
- 6) "watermelon"
- redis> SORT fruits ALPHA GET # -- 与上一个命令的结果完全相同
- 1) "apple"
- 2) "banana"
- 3) "cherry"
- 4) "dragon fruit"
- 5) "mango"
- 6) "watermelon"
因此,我们一般只会在同时使用多个 GET
选项时,才使用 GET #
获取被排序的元素。比如说,以下代码就展示了如何在对水果进行排序的同时,获取水果的价格和库存量:
- redis> SORT fruits ALPHA GET # GET *-price GET *-info->inventory
- 1) "apple" -- 水果
- 2) "8.5" -- 价格
- 3) "1000" -- 库存量
- 4) "banana"
- 5) "4.5"
- 6) "300"
- 7) "cherry"
- 8) "7"
- 9) "50"
- 10) "dragon fruit"
- 11) "6"
- 12) "500"
- 13) "mango"
- 14) "5"
- 15) "250"
- 16) "watermelon"
- 17) "3.5"
- 18) "324"
使用外部键的值作为排序权重
在默认情况下,SORT
命令将使用被排序元素本身作为排序权重,但在有需要时,用户可以通过可选的 BY
选项,指定其他键的值作为排序的权重:
- SORT key [BY pattern]
pattern
参数的值既可以是包含 符号的字符串,也可以是包含
符号和
->
符号的字符串,这两种值的作用和效果跟它们在 GET
选项时的作用和效果一样:前者用于获取字符串键的值,而后者则用于从散列里面获取指定字段的值。
举个例子,通过执行以下命令,我们可以使用储存在字符串键里面的水果价格作为权重,对水果进行排序:
- redis> SORT fruits BY *-price
- 1) "watermelon"
- 2) "banana"
- 3) "mango"
- 4) "dragon fruit"
- 5) "cherry"
- 6) "apple"
因为上面这个排序结果只展示了水果的名字,却没有展示水果的价格,所以这个排序结果并没有清楚地展示水果的名字和价格之间的关系。相反地,如果我们在使用 BY
选项的同时,使用两个 GET
选项去获取水果的名字以及价格,那么就能够直观地看出水果是按照价格进行排序的了:
- redis> SORT fruits BY *-price GET # GET *-price
- 1) "watermelon" -- 水果的名字
- 2) "3.5" -- 水果的价格
- 3) "banana"
- 4) "4.5"
- 5) "mango"
- 6) "5"
- 7) "dragon fruit"
- 8) "6"
- 9) "cherry"
- 10) "7"
- 11) "apple"
- 12) "8.5"
同样地,我们还可以通过执行以下命令,使用散列中记录的库存量作为权重,对水果进行排序并获取它们的库存量:
- redis> SORT fruits BY *-info->inventory GET # GET *-info->inventory
- 1) "cherry" -- 水果的名字
- 2) "50" -- 水果的库存量
- 3) "mango"
- 4) "250"
- 5) "banana"
- 6) "300"
- 7) "watermelon"
- 8) "324"
- 9) "dragon fruit"
- 10) "500"
- 11) "apple"
- 12) "1000"
保存排序结果
在默认情况下,SORT
命令会直接将排序结果返回给客户端,但如果用户有需要的话,也可以通过可选的 STORE
选项,以列表形式将排序结果储存到指定的键里面:
- SORT key [STORE destination]
如果用户给定的 destination
键已经存在,那么 SORT
命令会先移除该键,然后再储存排序结果。带有 STORE
选项的 SORT
命令在成功执行之后将返回被储存的元素数量作为结果。
作为例子,以下代码展示了如何将排序 fruits
集合所得的结果储存到 sorted-fruits
列表里面:
- redis> SORT fruits ALPHA STORE sorted-fruits
- (integer) 6 -- 有六个已排序元素被储存了
- redis> LRANGE sorted-fruits 0 -1 -- 查看排序结果
- 1) "apple"
- 2) "banana"
- 3) "cherry"
- 4) "dragon fruit"
- 5) "mango"
- 6) "watermelon"
其他信息
属性 | 值 |
---|---|
平均复杂度 | O(N*log(N)+M) ,其中 N 为被排序元素的数量,而 M 则为命令返回的元素数量。 |
版本要求 | SORT 命令从 Redis 1.0.0 版本开始可用。 |