Redis学习笔记(九)进阶之排序

SORT命令

除了使用有序集合外,我们还可以借助Redis提供的SORT命令来实现排序。

SORT命令可以对列表类型、集合类型和有序集合类型键进行排序,并且可以完成与关系数据库中的连接查询相类似的任务。

redis> SORT tag:ruby:posts

1)"2"

2)"6"

3)"12"

4)"26"

 

redis> LPUSH mylist 4 2 6 1 3 7

(integer)6

redis> SORT mylist

1)"1"

2)"2"

3)"3"

4)"4"

5)"6"

6)"7"

 

在对有序集合类型进行排序时会忽略元素的分数,只针对元素自身的值进行排序。

redis> ZADD myzset 50 2 40 3 20 1 60 5

(integer)4

redis> SORT myzset

1)"1"

2)"2"

3)"3"

4)"5"

 

除了可以排列数字外,SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字元素:

redis> LPUSH mylistalpha a c e d B C A

(integer)7

redis> SORT mylistalpha

(error)ERR One or more scores can't be converted into double

redis> SORT mylistalpha ALPHA

1)"A"

2)"B"

3)"C"

4)"a"

5)"c"

6)"d"

7)"e"

 

必须加ALPHA参数,不然SORT命令会尝试将所有元素转换为双精度浮点数来比较。

 

SORT命令默认按从小到大的顺序排列,DESC参数可以实现将元素按照从大到小的顺序排列。

redis> SORT tag:ruby:posts DESC

1)"26"

2)"12"

3)"6"

4)"4"

 

SORT命令还支持LIMIT参数来返回指定范围的结果。用法和SQL语句一样,LIMIT offset count,表示跳过前offset个元素并获取之后的count个元素。

redis> SORT tag:ruby:posts DESC LIMIT 1 2

1)"12"

2)"6"

 

BY参数

BY参数的语法为“BY 参考键”。其中参考键可以是字符串类型键或者是散列类型键的某个字段(表示为键名->字段名)。如果提供了BY参数,SORT命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该值对元素进行排序。如:

redis> SORT tag:ruby:posts BY post:*->time DESC

  1. "12"
  2. "26"
  3. "6"
  4. "2"

在上例中SORT命令会读取post:2post:6post:12post: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 anytext

  1. "3"
  2. "1"
  3. "2"

例子中anytext是常量键名(甚至anytext键可以不存在),此时SORT的结果与LRANGE的结果相同,没有执行排序操作。在不需要排序但是需要借助SORT命令获得与元素相关联的数据时,常量键名是很有用的。

如果几个元素的参考键相同,则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"

当某个元素的参考键不存在时,会默认参考键的值为0

redis> LPUSH sortbylist 5

(integer)5

redis> SORT sortbylist BY itemscore:* DESC

  1. "2"
  2. "4"
  3. "1"
  4. "5"
  5. "3"

 

参考键虽然支持散列类型,但是“*”只能在“->”符号前面(即键名部分)才有用,在“->”后(即字段名部分)会被当成字段名本身而不会作为占位符被元素的值替换,即常量键名。但是实际运行时会发现一个有趣的结果:

redis> SORT sortbylist BY somekey->somefield:*

  1. "1"
  2. "2"
  3. "3"
  4. "4"
  5. "5"

上面提到了当参考键名是 常量键名时SORT命令将不会执行排序操作,然而上例中却进行了排序,而且只是对元素本身进行排序。这是因为Redis判断参考键名是不是常量键名的方式是判断参考键名中是否包含"*",而somekey->somefield:*中包含了“*”所以不是常量键名。所以在排序的时候Redis对每个元素都会读取键somekey中的somefield:*字段(*不会被替换),无论能否获得其值,每个元素的参考键值是相同的,所以Redis会按照元素本身的大小排列。

 

GET参数

GET参数不影响排序,它的作用是使SORT命令的返回结果不再是元素自身的值,而是GET参数中指定的键值。GET参数的规则和BY参数一样,GET参数也支持字符串类型和散列类型的键,并使用“*”作为占位符。如:

redis> SORT tag:ruby:posts BY post:*->time DESCGET post:*->title

  1. "Windows 8 app designs"
  2. "love"
  3. "Uses for Linux"
  4. "The Ruby' nature"

在一个SORT命令可以使用多个GET参数(而BY参数只能有一个),GET #是返回元素本身的值。如:

redis> SORT tag:ruby:posts BY post:*->time DESCGET post:*->title GET post:*->time GET #

  1. "Windows 8 app designs"
  2. "2123132121"
  3. "12"
  4. "love"
  5. "2021212111"
  6. "26"
  7. "Uses for Linux"
  8. "1902012212"
  9. "6"
  10. "The Ruby' nature"
  11. "1021212121"
  12. "2"

 

STORE参数

默认情况下SORT会直接返回排序结果,如果希望保存排序结果,可以使用STORE参数。

redis> SORT tag:ruby:posts BY post:*->time DESCGET post:*->title GET post:*->time GET # STORE sort.result

(integer)12

redis> LRANGE sort.result 0 -1

  1. "Windows 8 app designs"
  2. "2123132121"
  3. "12"
  4. "love"
  5. "2021212111"
  6. "26"
  7. "Uses for Linux"
  8. "1902012212"
  9. "6"
  10. "The Ruby' nature"
  11. "1021212121"
  12. "2"

保存后的键的类型为列表类型,如果键已经存在则会覆盖它。STORE参数常用来结合EXPIRE命令缓存排序结果。

 

性能优化

SORTRedis中最强大最复杂命令之一。时间复杂度为O(n+mlogm),其中,n为要排序的列表中的元素个数,m表示要返回的元素个数。

开发中需要注意:

1)尽可能减少待排序键中元素的数量(使n尽可能小)。

2)使用LIMIT参数只获取需要的数据(使m尽可能小)。

3)如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值