redis 排序

使用sort命令可以对给定的链表、集合、有序集合中的元素进行排序。

  • redis默认将要排序的元素看作数字,封装成双精度的浮点数进行比较、排序
  • redis内部使用快速排序算法进行排序;

sort实现:

  • 服务器执行sort members命令的详细步骤:
  • 创建一个和members长度相同的数组,该数组的每个项都是一个redisSortObject结构;
  • 遍历数组,将各个数组项的obj指针分别指向members列表的各个项,构成obj指针和列表项之间的一对一关系;
  • 遍历数组,将各个obj指针所指向的列表项转成一个double浮点数(或根据选项转成字符串),并将其保存在相应数组项的score属性中;
  • 根据score属性,对数组进行排序;
  • 遍历数组,将各个obj指针所指向的列表向作为排序结果返回给客户端;

一般用法:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> lrange list1 0 -1
1) "3"
2) "6"
3) "1"
4) "9"

127.0.0.1:6379> sort list1
1) "1"
2) "3"
3) "6"
4) "9"

1)使用alpha选项,对字符串进行排序:
默认情况下,redis是按照数字进行排序的,通过alpha选项可以按照字符串排序。

1
2
3
4
5
127.0.0.1:6379> sort list2 alpha
1) "a"
2) "g"
3) "y"
4) "z"

2)使用asc、desc选项,进行升序、降序排序:
默认情况下, redis是按照升序排的,可以指定desc选项进行降序排列。

1
2
3
4
5
127.0.0.1:6379> sort list1 desc
1) "9"
2) "6"
3) "3"
4) "1"

使用limit分页显示排序结果:

用法:sort key limit offset count

  • offset:跳过已经排序元素数量;
  • count:要返回已排序元素数量;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> sort list2 alpha
    1) "a"
    2) "g"
    3) "y"
    4) "z"

    127.0.0.1:6379> sort list2 alpha limit 2 2
    1) "y"
    2) "z"

##by选项,使用外部key进行排序:

在默认情况下, sort命令使用被排序键包含的元素作为排序权重,即:元素本身决定了元素在排序之后所处的位置。通过by选项,sort命令可以指定某些字符串键、hash键的某些域作为元素的权重,进行排序。

uid username{id} userlevel{id}
1 admin 999
2 jack 10
3 peter 25
4 mary 70
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
把uid 加入到一个链表
redis 127.0.0.1:6379> lpush uid 1 2 3 4
(integer) 4

admin
redis 127.0.0.1:6379> set user_name_1 admin
ok
redis 127.0.0.1:6379> set user_level_1 9999
ok

jack
redis 127.0.0.1:6379> set user_name_2 jack
ok
redis 127.0.0.1:6379> set user_level_2 10
ok

peter
redis 127.0.0.1:6379> set user_name_3 peter
ok
redis 127.0.0.1:6379> set user_level_3 25
ok

mary
redis 127.0.0.1:6379> set user_name_4 mary
ok
redis 127.0.0.1:6379> set user_level_4 70
ok

redis 127.0.0.1:6379> sort uid
1) "1" # admin
2) "2" # jack
3) "3" # peter
4) "4" # mary

redis 127.0.0.1:6379> sort uid by user_level_*
1) "2" # jack , level = 10
2) "3" # peter, level = 25
3) "4" # mary, level = 70
4) "1" # admin, level = 9999
userlevel*是一个占位符,它先取出uid中的值,然后再用这个值来查找相应的键。

get选项,获取外部键:

1)默认情况下,sort命令对键进行排序之后,总是返回被排序键本身所包含的元素。通用get选项,sort命令可以在对键排序之后,根据被排序的元素,以及get选项指定的模式,查找并返回某些键值的值。

1
2
3
4
5
redis 127.0.0.1:6379> sort uid get user_name_*
1) "admin"
2) "jack"
3) "peter"
4) "mary"

以上代码先排序uid,再取出键username{uid}的值。

2)获取多个外部键:

1
2
3
4
5
6
7
8
9
redis 127.0.0.1:6379> sort uid get user_level_* get user_name_*
1) "9999" # level
2) "admin" # name
3) "10"
4) "jack"
5) "25"
6) "peter"
7) "70"
8) "mary"

以下代码就按 uid 分别获取 userlevel{uid} 和 username{uid}

3)get有一个额外的参数规则,那就是可以用 # 获取被排序键的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
redis 127.0.0.1:6379> sort uid get # get user_level_* get user_name_*
1) "1" # uid
2) "9999" # level
3) "admin" # name
4) "2"
5) "10"
6) "jack"
7) "3"
8) "25"
9) "peter"
10) "4"
11) "70"
12) "mary"

以下代码就将 uid 的值、及其相应的 userlevel 和 username 都返回为结果

4)not-exists-key获取外部键但不进行排序:
通过将一个不存在的键作为参数传给 by 选项, 可以让 sort 跳过排序操作,直接返回结果。这种用法在单独使用时,没什么实际用处。不过,通过将这种用法和get选项配合,就可以在不排序的情况下,获取多个外部键,相当于执行一个整合的获取操作(类似于 sql数据库的join关键字)。

1
2
3
4
5
redis 127.0.0.1:6379> sort uid by not-exists-key
1) "4"
2) "3"
3) "2"
4) "1"

下面的代码,在不引起排序的情况下,使用sort、by和get获取多个外部键:

1
2
3
4
5
6
7
8
9
10
11
12
13
redis 127.0.0.1:6379> sort uid by not-exists-key get # get user_level_* get user_name_*
1) "4" # id
2) "70" # level
3) "mary" # name
4) "3"
5) "25"
6) "peter"
7) "2"
8) "10"
9) "jack"
10) "1"
11) "9999"
12) "admin"

将hash表作为get或by的值:

uid username{id} userlevel{id}
1 admin 999
2 jack 10
3 peter 25
4 mary 70

我们可以不将用户的名字和级别保存在 username{uid} 和 userlevel{uid} 两个字符串键中, 而是用一个带有 name 域和 level 域的哈希表 userinfo{uid} 来保存用户的名字和级别信息:

1
2
3
4
5
6
7
8
9
10
11
redis 127.0.0.1:6379> hmset user_info_1 name admin level 9999
ok

redis 127.0.0.1:6379> hmset user_info_2 name jack level 10
ok

redis 127.0.0.1:6379> hmset user_info_3 name peter level 25
ok

redis 127.0.0.1:6379> hmset user_info_4 name mary level 70
ok

之后, by 和 get 选项都可以用 key->field 的格式来获取哈希表中的域的值, 其中 key 表示哈希表键, 而 field 则表示哈希表的域:

1
2
3
4
5
6
7
8
9
10
11
redis 127.0.0.1:6379> sort uid by user_info_*->level
1) "2"
2) "3"
3) "4"
4) "1"

redis 127.0.0.1:6379> sort uid by user_info_*->level get user_info_*->name
1) "jack"
2) "peter"
3) "mary"
4) "admin"

stor选项,保存排序结果:

默认情况下, sort操作只是简单地返回排序结果,并不进行任何保存操作。通过给 store 选项指定一个 key 参数,可以将排序结果保存到给定的键上。如果被指定的 key 已存在,那么原有的值将被排序结果覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> sort userid
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

127.0.0.1:6379> sort userid store userid_sort
(integer) 5

127.0.0.1:6379> lrange userid_sort 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"