Redis中的排序可以怎么实现?

遇到这个问题,我上来就回答可以利用数据结构的特性,比如Zset的自带排序。(当时没有想到redis也是自带sort功能,对无序数据结构进行后续排序的)


先看AI的表现:

问题:Redis排序知道吗?如果我的业务场景中需要引入Redis缓存,且需要维护一定的顺序性,Redis可以通过哪些方式实现?

回答:

是的,Redis可以通过一些方式来实现有序集合的排序功能。

1. 使用有序集合

Redis中的有序集合(SortedSet)是一个键值对集合,其中每个元素都有一个分数(score),可以根据分数进行排序。

使用ZADD命令添加元素时,指定分数即可。使用ZRANGEBYSCORE命令可以按照分数区间获取元素,使用ZREVRANGEBYSCORE命令可以按照分数区间逆序获取元素。

2. 使用列表

Redis中的列表(List)可以通过LPUSH、RPUSH、LINSERT等命令添加元素。使用LINDEX命令可以获取指定位置的元素,使用LLEN命令可以获取列表长度。

可以通过设置列表元素的值来实现排序功能。例如,将列表元素设置为JSON字符串,其中包含一个需要排序的字段。然后可以使用SORT命令按照该字段进行排序。

3. 使用有序列表

Redis中的有序列表(Sorted List)是通过列表和有序集合实现的。列表中存储元素,有序集合中存储元素对应的分数。使用ZADD命令向有序集合中添加元素时,同时在列表中插入一个元素。使用ZRANGEBYSCORE命令按照分数区间获取元素时,同时获取对应的列表元素。

有序列表可以实现高效的排序功能,因为它既可以按照分数进行排序,又可以按照插入顺序进行排序。

以上是Redis实现排序的三种方式,可以根据具体业务场景选择合适的方式来实现。


我们自己在服务器上进行实践

首先开启服务器

centos上执行: redis-server

但是如果我们有自定义配置的话,一定要后接自己的配置文件地址

redis-server /usr/local/redis-5.0.8/redis.conf

b9df3a81c4eb480681ea4d8ab1071984.png

 再开一个客户端,执行redis-cli进入客户端。

Sort命令

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

在列表中使用

127.0.0.1:6379> lpush mylist 4 2 5 1 3 7
(integer) 6
127.0.0.1:6379> sort mylist
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "7"
127.0.0.1:6379>

 在集合中使用

127.0.0.1:6379> sadd myset 2 8 55 5 6 6 9
(integer) 6
127.0.0.1:6379> sort myset
1) "2"
2) "5"
3) "6"
4) "8"
5) "9"
6) "55"

在有序集合中使用

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

127.0.0.1:6379> zadd myzset 50 2 40 3 20 1 60 6
(integer) 4
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "1"
2) "20"
3) "3"
4) "40"
5) "2"
6) "50"
7) "6"
8) "60"
127.0.0.1:6379> sort myzset
1) "1"
2) "2"
3) "3"
4) "6"

zrange的含义与作用

Redis中的ZRANGE指令用于获取有序集合(Sorted Set)中指定范围内的元素,按照元素的分值(score)从小到大排序。

语法如下:

ZRANGE key start stop [WITHSCORES]

参数说明:

  • key:有序集合的键名。
  • start:元素排名的起始值,从0开始计数,表示第一个元素。
  • stop:元素排名的结束值,从0开始计数。如果指定的值比集合的长度大,就返回集合中的所有元素。如果stop的值为-1,则表示获取集合中的所有元素。
  • WITHSCORES:可选参数,指定是否返回元素的分值(score)。如果指定了该参数,则会在返回结果中包含每个元素的分值。

举个例子,如果有一个有序集合scores,其中包含以下元素:

redis> ZADD scores 10 Tom
redis> ZADD scores 20 Jack
redis> ZADD scores 30 Alice
redis> ZADD scores 40 Bob

使用ZRANGE scores 0 -1指令,则会返回整个有序集合,按照分值从小到大排序:

1) "Tom"
2) "Jack"
3) "Alice"
4) "Bob"

如果使用ZRANGE scores 1 2命令,则会返回排名为1和2的元素,即"Jack"和"Alice":

1) "Jack"
2) "Alice"

如果使用ZRANGE scores 0 -1 WITHSCORES命令,则会返回整个有序集合,包含每个元素的分值:

1) "Tom"
2) "10"
3) "Jack"
4) "20"
5) "Alice"
6) "30"
7) "Bob"
8) "40"


DESC和LIMIT参数

使用sort命令配合DESC参数可以实现倒序排序。

