Статьи

Редис с Джедисами

В этом посте мы поговорим о команде Redis SORT.

Redis предоставляет команду SORT, которую мы можем использовать для извлечения или сохранения отсортированных значений из LIST, SET или ZSET.

В простейшей форме мы можем использовать команду над KEY, как в примере ниже:

1
SORT numbers_list

Это позволит отсортировать значения, содержащиеся в ключе, и вернуть их. Команда сортирует значения по номерам. Итак, допустим, у нас есть список со следующими значениями:

1
1, 110, 5

Команда выше вернется

1
1 5 110

Мы можем указать сортировку значений по алфавиту, используя модификатор ALPHA. Есть ряд модификаторов. Мы рассмотрим некоторые из них в примерах ниже. В примерах будет использоваться API джедаев.

Для наших примеров давайте рассмотрим, что у нас есть система управления идеями. У нас есть список, содержащий все имена пользователей из системы:

1
all:users [junior, francisco, ribeiro, user4]

И для каждого имени пользователя будет хеш, содержащий информацию о пользователе:

01
02
03
04
05
06
07
08
09
10
11
12
13
user:
 
user:junior
  - name: "Junior User"
  - num_ideas : "5"
  - email:"[email protected]"
 
user:francisco
 - name: "Francisco User"
 - num_ideas: "4"
 - email: "[email protected]"
 
...

Мы можем видеть класс, который будет заполнять redis для нашего примера:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package br.com.xicojunior.redistest;
 
import java.util.HashMap;
import java.util.Map;
 
import redis.clients.jedis.Jedis;
 
public class App
{
 
    public static Jedis jedis = new Jedis("localhost");  
    public static void main( String[] args ){
 
        String names[] = new String[]{"junior", "francisco", "ribeiro", "user4"};
        for(String name: names){
            jedis.lpush("all:users", name);
        }
        addUserHash(names[0], "Junior User", "[email protected]", "5");
        addUserHash(names[1], "Francisco User", "[email protected]", "4");
        addUserHash(names[2], "Ribeiro User", "[email protected]", "3");
        addUserHash(names[3], "User 4", "[email protected]", "2");
 
        for(String name: names){
            System.out.println(jedis.hgetAll("user:".concat(name)));
        }
 
        System.out.println(jedis.lrange("all:users", 0, -1));
 
    }
 
    public static void addUserHash(String username, String name, String email, String numberOfIdeas){
        Map<String, String> userProp = new HashMap<String, String>();
        userProp.put("name",name);
        userProp.put("email", email);
        userProp.put("num_ideas", String.valueOf(numberOfIdeas));
 
        jedis.hmset("user:".concat(username), userProp);
    }
}

Давайте посмотрим на пример кода ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package br.com.xicojunior.redistest;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.SortingParams;
 
public class SortTest {
 
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
 
        //[1]sorting the usernames
        System.out.println(jedis.sort("all:users"));
        //[ribeiro, francisco, junior, user4]
 
        //[2]sorting the username alpha
        //jedis sort method receives a SortingParams instance for modifiers
        System.out.println(jedis.sort("all:users", new SortingParams().alpha()));
        //[francisco, junior, ribeiro, user4]
 
    }
 
}

В приведенном выше примере мы сортируем ключ « все: пользователи ». С первой попытки, похоже, сортировка выполнена неправильно, поскольку сортировка по умолчанию учитывает числа. Во втором примере мы используем модификатор ALPHA . Мы можем сделать это, используя перегруженную версию метода sort. Он получает экземпляр класса SortingParams. В этом случае мы видим, что имена пользователей отсортированы правильно.

Приятной особенностью команды SORT является то, что мы можем сортировать список, используя внешние значения, значения в других ключах. В приведенном ниже примере мы отсортируем ключ all: users по количеству идей, предложенных пользователем. Это можно сделать с помощью модификатора « BY », который получает шаблон используемых ключей. Давайте посмотрим наш пример ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package br.com.xicojunior.redistest;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.SortingParams;
 
public class SortTest {
 
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
 
        //[1] Sorting the usernames by the number of ideas
        System.out.println(jedis.sort("all:users", new SortingParams().by("user:*->num_ideas")));
        //[user4, ribeiro, francisco, junior]
 
        //[1] Sorting the usernames by the number of ideas DESC
        System.out.println(jedis.sort("all:users", new SortingParams().by("user:*->num_ideas").desc()));
    }
 
}

