Redis sort sorting command details

  • 2020-05-13 03:48:35
  • OfStack

This article describes the redis sorting command

redis supports sorting of list, set, sorted set elements

sort sort command format:

sort key [BY pattern] [LIMIT start count] [GET pattern] [ASC|DESC] [ALPHA] [STORE dstkey]

1) sort key (list)

This is the simplest case where there is no option to sort the elements of the collection itself and return the sorted results; the default is value ascending.

Example:


127.0.0.1:6379> lpush mimvp 12
(integer) 1
127.0.0.1:6379> lpush mimvp 11
(integer) 2
127.0.0.1:6379> lpush mimvp 13
(integer) 3
127.0.0.1:6379> lpush mimvp 10
(integer) 4
127.0.0.1:6379> lrange mimvp 0 -1
1) " 10 "
2) " 13 "
3) " 11 "
4) " 12 "
127.0.0.1:6379> sort mimvp
1) " 10 "
2) " 11 "
3) " 12 "
4) " 13 "
127.0.0.1:6379> sort mimvp desc
1) " 13 "
2) " 12 "
3) " 11 "
4) " 10 "

2) [ASC|DESC] [ALPHA] (list)

The default sorting method for sort (asc) is from small to large, but it can also be sorted in reverse or character order.

You can add desc in reverse order, alpha in alphabetical order, alpha in alphabetical order, alpha in alphabetical order, desc1 in alphabetical order.

sort is sorted by score (numeric value) by default, and letters are sorted by sort by default. Error will be reported!

Example:


127.0.0.1:6379> lpush mylist forum
(integer) 1
127.0.0.1:6379> lpush mylist proxy
(integer) 2
127.0.0.1:6379> lpush mylist blog
(integer) 3
127.0.0.1:6379> lpush mylist apptop
(integer) 4
127.0.0.1:6379> sort mylist
(error) ERR One or more scores can't be converted into double
127.0.0.1:6379> sort mylist alpha
1) " apptop "
2) " blog "
3) " forum "
4) " proxy "
127.0.0.1:6379> sort mylist alpha desc
1) " proxy "
2) " forum "
3) " blog "
4) " apptop "
127.0.0.1:6379> sort mylist desc alpha
1) " proxy "
2) " forum "
3) " blog "
4) " apptop "

3) [BY pattern] (set)

In addition to sorting by the set element's own value (number, letter), you can also combine the set element contents into the new key according to the given pattern, and order them according to the corresponding contents in the new key.

Example:


127.0.0.1:6379> set mimvp_12 mimvp_12
OK
127.0.0.1:6379> set mimvp_11 mimvp_11
OK
127.0.0.1:6379> set mimvp_13 mimvp_13
OK
127.0.0.1:6379> set mimvp_10 mimvp_10
OK
127.0.0.1:6379> sort mimvp by mimvp_*         // mimvp_* It's a string, so it needs to be alpha
(error) ERR One or more scores can't be converted into double
127.0.0.1:6379> sort mimvp by mimvp_* alpha
1) " 10 "
2) " 11 "
3) " 12 "
4) " 13 "
127.0.0.1:6379> sort mimvp by mimvp_* alpha desc
1) " 13 "
2) " 12 "
3) " 11 "
4) " 10 "

* represents the element values already given by example 1) mimvp above, so the sorting is done according to mimvp_12, mimvp_11, mimvp_13, mimvp_10 corresponding to the four key values, but the sorted mimvp set element is still returned, that is, the value 13,11,12,10, rather than the mimvp_* string element.

4) [GET pattern]

The above examples are numeric elements in the returned mimvp collection, or you can use the get option to get the string value that specifies pattern as the new key (mimvp_*).

Example:


127.0.0.1:6379> sort mimvp by mimvp_* get mimvp_* alpha
1) " mimvp_10 "
2) " mimvp_11 "
3) " mimvp_12 "
4) " mimvp_13 "
127.0.0.1:6379> sort mimvp by mimvp_* get mimvp_* alpha desc
1) " mimvp_13 "
2) " mimvp_12 "
3) " mimvp_11 "
4) " mimvp_10 "

This time, instead of returning the elements in mimvp, the corresponding values of mimvp_12, mimvp_11, mimvp_13, mimvp_10 are sorted alphabetically according to the values of mimvp_12, mimvp_11, mimvp_13, mimvp_10.

In addition, the get option can have more than one, and the # special symbol refers to the original set, which is mimvp (similar to sorted-set withscores)

Example:


127.0.0.1:6379> sort mimvp by mimvp_* get mimvp_* get # alpha
1) " mimvp_10 "
2) " 10 "
3) " mimvp_11 "
4) " 11 "
5) " mimvp_12 "
6) " 12 "
7) " mimvp_13 "
8) " 13 "
127.0.0.1:6379> sort mimvp by mimvp_* get mimvp_* get # alpha desc
1) " mimvp_13 "
2) " 13 "
3) " mimvp_12 "
4) " 12 "
5) " mimvp_11 "
6) " 11 "
7) " mimvp_10 "
8) " 10 "

Finally, there is a special character - that references a field of type hash > (hash)

Example:


127.0.0.1:6379> hset user_12 name yanggang
(integer) 1
127.0.0.1:6379> hset user_11 name yangjie
(integer) 1
127.0.0.1:6379> hset user_13 name yangliang
(integer) 1
127.0.0.1:6379> hset user_10 name yangchuang
(integer) 1
127.0.0.1:6379> sort mimvp get user_*->name
1) " yangchuang "
2) " yangjie "
3) " yanggang "
4) " yangliang "
127.0.0.1:6379> sort mimvp get user_*->name desc
1) " yangliang "
2) " yanggang "
3) " yangjie "
4) " yangchuang "