127.0.0.1:6379> lpush mylist 1 3 5 7 1 -1 233 4
(integer) 8
127.0.0.1:6379> sort mylist desc
1) "233"
2) "7"
3) "5"
4) "4"
5) "3"
6) "1"
7) "1"
8) "-1"

使用limit可以分页显示结果。Limist offet count:我们从第offset+1元素开始输出,取count个元素

127.0.0.1:6379> sort mylist desc limit 0 2
1) "233"
2) "7"

BY参数:自定义排序

假定有一张表的数据如下:

uiduser_name_{uid}user_level_{uid}
1admin9999
2jack10
3lucky256
4mary70

对于上表中的数据,很多情况下在Redis 中的存储方式是:使用列表存储 uid,再分别用字符串存储 user_name_ {uid} 和 user_level_ {uid}

我们根据上述传统模式,在redis中添加数据

首先添加admin

127.0.0.1:6379> lpush uid 1
(integer) 1
127.0.0.1:6379> set user_name_1 admin
OK
127.0.0.1:6379> set user_level_1 9999
OK
127.0.0.1:6379>
 

再添加jack的信息

127.0.0.1:6379> lpush uid 2
(integer) 2
127.0.0.1:6379> set user_name_2 jack
OK
127.0.0.1:6379> set user_level_2 10
OK
 

 我们分别用sort uid和sort uid by user_level_* 查看效果:

127.0.0.1:6379> sort uid
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> sort uid by user_level_*
1) "2"
2) "3"
3) "1"
127.0.0.1:6379>
 

 对by pattern的解释:

​​user_level_*​​ 是一个占位符, 它先取出 ​​uid​​ 中的值, 然后再用这个值来查找相应的键。

比如在对 ​​uid​​ 列表进行排序时, 程序就会先取出 ​​uid​​ 的值 ​​1​​ 、 ​​2​​ 、 ​​3​​ 、 ​​4​​ , 然后使用 ​​user_level_1​​ 、 ​​user_level_2​​ 、 ​​user_level_3​​ 和 ​​user_level_4​​ 的值作为排序 ​​uid​​ 的权重。
 

GET参数:获取外部键

对于上述根据pattern进行排序,我们还想知道具体的键值,那么可以引入GET选项

比如,以下代码先排序uyid,然后,再取出对应键user_name_{uid}的值:

127.0.0.1:6379> sort uid
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> sort uid get user_name_*
1) "admin"
2) "jack"
3) "lucky"

 我们一条语句也可以跟上多个GET参数

比如说, 以下代码就按 ​​uid​​ 分别获取 ​​user_level_{uid}​​ 和 ​​user_name_{uid}​​ :

127.0.0.1:6379> sort uid get user_level_* GET user_name_*
1) "9999"
2) "admin"
3) "10"
4) "jack"
5) "256"
6) "lucky"

 GET​​ 有一个额外的参数规则,那就是 —— 可以用 ​​#​​ 获取被排序键的值。

以下代码就将 ​​uid​​ 的值、及其相应的 ​​user_level_*​​ 和 ​​user_name_*​​ 都返回为结果:

127.0.0.1:6379> sort uid GET # GET user_level_* get user_name_*
1) "1"
2) "9999"
3) "admin"
4) "2"
5) "10"
6) "jack"
7) "3"
8) "256"
9) "lucky"

 STORE 参数:保存排序结果

首先我们用一个列表来缓存结果

默认情况下, ​​SORT​​ 操作只是简单地返回排序结果,并不进行任何保存操作。

通过给 ​​STORE​​ 选项指定一个 ​​key​​ 参数,可以将排序结果保存到给定的键上。

如果被指定的 ​​key​​ 已存在,那么原有的值将被排序结果覆盖。

127.0.0.1:6379> rpush mynum 1 3 5
(integer) 3
127.0.0.1:6379> lrange mynum 0 -1
1) "1"
2) "3"
3) "5"
127.0.0.1:6379> rpush mynum 2 4 6
(integer) 6
127.0.0.1:6379> lrange mynum 0 -1
1) "1"
2) "3"
3) "5"
4) "2"
5) "4"
6) "6"
127.0.0.1:6379> sort mynum store mysortednum
(integer) 6
127.0.0.1:6379> lrange mysortednum 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"


小节:

SORT是Redis中最强大最复杂的命令之一,如果使用不好很容易成为性能瓶颈。

SORT命 令的时间复杂度是O(n+mlog(m)),其中n表示要排序的列表(集合或有序集合)中的元素个 数,m表示要返回的元素个数。

所以开发中使用SORT命令时需要注意以下几点。

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

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

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


参考资料:

Redis 排序功能 -- SORT_51CTO博客_redis sort

 

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值