• redis的sort排序


    Redis排序命令是sort,完整的命令格式如下:
    SORT key [BY pattern] [LIMIT start count] [GET pattern] [ASC|DESC] [ALPHA] [STORE dstkey]
    返回或保存给定列表、集合、有序集合key中经过排序的元素。排序默认以数字作为对象,值被解释为双精度浮点数,然后进行比较。

      说明
    1.一般sort用法  
    > lpush list1 hello 1 world 2 nihao 3 color bit 2B
    (integer) 8

    > lrange list1 0 -1
    1) "2B"
    2) "bit"
    3) "color"
    4) "3"
    5) "nihao"
    6) "2"
    7) "world"
    8) "1"
    9) "hello"
    向链表list1中添加实验数据
    > sort list1
    1) "bit"
    2) "color"
    3) "nihao"
    4) "world"
    5) "hello"
    6) "1"
    7) "2B"
    8) "2"
    9) "3"
    最简单的情况
    a.排序对象:没指定(默认:数字);
    b.排序方式:没有指定(默认:asc升序);

    1.字母开头元素先(字母全当0,内部不排序);
    2.数字开头元素后(内部默认按升序);
    > sort list1 desc
    1) "3"
    2) "2B"
    3) "2"
    4) "1"
    5) "bit"
    6) "color"
    7) "nihao"
    8) "world"
    9) "hello"
    a.排序对象:没指定(默认:数字);
    b.排序方式:指定了desc降序;

    1.数字开头元素先(内部降序)
    2.字母开头元素后(字母全当0,内部不排序)
       
    2.使用alpha修饰符对字符串进行排序  
    > sort list1 alpha
    1) "1"
    2) "2"
    3) "2B"
    4) "3"
    5) "bit"
    6) "color"
    7) "hello"
    8) "nihao"
    9) "world"
    a.指定按alpha(字符)对象;
    b.没有指定方式(默认:asc升序);

    1.数字开头元素先(数字全当a),内部按升序
    2.字母开头元素后,按升序
    > sort list1 desc alpha
    1) "world"
    2) "nihao"
    3) "hello"
    4) "color"
    5) "bit"
    6) "3"
    7) "2B"
    8) "2"
    9) "1"
    a.排序对象:指定按alpha(字符)对象;
    b.排序方式:指定了desc降序

    1.字母开头元素先,按降序
    2.数字开头元素后(数字全当a),内部按降序
       
    3.使用limit修饰符限制返回结果  
    排序之后返回元素的数量可以通过limit修饰符进行限制,修饰符接受offset和count两个参数。
    offset:指定要跳过的元素数量,即起始位置(偏移量;0 1 2 3 ...)。
    count:指定跳过offset个指定的元素之后,要返回多少个对象。
     
    > sort list1 desc alpha limit 2 3
    1) "hello"
    2) "color"
    3) "bit"
    使用limit 2 3限制,在全部查询结果中从第2个偏移,取3个元素。
    用法同MySQL中的limit
       
    4.案例实战篇:假设现在有用户数据如下:  
     
    #添加admin用户
    > lpush listuid 1
    (integer) 1
    > mset user_name_1 admin user_level_1 9999
    OK

    #添加jack用户
    > lpush listuid 2
    (integer) 1
    > mset user_name_2 jack user_level_2 10
    OK

    #添加peter用户
    > lpush listuid 3
    (integer) 2
    > mset user_name_3 peter user_level_3 25
    OK

    #添加mary用户
    > lpush listuid 4
    (integer) 4
    > mset user_name_4 mary user_level_4 70
    OK
    添加实验数据
       
    4.1by 选项[BY pattern]  
    除了可以按集合元素自身值排序外,还可以使用外部 key 的数据作为权重,代替默认的直接对比键值的方式来进行排序。
    即:将集合元素内容按照给定pattern组合成新的key,并按照新key中对应的内容进行排序。
     
    > sort listuid by user_level_* asc
    1) "2"  #jack用户级别10↑,对应键名user_level_2,返回2
    2) "3"  #peter用户级别25↑,对应键名user_level_3,返回3
    3) "4"  #mary用户级别70↑,对应键名user_level_4,返回4
    4) "1"  #admin用户级别9999↑,对应键名user_level_1,返回1
    通过使用by选项,可以让listuid按其他键的元素来排序。

    目的:将用户按用户级别asc升序进行排序,返回排过序的用户uid

    解释:user_level_*是一个占位符,*代表listuid中的元素值,它先逐个取出listuid中的值,然后再用这个值来查找相应user_level_{listuid}元素值,并按要求排序,完成后再将user_level_{listuid}中的{listuid}这部分返回输出。

    过程:比如在对listuid链表进行排序时,程序就会先取出listuid的值1、2、3、4,然后再对应的取出user_level_1、user_level_2、user_level_3和 user_level_4的值进行排序,排序完成后将user_level_{listuid}中的{listuid}返回输出。
    > sort listuid by user_name_* alpha asc
    1) "1"  #admin↑用户对应键名user_name_1,返回1
    2) "2"  #jack↑用户对应键名user_name_2,返回2
    3) "4"  #mary↑用户对应键名user_name_4,返回4
    4) "3"  #peter↑用户对应键名user_name_3,返回3
    目的:按用户名值asc降序进行排序,查询出数据库中对应的uid。
       
    4.2get 选项[GET pattern]  
    我们也可以通过get选项去获取指定pattern作为新key对应的值。  
    > sort listuid get user_level_* desc
    1) "70"    #listuid=4,对应用户级别键名user_level_4值为70
    2) "25"    #listuid=3,对应用户级别键名user_level_3值为25
    3) "10"    #listuid=2,对应用户级别键名user_level_2值为10
    4) "9999"  #listuid=1,对应用户级别键名user_level_1值为9999
    紧接上面实验
    目的:将用户按uid进行desc降序排序,返回排过序的对应用户级别值。
    过程:程序对listuid进行排序,逐个取出排过序的uid元素值4、3、2、1,然后再对应的返回user_level_4、user_level_3、user_level_2和 user_level_1的值。
    > sort listuid get # get user_name_* get user_level_* desc
     1) "4"
     2) "mary"
     3) "70"
     4) "3"
     5) "peter"
     6) "25"
     7) "2"
     8) "jack"
     9) "10"
    10) "1"
    11) "admin"
    12) "9999"
    1.可以同时使用多个get,达到一次性获取多个“字段”(外部键)值目的。
    2.get有一个额外的参数规则,那就是可以用#特殊符号引用原始集合也就是listuid。

    本例使用get #再获取用户uid“字段”
       
    4.3sort by选项 get选项综合使用  
    > sort listuid by user_level_* get # get user_name_* get user_level_* desc
     1) "1"
     2) "admin"
     3) "9999"
     4) "4"
     5) "mary"
     6) "70"
     7) "3"
     8) "peter"
     9) "25"
    10) "2"
    11) "jack"
    12) "10"
    sort、by和get综合使用案例
    > sort listuid by not-exists-key get # get user_name_* get user_level_*
     1) "4"
     2) "mary"
     3) "70"
     4) "3"
     5) "peter"
     6) "25"
     7) "2"
     8) "jack"
     9) "10"
    10) "1"
    11) "admin"
    12) "9999"
    也可以使用 by not-exists-key 不进行任何排序(节省CPU资源),而关联的获取多个外部键。
       
    4.4将哈希表作为get或by的参数  
    除了可以将字符串键之外, 哈希表也可以作为 get 或 by 选项的参数来使用。
    我们可以不将用户的名字和级别保存在 user_name_{uid} 和 user_level_{uid} 两个字符串键中, 而是用一个带有 name 域和 level 域的哈希表 user_info_{uid} 来保存用户的名字和级别信息。
     
    > hmset user_info_1 name admin level 9999
    OK
    > hmset user_info_2 name jack level 10
    OK
    > hmset user_info_3 name peter level 25
    OK
    > hmset user_info_4 name mary level 70
    OK
    添加hash类型实验数据
    > sort listuid by user_info_*->level asc
    1) "2"  #jack用户级别10↑,对应哈希键名user_info_2,返回2
    2) "3"  #peter用户级别25↑,对应哈希键名user_info_3,返回3
    3) "4"  #mary用户级别70↑,对应哈希键名user_info_4,返回4
    4) "1"  #admin用户级别9999↑,对应哈希键名user_info_1,返回1
    by 和 get 选项都可以用 key->field 的格式来获取哈希表中的域的值, 其中 key 表示哈希表键, 而 field 则表示哈希表的域。

    目的:将用户按用户级别asc升序排序,然后返回排过序的用户uid
    > sort listuid get # get user_info_*->name get user_info_*->level desc
     1) "4"
     2) "mary"
     3) "70"
     4) "3"
     5) "peter"
     6) "25"
     7) "2"
     8) "jack"
     9) "10"
    10) "1"
    11) "admin"
    12) "9999"
    目的:将用户按uid进行desc降序排序,返回用户详细信息
       
    5.保存排序结果  
    如果对集合经常按照固定的模式去排序,那么把排序结果缓存起来会减少CPU开销。使用store选项可以将排序内容保存到指定key中。保存的类型是list。如果被指定的 key 已存在,那么原有的值将被排序结果覆盖。  
    > lpush myStore c b a
    (integer) 3
    > lrange myStore 0 -1
    1) "a"
    2) "b"
    3) "c"
    假设我有一个链表类型键,准备存储排序结果
    > sort listuid by user_info_*->level asc store myStore
    (integer) 4
    排序并存储
    返回成功存储的元素个数
    > lrange myStore 0 -1
    1) "2"
    2) "3"
    3) "4"
    4) "1"
    查看结果,原值被覆盖,新值存储了
       


          如果我们有多个redis server的话,不同的key可能存在于不同的server上。比如name12 name13 name23 name23,很有可能分别在四个不同的server上存贮着。这种情况会对排序性能造成很大的影响。redis作者在他的blog上提到了这个问题的解 决办法,就是通过key tag将需要排序的key都放到同一个server上 。由于具体决定哪个key存在哪个服务器上一般都是在client端hash的办法来做的。我们可以通过只对key的部分进行hash.举个例子假如我们 的client如果发现key中包含[]。那么只对key中[]包含的内容进行hash。我们将四个name相关的key,都这样命名[name]12 [name]13 [name]23 [name]23,于是client 程序就会把他们都放到同一server上。不知道jredis实现了没。

          还有一个问题也比较严重。如果要sort的集合非常大的话排序就会消耗很长时间。由于redis单线程的,所以长时间的排序操作会阻塞其他client的 请求。解决办法是通过主从复制机制将数据复制到多个slave上。然后我们只在slave上做排序操作。并进可能的对排序结果缓存。另外就是一个方案是就 是采用sorted set对需要按某个顺序访问的集合建立索引。

  • 相关阅读:
    Spring 控制器层如何调用DAO层
    Spring 工程分层
    spring boot工程如何启用 热启动功能
    Spring 视图层如何显示验证消息提示
    Sping POJO中如何添加验证规则和验证消息提示
    Spirng 分层,增加数据访问对象层
    Spring A 标签链接使用
    Spring 控制器重定向
    课程详情页之后台
    课程详情页之前台
  • 原文地址:https://www.cnblogs.com/martinzhang/p/3416310.html
Copyright © 2020-2023  润新知