Во втором примере мы сортируем имена пользователей по внешнему значению, в нашем случае по полю « num_ideas ». Так как в этом случае мы сортируем по хеш-полю, мы использовали следующий шаблон « user: * -> num_ideas «. С этим шаблоном мы говорим искать ключ « user: * », где этот «*» будет заменен значением из списка. Поскольку это хеш, нам нужно сообщить поле, мы делаем это, используя шаблон « -> fieldname «. Если бы мы сортировали по строковому ключу, мы могли бы использовать следующий шаблон « num_ideas_ * », учитывая, что был ключ для хранения количества идей для каждого пользователя.

При первом вызове он извлекает значения, сортируя их ASC , мы также можем сказать redis, что нужно отсортировать его DESC с помощью модификатора DESC. С jedis BY и DESC являются методы из SortingParams. Поскольку все методы возвращают экземпляр, мы можем связать все вызовы, что облегчает чтение кода.

С помощью команды SORT мы также можем получить значения из внешнего ключа или поля из внешнего хеша. Мы можем сделать это, используя модификатор GET , и мы можем использовать его много раз. Давайте посмотрим несколько примеров этого модификатора ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package br.com.xicojunior.redistest;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.SortingParams;
 
public class SortTest {
 
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
 
        //[1] Sorting the usernames by the number of ideas and retrieving the user name
        System.out.println(jedis.sort("all:users", new SortingParams().by("user:*->num_ideas").get("user:*->name")));
        //[User 4, Ribeiro User, Francisco User, Junior User]
 
        //[2] Retrieving the name and email
        System.out.println(jedis.sort("all:users", new SortingParams().by("user:*->num_ideas").get("user:*->name","user:*->email")));
        //[User 4, [email protected], Ribeiro User, [email protected], Francisco User, [email protected], Junior User, [email protected]]
 
        //[3] Retrieve the value of the key being sorted - Special pattern #
        System.out.println(jedis.sort("all:users", new SortingParams().by("user:*->num_ideas").get("user:*->name","user:*->email","#")));
        //[User 4, [email protected], user4, Ribeiro User, [email protected], ribeiro, Francisco User, [email protected], francisco, Junior User, [email protected], junior]
    }
 
}

В приведенном выше коде мы видим использование модификатора GET , чтобы вернуть хеш-поле, мы можем использовать шаблон, похожий на тот, который мы использовали в модификаторе BY. В первом мы просто возвращаем имя, как мы уже говорили, мы можем использовать GET много раз, во втором мы получаем имя и адрес электронной почты от пользователя. Мы также можем получить значение для ключа, который был отсортирован, используя специальный шаблон «#». Метод get, получает vararg, поэтому мы можем передать все внешние ключи, из которых мы хотим получить значение.

Еще одна вещь, которую мы можем сделать, это сохранить результат сортировки в ключе. Это полезно в тех случаях, когда мы хотим кэшировать результат сортировки, мы можем указать ключ dest для команды сортировки. Результат будет сохранен в виде списка.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package br.com.xicojunior.redistest;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.SortingParams;
 
public class SortTest {
 
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
 
        jedis.sort("all:users","dest_key1");
 
        System.out.println(jedis.lrange("dest_key1", 0, -1));
        //[ribeiro, francisco, junior, user4]
 
        jedis.sort("all:users", new SortingParams().alpha().desc(), "dest_key2");
 
        System.out.println(jedis.lrange("dest_key2", 0, -1));
        //[user4, ribeiro, junior, francisco]
    }
 
}

Одна очень полезная особенность команды SORT заключается в том, что мы можем использовать ее только для получения значений из связанных ключей. Существует модификатор, указывающий, что не следует сортировать NOSORT

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package br.com.xicojunior.redistest;
 
import redis.clients.jedis.Jedis;
import redis.clients.jedis.SortingParams;
 
public class SortTest {
 
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");
 
        System.out.println(jedis.sort("all:users", new SortingParams().get("user:*->name","user:*->email").nosort()));
        //[User 4, [email protected], Ribeiro User, [email protected], Francisco User, [email protected], Junior User, [email protected]]
 
    }
 
}

Этот фрагмент кода в основном получает имя и адрес электронной почты для всех пользователей. В случае, если мы не используем команду SORT, нам понадобятся как минимум две команды, чтобы сделать то же самое:

1
LRANGE all:users 0 -1 //TO get all usernames

а затем для каждого имени пользователя вызовите hmget для каждого, как показано ниже

1
HMGET user:junior name email //TO get the name and email from a user
  • Мы можем найти документацию команды на сайте redis .

Ссылка: Redis сортируется с Jedis от нашего партнера JCG Франсиско Рибейру Младшего в блоге XICO JUNIOR’S WEBLOG .