It is easy to understand that if mimvp does not exist, then nil is returned

5) [LIMIT start count] (limit)

The above example returns all elements, and the limit option limits the number of results returned.

Example:


127.0.0.1:6379> sort mimvp get mimvp_* limit 1 2
1) " mimvp_11 "
2) " mimvp_12 "
127.0.0.1:6379> sort mimvp get mimvp_* limit 0 3
1) " mimvp_10 "
2) " mimvp_11 "
3) " mimvp_12 "

The start subscript starts at 0, and the limit option (limit 1 2) means to get 2 from the second element.

6) [STORE dstkey] (store)

If the collection is often sorted in a fixed pattern, caching the sorted results can reduce the cpu overhead. Using the store option, you can save the sorted contents to the specified key, of type list


127.0.0.1:6379> sort mimvp get mimvp_* limit 0 3 store mimvp_store
(integer) 3
127.0.0.1:6379> type mimvp_store
list
127.0.0.1:6379> lrange mimvp_store 0 -1
1) " mimvp_10 "
2) " mimvp_11 "
3) " mimvp_12 "

This example saves the sorted results to mimvp_store and extracts them directly from mimvp_store.

summary

After the introduction of the functions, we will discuss some problems about sorting.

If there are multiple redis server, different key may exist on different server. For example, mimvp_12, mimvp_11, mimvp_13, mimvp_10 are likely to be stored on four different server, which can have a significant impact on sorting performance.

The author of redis mentions in his blog that the solution to this problem is to place all the key that need to be sorted on the same server through key tag. Since deciding which key is stored on which server 1 is usually done on hash at client, we can hash only on the part of key

Here's an example:

If our client finds that key contains [], then only hash contains [] in key. We will name all four key related to name as [name]12 [name]13 [name]11 [name]10, and then the client program will put them all on the same 1server.

There is also a serious problem

If you want the collection of sort to be very large the sorting takes a long time. Because redis is single-threaded, long sort operations block other client requests. The solution is to replicate the data to multiple slave via master-slave replication. Then we only sort on slave and cache the sorted results as much as possible. Another option is to use sorted set to index collections that need to be accessed in a certain order.

Example:


127.0.0.1:6379> sadd tom:friend:list 123        # tom The list of friends is the list of friends uid
(integer) 1
127.0.0.1:6379> sadd tom:friend:list 456
(integer) 1
127.0.0.1:6379> sadd tom:friend:list 789
(integer) 1
127.0.0.1:6379> sadd tom:friend:list 101
(integer) 1
127.0.0.1:6379> set uid:sort:123 1000            # uid Corresponding grades
OK
127.0.0.1:6379> set uid:sort:456 6000
OK
127.0.0.1:6379> set uid:sort:789 100
OK
127.0.0.1:6379> set uid:sort:101 5999
OK
127.0.0.1:6379> set uid:123 " { ' uid':123,'name':'lucy'} "             # increase uid Corresponding friend information
OK
127.0.0.1:6379> set uid:456 " { ' uid':456,'name':'jack'} "
OK
127.0.0.1:6379> set uid:789 " { ' uid':789,'name':'marry'} "
OK
127.0.0.1:6379> set uid:101 " { ' uid':101,'name':'icej'} "  
OK
127.0.0.1:6379> sort tom:friend:list by uid:sort:* get uid:*    # Get it from your buddy list id with uid:sort Sort after the fields match , And according to the order after sorting, use key in uid Table to get information
1) " { ' uid':789,'name':'marry'} "
2) " { ' uid':123,'name':'lucy'} "
3) " { ' uid':101,'name':'icej'} "
4) " { ' uid':456,'name':'jack'} "
127.0.0.1:6379> sort tom:friend:list by uid:sort:* get uid:* get uid:sort:*
1) " { ' uid':789,'name':'marry'} "
2) " 100 "
3) " { ' uid':123,'name':'lucy'} "
4) " 1000 "
5) " { ' uid':101,'name':'icej'} "
6) " 5999 "
7) " { ' uid':456,'name':'jack'} "
8) " 6000 "

Problems and analysis

1. Why is sort mimvp by * get * mimvp_* get # alpha arranged in the order of 10 and 13, which is not the same as the simple sorting of name* and name * alpha

This problem is analyzed from the implementation logic of redis

a) list (FILO, FILO), lrange ml 0-1, the result is :12, 13, 11, 10. This is because list inserts the latest item into the header

If mimvp_* is not num and alpha is not set, the sorting score will be the same, because the program will try to convert mimvp_* to nun

This causes sort mimvp by mimvp_* to be arranged in the natural order of ml


if (alpha) {
    if (sortby) {
        vector[j].u.cmpobj = getDecodedObject(byval);
    }
}
else {
    if (byval->encoding == REDIS_ENCODING_RAW) {
        vector[j].u.score = strtod(byval->ptr,NULL);
    }
    else if (byval->encoding == REDIS_ENCODING_INT) {
        /* Don't need to decode the object if it's
         * integer-encoded (the only encoding supported) so
         * far. We can just cast it
         */
        vector[j].u.score = (long)byval->ptr;
    }
    else {
        redisAssert(1 != 1);
    }  
}


Related articles: