• 选项参数
  • sort 命令的实现
  • ALPHA选项的实现
  • DESC与ASC选项
  • BY选项
  • 带有ALPHA选项的BY选项的实现
  • LIMIT选项的实现
  • Get选项的实现
  • STORE选项的实现
  • SORT命令多个选项的执行顺序
  • 重点


Redis可以使用sort命令对列表和集合进行排序

redis sortset 存放复杂数据结构 redis sort by_数组


redis sortset 存放复杂数据结构 redis sort by_redis_02

选项参数

  • ALPHA选项:可以对字符串进行排序
  • redis sortset 存放复杂数据结构 redis sort by_redis_03

  • 可以看到,alpha对数字排序不影响,但如果出现字符串,那么就必须加上alpha,否则会报错,提示有scores不可以转变为double
  • By选项:可以指定权重,这里要知道sort命令都要指定权重的,如果没有,那就默认的权重就是自己本身(如果是zset,默认的是member,所以要sort有序集合,member必须是可以转化为浮点型)
  • redis sortset 存放复杂数据结构 redis sort by_redis_04

  • 如果member不是浮点型,那就要指定权重去比了,权重其实也就是一个字符串对象(*就是对应的member)
  • redis sortset 存放复杂数据结构 redis sort by_权重_05

  • ASC与DESC:升序和降序
  • redis sortset 存放复杂数据结构 redis sort by_数组_06

sort 命令的实现

首先认识redisSortObject结构

typedef struct _redisSortObject(
	//被排序的键
    robj *obj
    //权重
    union{
        //排序数字值时使用
        double score;
        //排序带有BY选项的字符串值时使用
        robj *cmpobj;
    }u;
)redisSortObject;

排序的步骤如下

  1. 创建一个和列表或者集合长度相同的数组,数组里面的每一个项都是redisSortObject结构
  2. 遍历数组,将各个redisSortObject的obj属性分别指向列表或集合中的每一个项,形成obj指针与列表项之间的一对一关系
  3. 遍历数组,将各个obj指针所指向的列表项转换成一个double类型的浮点数,然后保存在score属性里面
  4. 数组项根据score属性的值进行排序,排序后的数组项按照score属性从大到小排列
  5. 最后再次遍历数组,将各个数组项的Obj指针所指向的列表项作为排序结果返回给客户端,客户端就得到有序的结果了。

ALPHA选项的实现

ALPHA选项是可以对字符串进行排序

  1. 同理第一步是创建redisSortObject结构数组 ,长度依旧等于指定集合或者列表长度
  2. 遍历数组,让数组中的redisSortObject的obj指针与集合或者列表里面的每一个项进行关联
  3. 并且根据obj指针所指向的集合元素,对数组进行字符串排序,排序后得到的数组项按字符串值从小到达进行排列
  4. 遍历数组,依次将数组项的obj指针所指向的元素也返回给客户端

DESC与ASC选项

这两个选项其实就是对比的方式不同

  • DESC使用降序的对比函数,产生降序的结果
  • ASC使用升序的对比函数,产生升序的结果

BY选项

步骤也是比较类似的

  1. 创建一个redisSortObject结构数组,数组的长度也是由有序集合的长度决定
  2. 遍历数组,将各个数组项的obj指针分别指向有序集合的各个元素
  3. 再遍历数组,根据各个数组项的obj指针所指向的集合元素,以及By选项所给定的名字模式,找到相应的权重键
  4. 将各个权重键的值转换成一个double类型的浮点数,然后仍然保存在redisSortObject的score属性里面
  5. 根据权重值对数组进行排序,得到一个按score属性的值从小到大排序的数组
  6. 遍历数组,依次将数组项的obj指针指向的集合的项返回给客户端

带有ALPHA选项的BY选项的实现

带有ALPHA和BY选项,也是自己自定义权重,而且权重是比较的是字符串

redis sortset 存放复杂数据结构 redis sort by_权重_07


权重变为了字符串去比较

步骤也是十分类似

  • 创建一个redisSortObject结构数组,数组的长度还是等于集合的大小
  • 遍历数组,让数组项的redisSortObject分别指向集合的每一个项
  • 遍历数组,根据各个redisSortObject的obj指针所指向的集合元素,再结合by选项给定的模式,查找相应的权重键
  • 将各个数组项的cmpobj指针指向权重键(这一步与前面的都不同)
  • 根据各个数组项的cmpobj指针找到权重键,然后根据权重键对redisSortObject数组进行排序
  • 遍历数组,依次将redisSortObject的obj指针所指向的集合元素返回给客户端

LIMIT选项的实现

LIMIT选项可以让SORT命令只返回其中一部分已排序的元素

命令为

limit <offset> <count> //offset是偏移量,其实也就是从哪里开始,count就是需要几个元素

redis sortset 存放复杂数据结构 redis sort by_redis_08

  • 创建一个redisSortObject数组,数组的长度依然等于集合的长度
  • 遍历数组,将各个redisSortObject的obj指针分别指向集合的各个元素
  • 根据obj指针所指向的集合元素,对数组进行排序(如果是字符串排序,则要将字符串保存在cmpobj指针)
  • 根据limit选项的参数,将指针移动到数组的索引offset上,然后从这里开始遍历count次,返回给客户端

Get选项的实现

可以让SORT命令在对键进行排序之后,根据被排序的元素,以及GET选项所指定的模式,查找并返回对应某些键的值(可以使用这个来维护索引,贼强)

redis sortset 存放复杂数据结构 redis sort by_redis_09


*一样对应的是值名,然后对应找到键名,然后返回值

步骤也是十分类似

  • 创建一个redisSortObject结构数组,长度为集合长度
  • 让redisSortObject的项分别指向集合中的每一个元素
  • 使用对应的规则进行排序,我这里是需要对应元素(obj指针)和by选项的模式找到权重键,然后将权重键保存到redisSortObject的cmpobj指针里面
  • 根据权重值进行排序
  • 遍历数组,根据数组项的obj指针和get的参数,找到对应的键
  • 遍历找到的键,然后向客户端返回键(因为可能有Limit操作)

GET选项是可以匹配多个的,只不过这样会导致查找的键更多

STORE选项的实现

在默认情况下,SORT命令只会返回排序结果,而不会保存排序结果,而STORE命令可以将排序结果保存在指定的键里面,让有需要的时候可以直接重用这个排序结果

redis sortset 存放复杂数据结构 redis sort by_权重_10


步骤如下

  • 创建一个redisSortObject数组,长度为集合或列表长度
  • 让redisSortObject中的每一个项指向集合中的每一个元素
  • 进行排序,以上栗子的排序规则为,遍历数组,对数组进行排序,将列表中的每个元素的值转换成一个浮点型,存放在redisSortObject的score里面,对score进行排序
  • 检查指定的保存键是否存在,如果存在的话还需要去删除这个键
  • 将指定的保存键设置为对应结构(集合或列表或有序集合)的空白键
  • 遍历数组,依次将数组里面的obj指针保存的元素放入保存键里面
  • 遍历数组,向客户端返回数组里面的obj指针指向的元素

SORT命令多个选项的执行顺序

顺序分为以下的几步

  • 排序:使用ALPHA、ASC、DESC或BY对输入键进行排序,得到一个结果集
  • 限制排序结果集的长度:在这一步,使用LIMIT选项对结果集的长度进行限制,只有LIMIT选项指定的那部分元素才会被保留在结果集里
  • 获取外部键:对应GET命令,使用数组里面的redisSortObject对象的obj指针和get命令指定的模式,去查找指定键的值,并用这些值作为新的排序结果
  • 保存排序结果:对应STORE命令,将排序结果保存在指定保存键里面
  • 向客户端返回排序结果集
  • 命令遍历结果集中的元素返回给客户端

也就是总体顺序为:

sort -> alpha asc desc by -> limit -> get -> store

重点

  • SORT命令的实现,是将集合里面的元素都放在redisSortObject数组里面,然后再进行相应排序
  • 默认情况下,使用数字排序方式,将集合里面的值转化为浮点型,保存在redisSortObject的score属性里面
  • 通过alpha命令,可以使用字符串排序方式,将字符串值保存在redisSortObject的cmpobj指针里面(因为字符串就是一个SDS对象)
  • SORT的排序操作是使用快速排序来实现的