Redis的SORT命令可以对列表键、集合键、有序集合键进行排序。
1.SORT <key>命令的实现
SORT命令最简单的执行形式为:SORT <key>
这个命令可以对一个包含数字值的键key进行排序,示例:
RPUSH numbers 3 1 2
SORT numbers
服务器执行SORT numbers命令的详细步骤如下:
1)创建一个和numbers列表长度相同的数组,该数组的每个项都是一个redis.h/redisSortObject结构
2)遍历数组,将各个数组项的obj指针分别指向numbers列表的各个项,构成obj指针和列表项之间的一对一关系
3)遍历数组,将各个obj指针所指向的列表项转化为一个double类型的浮点数,并将这个浮点数保存在相应数组项u.score属性里
4)根据数组项u.score属性的值,对数组进行数字值排序,排序后的数组项按u.score属性的值从小到大排序
5)遍历数组,将各个数组项的obj指针所指向的列表项作为排序结果返回给客户端
redisSortObject结构的完整定义:
typedef struct _redisSortObject{
//被排序键的值
robj *obj;
//权重
union{
//排序数字值时使用
double score;
//排序带有BY选项的字符串值时使用
robj *compobj;
} u;
} redisSortObject;
2. ALPHA选项的实现
通过使用ALPHA选项,SORT命令可以对包含字符串值得键进行排序:
SORT <key> ALPHA
示例:
SADD fruits apple banana cherry
SMEMBERS fruits
SORT fruits ALPHA
服务器执行SORT fruits ALPHA命令的详细步骤如下:
1)创建一个redisSortObject结构数组,数组的长度等于fruits集合大小
2)遍历数组,将各个数组项的obj指针分别指向fruits集合的各个元素
3)根据obj指针指向的集合元素,对数组进行字符串排序,排序后的数组项按集合元素的字符串值从小到大排序
4)遍历数组,依次将数组项的obj指针所指向的元素返回给客户端
3.ASC选项和DESC选项的实现
在默认情况下,SORT命令执行升序排序,排序后的结构按照从小到大排序:
SORT <key> 等价于 SORT <key> ASC
相反,SORT <key> DESC是从大到小
4.BY选项的实现
在默认情况下,SORT命令使用被排序键包含的元素作为排序的权重,元素本身决定了元素在排序之后所处的位置。
另一方面,通过使用BY选项,SORT命令可以指定某些字符串键,或者某个哈希键所包含的某些域作为元素的权重,对一个键进行排序
示例:
MSET apple-price 8 banana-price 5.5 cherry-price 7
SORT fruits BY *-price
详细步骤:
1)创建一个redisSortObject结构数组,数组的长度等于fruits集合的大小
2)遍历数组,将各个数组项的obj指针分别指向fruits集合的各个元素
3)遍历数组,根据各个数组项的obj指针所指向的集合元素,以及BY选项所给定的模式,查找相应的权重键
4)将各个权重键的值转换成一个double类型的浮点数,然后保存在相应数组项的u.score属性里面
5)以数组项u.score属性的值为权重,对数组进行排序,得到一个按u.score属性的值从小到大排序的数组
6)遍历数组,一次将数组的obj指针所指向的集合元素返回给客户端
5.带有ALPHA选项的BY选项的实现
BY选项默认假设权重键保存的值为数字值,如果权重键保存的值是字符串值得话,那么就需要在使用BY选项的同时,配合ALPHA选项了。
示例:
SADD fruits "apple" "banbana" "cherry"
MSET apple-id "FRUIT-25" banbana-id "FRUIT-79" cherry-id "FRUIT-13"
SORT fruits BY *-id ALPHA
详细步骤:
1)创建一个redisSortObject结构数组,数组的长度等于fruits集合的大小
2)遍历数组,将各个数组项的obj指针分别指向fruits集合的各个元素
3)遍历数组,根据各个数组项的obj指针所指向的集合元素,以及BY选项所给定的模式,查找相应的权重键
4)将各个数组项的u.cmpobj指针分别指向相应的权重键(一个字符串对象)
5)以各个数组项的权重键的值为权重,对数组执行字符串排序
6. LIMIT选项的实现
在默认情况下,SORT命令总会将排序后的所有元素都返回给客户端。
但是通过LIMIT选项,我们可以让SORT命令只返回其中一部分已排序的元素。
LIMIT选项的格式为:LIMIT <offset> <count>;
offset:要跳过的已排序元素数量
count:跳过给定数量的已排序元素之后,要返回的已排序元素数量
示例:
SADD alphabet a b c d e f g
SMEMBERS alphabet
SORT alphabet ALPHA
SORT alphabet ALPHA LIMIT 0 4
7.GET选项的实现
在默认情况下,SORT命令在对键进行排序之后,总是返回被排序键本身所包含的元素。
但是通过GET选项,我们可以让SORT命令在对键进行排序之后,根据被排序的元素,以及GET选项所指定的模式,查找并返回某些键的值。
示例:
SADD students "peter" "jack" "tom"
SORT students ALPHA
SET peter-name "Peter White"
SET jack-name "Jack Snow"
SET tom-name "Tom Smith"
SORT sutdents ALPHA GET *-name
8.STORE选项的实现
在默认情况下,SORT命令只向客户端返回排序结果,而不保存排序结果。
但是通过STORE选项,我们可以将排序结果保存在指定的键里面,并在有需要时重用这个排序结果。
示例:
SADD students "peter" "jack" "tom"
SORT students ALPHA
SORT students ALPHA STORE sorted_students
LRANGE sorted_students 0-1
9.多个选项的执行顺序
一个SORT命令请求通常会用到多个选项,而这些选项的执行顺序是由先后之分的。
9.1 选项的执行顺序
如果按照选项来划分的话,一个SORT命令的执行过程可以分为以下四步:
1)排序:在这一步,命令会使用ALPHA、ASC、DESC、BY这几个选项,对输入键进行排序,并得到一个排序结果集
2)限制排序结果集的长度:在这一步,会使用LIMIT选项对结果集的长度进行限制,只有LIMIT选项指定的那部分元素会被保留在排序结果集中
3)获取外部键:在这一步,命令会使用GET选项,根据排序结果集中的元素以及GET选项指定的模式,查找并获取指定键的值,并用这些值作为新的排序结果集
4)保存排序结果集:在这一步,命令会使用STORE选项,将排序结果及保存到指定的键上面去
5)向客户的返回排序结果集:在最后这一步,命令遍历排序结果集,并以此向客户端返回排序结果集中的元素。
示例:
SORT <key> ALPHA DESC BY <by-pattern> LIMIT <offset> <count> GET <get-pattern> STORE <store-key>
9.2 选项的摆放顺序
调用SORT命令时,除了GET选项之外,改变选项的摆放顺序并不会影响SORT命令执行这些选项的顺序。
不过,如果命令包含了多个GET选项,那么在调整选项的位置时,我们必须保证多个GET选项的摆放顺序不变,这才可以让排序结果集保持不变。