14-BY参数
4.3.3 BY
参数
参考键虽然支持散列类型,但是“
*
”只能在“->
”符号前面(即键名部分)才有用,在“->
”后(即字段名部分)会被当成字段名本身而不会作为占位符被元素的值替换,即常量键名。但是实际运行时会发现一个有趣的结果: 上面提到了当参考键名是常量键名时SORT
命令将不会执行排序操作,然而上例中却进行了排序,而且只是对元素本身进行排序。这是因为Redis判断参考键名是不是常量键名的方式是判断参考键名中是否包含“*
”,而somekey->somefield:*
中包含“*
”所以不是常量键名。所以在排序的时候Redis对每个元素都会读取键somekey
中的somefield:*
字段(“*
”不会被替换),无论能否获得其值,每个元素的参考键值是相同的,所以Redis会按照元素本身的大小排列。
很多情况下列表(或集合、有序集合)中存储的元素值代表的是对象的ID(如标签集合中存储的是文章对象的ID),单纯对这些ID自身排序有时意义并不大。更多的时候我们希望根据ID对应的对象的某个属性进行排序。回想3.6节,我们通过使用有序集合键来存储文章ID列表,使得小白的博客能够支持修改文章时间,所以文章ID的顺序和文章的发布时间的顺序并不完全一致,因此4.3.2节介绍的对文章ID本身排序就变得没有意义了。小白的博客是使用散列类型键存储文章对象的,其中 time
字段存储的就是文章的发布时间。现在我们知道ID为“ 2
”、“ 6
”、“ 1 2
”和“ 26
”的四篇文章的 time
字段的值分别为“ 1352619200
”、“ 1352619600
”、“ 1352620100
”和“ 1352620000
”(Unix时间)。如果要按照文章的发布时间递减排列结果应为“ 12
”、“ 26
”、“ 6
”和“ 2
”。为了获得这样的结果,需要使用 SORT
命令的另一个强大的参数: BY
。
redis> SORT sortbylist BY somekey->somefield:* 1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
BY
参数的语法为 BY参考键
。其中参考键可以是字符串类型键或者是散列类型键的某个字段(表示为键名->字段名)。如果提供了 BY
参数, SORT
命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个“ *
”并获取其值,然后依据该值对元素排序。就像这样:
redis> SORT tag:ruby:posts BY post:*->time DESC 1) "12"
2) "26"
3) "6"
4) "2"
在上例中 SORT
命令会读取 post:2
、 post:6
、 post:12
、 post:26
几个散列键中的 time
字段的值并以此决定 tag:ruby:posts
键中各个文章ID的顺序。
除了散列类型之外,参考键还可以是字符串类型,比如:
redis> LPUSH sortbylist 2 1 3 (integer) 3
redis> SET itemscore:1 50 OK
redis> SET itemscore:2 100 OK
redis> SET itemscore:3 -10 OK
redis> SORT sortbylist BY itemscore:* DESC 1) "2"
2) "1"
3) "3"
当参考键名不包含“*”时(即常量键名,与元素值无关), SORT
命令将不会执行排序操作,因为Redis认为这种情况是没有意义的(因为所有要比较的值都一样)。例如:
redis> SORT sortbylist BY anytext 1) "3"
2) "1"
3) "2"
例子中 anytext
是常量键名(甚至 anytext
键可以不存在),此时 SORT
的结果与 LRANGE
的结果相同,没有执行排序操作。在不需要排序但需要借助 SORT
命令获得与元素相关联的数据时(见4.3.4节),常量键名是很有用的。
如果几个元素的参考键值相同,则 SORT
命令会再比较元素本身的值来决定元素的顺序。像这样:
redis> LPUSH sortbylist 4 (integer) 4
redis> SET itemscore:4 50 OK
redis> SORT sortbylist BY itemscore:* DESC 1) "2"
2) "4"
3) "1"
4) "3"
示例中元素 " 4 "
的参考键 itemscore:4
的值和元素 "1"
的参考键 itemscore:1
的值都是50,所以 SORT
命令会再比较 " 4 "
和 "1"
元素本身的大小来决定二者的顺序。
当某个元素的参考键不存在时,会默认参考键的值为0:
redis> LPUSH sortbylist 5 (integer) 5
redis> SORT sortbylist BY itemscore:* DESC 1) "2"
2) "4"
3) "1"
4) "5"
5) "3"
上例中 " 5 "
排在了 " 3 "
的前面,是因为 " 5 "
的参考键不存在,所以默认为0,而 " 3 "
的参考键值为−10。
补充知识