Управление сортированными наборами в Redis

Redis — это хранилище данных типа “ключ-значение” с открытым исходным кодом. В Redis сортированные наборы — это тип данных. Они похожи на обычные наборы в том, что оба эти типы данных являются уникальными группами строк. Разница между обычными и сортированными наборами заключается в том, что все члены последнего связаны с оценкой, что позволяет сортировать их от наименьшей оценки к наибольшей. Как и в случае с простыми наборами, каждый член сортированного набора должен быть уникальным, хотя несколько членов могут иметь одинаковые оценки.

В этом мануале вы узнаете, как создавать сортированные наборы, извлекать и удалять их элементы, а также создавать новые сортированные наборы на основе существующих.

Как работать с этим мануалом

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

Команды, использованные в этом мануале, были протестированы на сервере Ubuntu 18.04 и экземпляре Redis версии 4.0.9. Чтобы настроить аналогичную среду, вы можете следовать разделу 1 руководства Установка и защита Redis в Ubuntu 18.04. Мы покажем, как эти ведут себя команды в redis-cli, интерфейсе командной строки Redis. Обратите внимание, что если вы используете другой интерфейс Redis — например, Redli – то вывод некоторых команд будет отличаться.

Создание сортированных наборов

Чтобы создать сортированный набор, используйте команду zadd. Она принимает в качестве аргументов имя ключа, в котором будет храниться сортированный набор, а затем оценку добавляемого вами элемента и его значение. Следующая команда создаст сортированный набор с ключом faveGuitarists с одним членом, «Joe Pass», который имеет оценку 1:

zadd faveGuitarists 1 "Joe Pass"

Если команда zadd была выполнена успешно, она вернет число, которое указывает количество элементов, добавленных в сортированный набор.

(integer) 1

С помощью этой команды можно добавить в сортированный набор более одного члена. Обратите внимание: их оценки не должны быть последовательными, между оценками могут быть промежутки; также несколько членов в одном и том же сортированном наборе могут иметь одинаковую оценку:

zadd faveGuitarists 4 "Stephen Malkmus" 2 "Rosetta Tharpe" 3 "Bola Sete" 3 "Doug Martsch" 8 "Elizabeth Cotten" 12 "Nancy Wilson" 4 "Memphis Minnie" 12 "Michael Houser"
(integer) 8

Команда zadd принимает такие опции (их нужно указывать после имени ключа и перед оценкой первого элемента):

  • NX или XX: эти опции имеют противоположное действие, потому вы можете включить в команду только одну из них:
    • NX говорит zadd не обновлять существующие элементы набора. С этой опцией команда zadd только добавит новые элементы, сохранив предыдущие.
    • XX, напротив, обновляет существующие элементы. С этой опцией команда zaddа обновит существующие элементы, не добавляя новых.
  • CH: Обычно zadd возвращает только количество новых элементов, добавленных в отсортированный набор. Однако, если в команде включена эта опция, zadd вернет количество измененных элементов: включая новые элементы и те, чьи оценки изменились.
  • INCR: увеличивает значение оценки элемента. Если элемент еще не существует, команда добавит его в сортированный набор, а оценку увеличит на указанное число, отталкиваясь от исходного значения 0. С опцией INCR zadd вернет новую оценку элемента, если все прошло успешным. Обратите внимание: при использовании этой опции вы можете включать только одну пару оценка/элемент.

Вместо параметра INCR в zadd вы можете использовать команду zincrby — она ведет себя точно так же. Вместо присваивания сортированному элементу значения, указанного в качестве оценки (как zadd), zincrby увеличивает оценку этого элемента на указанное значение. Например, следующая команда увеличивает на 5 оценку элемента «Stephen Malkmus» — изначально была 4, а будет 9.

zincrby faveGuitarists 5 "Stephen Malkmus"
"9"

Как и в случае с параметром INCR команды zadd, если указанный элемент не существует, команда zincrby создаст его с инкрементным значением в качестве оценки.

Извлечение членов из сортированных наборов

Основной способ извлечения элементов, хранящихся в отсортированном наборе, — это команда zrange. Она принимает в качестве аргументов имя ключа, элементы которого вы хотите извлечь, и диапазон элементов, содержащихся в нем. Диапазон определяется двумя числами, которые представляют индексы. Индексация начинается с нуля: 0 представляет первый элемент в сортированном наборе (или элемент с наименьшей оценкой), 1 представляет следующий и т. д.

В этом примере возвращаются первые четыре члена из сортированного набора faveGuitarists, созданного в предыдущем разделе:

zrange faveGuitarists 0 3
1) "Joe Pass"
2) "Rosetta Tharpe"
3) "Bola Sete"
4) "Doug Martsch"

Обратите внимание: если в сортированном наборе, который вы передаете команде zrange, есть два или более элементов с одинаковыми оценками, эти элементы будут отсортированы в алфавитном порядке.

Исходный и конечный индексы также могут выражаться отрицательными числами, где -1 обозначает последний член, -2 — предпоследний и т. д.

zrange faveGuitarists -5 -2
1) "Memphis Minnie"
2) "Elizabeth Cotten"
3) "Stephen Malkmus"
4) "Michael Houser"

Команда zrange может принять аргумент WITHSCORES, который будет возвращать оценки элементов:

zrange faveGuitarists 5 6 WITHSCORES
1) "Elizabeth Cotten"
2) "8"
3) "Stephen Malkmus"
4) "9"

Команда zrange может возвращать диапазон членов только в порядке возрастания номеров. Чтобы изменить это и вернуть диапазон в порядке убывания, вы должны использовать команду zrevrange. По сути эта команда выполняет временное изменение порядка данного отсортированного набора перед возвратом элементов, попадающих в указанный диапазон. При использовании zrevrange 0 будет представлять последний элемент, содержащийся в ключе, 1 — предпоследний и так далее:

zrevrange faveGuitarists 0 5
1) "Nancy Wilson"
2) "Michael Houser"
3) "Stephen Malkmus"
4) "Elizabeth Cotten"
5) "Memphis Minnie"
6) "Doug Martsch"
zrevrange также может принять опцию WITHSCORES.

Вы можете вернуть диапазон элементов на основании их оценок с помощью команды zrangebyscore. В следующем примере команда выводит все элементы включе faveGuitarists с оценками 2, 3 или 4:

zrangebyscore faveGuitarists 2 4
1) "Rosetta Tharpe"
2) "Bola Sete"
3) "Doug Martsch"
4) "Memphis Minnie"

В этом примере диапазон включительный — то есть он вернет все элементы с оценками 2 или 4. Вы можете исключить любой конец диапазона, поставив перед ним открытую скобку ((). В следующем примере показано, как это работает: здесь будут выведены все элементы с оценкой больше или равно 2, но меньше 4:

zrangebyscore faveGuitarists 2 (4
1) "Rosetta Tharpe"
2) "Bola Sete"
3) "Doug Martsch"

Как и zrange, zrangebyscore может принимать аргумент WITHSCORES. Он также принимает параметр LIMIT, который вы можете использовать для извлечения только выбранных элементов из вывода zrangebyscore. Эта опция принимает смещение (оно отмечает первый элемент в диапазоне, который вернет команда) и счетчик (который определяет, сколько элементов команда вернет в общей сложности). Например, следующая команда рассмотрит первые шесть элементов сортированного набора faveGuitarists, но вернет из него только 3 элемента, начиная со второго в диапазоне, представленном 1:

zrangebyscore faveGuitarists 0 5 LIMIT 1 3
1) "Rosetta Tharpe"
2) "Bola Sete"
3) "Doug Martsch"

Команда zrevrangebyscore возвращает диапазон членов в обратном порядке на основе их оценок. Следующая команда возвращает все элементы набора с оценкой от 10 до 6:

zrevrangebyscore faveGuitarists 10 6
1) "Stephen Malkmus"
2) "Elizabeth Cotten"

Как и zrangebyscore, zrevrangebyscore может принимать опции WITHSCORES и LIMIT. Кроме того, вы можете исключить любой конец диапазона, поставив перед ним открытую скобку.

В отдельных случаях все элементы в отсортированном наборе имеют одинаковые оценки. В таком случае redis может вернуть диапазон элементов, отсортированных в алфавитном порядке, с помощью команды zrangebylex. Чтобы посмотреть, как она работает, выполните следующую команду zadd и создайте сортированный набор, в котором все элементы имеют одинаковые оценки:

zadd SomervilleSquares 0 Davis 0 Inman 0 Union 0 porter 0 magoun 0 ball 0 assembly

Команда zrangebylex принимает имя ключа, а затем начальную и конечную точку интервала. Обе точки должны начинаться с открытой круглой или квадратной скобки (символы ( или [).

zrangebylex SomervilleSquares [a [z
1) "assembly"
2) "ball"
3) "magoun"
4) "porter"

Обратите внимание: в этом примере мы получили только 4 из 8 элементов набора, хотя команда искала диапазон от a до z. Это связано с тем, что Redis чувствителен к регистру, поэтому элементы, начинающиеся с заглавных букв, были исключены из вывода. Чтобы вывести их, вы можете запустить следующую команду:

zrangebylex SomervilleSquares [A [z
1) "Davis"
2) "Inman"
3) "Union"
4) "assembly"
5) "ball"
6) "magoun"
7) "porter"

zrangebylex также принимает специальные символы -, который представляет отрицательную бесконечность, и +, который представляет положительную бесконечность. Таким образом, следующий синтаксис вернет все элементы сортированного набора:

zrangebylex SomervilleSquares - +

Обратите внимание: zrangebylex не может возвращать элементы набора в обратном алфавитном порядке. Для этого используйте команду zrevrangebylex:

zrevrangebylex SomervilleSquares + -
1) "porter"
2) "magoun"
3) "ball"
4) "assembly"
5) "Union"
6) "Inman"
7) "Davis"

Поскольку команда zrangebylex предназначена для работы с сортированными наборами, в которых оценки всех элементов одинаковы, она не принимает опцию WITHSCORES. Но она принимает параметр LIMIT.

Извлечение информации о сортированных наборах

Чтобы узнать, сколько элементов входит в данный сортированный набор (или, другими словами, определить его кардинальное число), используйте команду zcard. В следующем примере показано, сколько элементов содержится в ключе faveGuitarists из первого раздела мануала:

zcard faveGuitarists
(integer) 9

Команда zcount может сказать, сколько элементов, содержащихся в заданном сортированном наборе, попадают в определенный диапазон оценок. Первое число после ключа задает начало диапазона, а второе — конец.

zcount faveGuitarists 3 8
(integer) 4

Команда zscore выдает оценку конкретного элемента набора:

zscore faveGuitarists "Bola Sete"
3

Если указанный член или ключ не существует, zscore вернет (nil).

Команда zrank похожа на zscore, но она возвращает не оценку заданного элемента, а его ранг. В Redis ранг — это индекс элементов отсортированного набора с нулевой базой, упорядоченный по их оценкам. Например, элемент «Joe Pass» имеет оценку 1, но, поскольку это самая низкая оценка среди всех элементов данного ключа, он имеет ранг 0:

zrank faveGuitarists "Joe Pass"
(integer) 0

Есть еще одна команда Redis, zrevrank, которая выполняет ту же функцию, что и zrank, но она обращает ранги элементов в наборе. То есть, элемент «Joe Pass», который имеет наименьшую оценку, получит наивысший ранг:

zrevrank faveGuitarists "Joe Pass"
(integer) 8

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

Как и zscore, команды zrank и zrevrank вернут (nil), если ключ или элемент не существует.

Команда zlexcount сообщит вам, сколько элементов в сортированном наборе попадает в заданный алфавитный диапазон. В следующем примере мы применим эту команду на сортированный набор SomervilleSquares из предыдущего раздела:

zlexcount SomervilleSquares [M [t
(integer) 5

Эта команда использует тот же синтаксис, что и zrangebylex (обратитесь к предыдущему разделу за подробностями о том, как определить диапазон строк).

Удаление элементов из сортированного набора

Команда zrem может удалить один или несколько элементов из сортированного набора:

zrem faveGuitarists "Doug Martsch" "Bola Sete"

Команда zrem вернет целое число, указывающее, сколько элементов было удалено:

(integer) 2

Есть три команды Redis, которые позволяют удалять элементы сортированного набора на основе диапазона. Например, если у всех элементов в наборе одинаковая оценка, вы можете удалить элемент на основе лексикографического диапазона — это делается с помощью zremrangebylex. Эта команда использует тот же синтаксис, что и zrangebylex. В следующем примере команда удаляет все элементы, начинающиеся с заглавной буквы, из ключа SomervilleSquares:

zremrangebylex SomervilleSquares [A [Z

В выводе команда zremrangebylex укажет количество удаленных элементов:

(integer) 3

Вы также можете удалить элементы на основе диапазона оценок. Это делается с помощью команды zremrangebyscore, которая использует тот же синтаксис, что и zrangebyscore. В следующем примере будут удалены все элементы faveGuitarists с оценкой 4, 5 или 6:

zremrangebyscore faveGuitarists 4 6
(integer) 1

Вы можете удалить элемент из набора на основе диапазона рангов. Для этого есть команда zremrangebyrank, которая использует тот же синтаксис, что и zrangebyrank. Следующая команда удалит три элемента с наименьшим рангом, (который определяется диапазоном индексов с нулевой базой):

zremrangebyrank faveGuitarists 0 2
(integer) 3

Обратите внимание, числа, переданные remrangebyrank, также могут быть отрицательными: -1 обозначает наивысший ранг, -2 — следующий за ним и так далее.

Создание нового сортированного набора на основе существующего

Redis предоставляет две команды, которые позволяют сравнивать элементы нескольких сортированных наборов и создавать на основе этих сравнений новые наборы: это команды zinterstore и zunionstore. Чтобы поэкспериментировать с ними, мы с помощью команды zadd создадим пару тестовых сортированных наборов.

zadd NewKids 1 "Jonathan" 2 "Jordan" 3 "Joey" 4 "Donnie" 5 "Danny"
zadd Nsync 1 "Justin" 2 "Chris" 3 "Joey" 4 "Lance" 5 "JC"

Команда zinterstore находит общие элементы между двумя или более сортированными наборами (их пересечение) и создает новый сортированный набор, содержащий только эти элементы. Эта команда принимает имя целевого ключа (в котором будут сохранены общие элементы в виде отсортированного набора), количество ключей и имена ключей, которые вы хотите проанализировать:

zinterstore BoyBands 2 NewKids Nsync

Команда zinterstore вернет целое число, которое отражает количество элементов, сохраненных в целевом наборе. Поскольку наборы NewKids и Nsync имеют только один общий элемент, «Joey», команда вернет 1:

(integer) 1

Имейте в виду, если целевой ключ уже существует, zinterstore перезапишет его содержимое.

Команда zunionstore создаст новый сортированный набор, содержащий все без исключения элементы переданных ему ключей. Эта команда использует тот же синтаксис, что и zinterstore: она принимает имя целевого ключа, количество ключей, передаваемых команде, и их имена:

zunionstore SuperGroup 2 NewKids Nsync

Как и zinterstore, zunionstore вернет целое число, показывающее количество элементов, сохраненных в целевом ключе. Несмотря на то, что оба исходных сортированных набора содержали пять членов, в целевом ключе будет 9 элементов: элементы в наборах не могут повторяться, а элемент «Joey» встречается в каждом ключе.

(integer) 9

Как и zinterstore, zunionstore перезапишет содержимое целевого ключа, если он уже существует.

Чтобы получить больший контроль над оценками элементов при создании новых сортированных наборов с помощью команд zinterstore и zunionstore, вы можете использовать параметры WEIGHTS и AGGREGATE.

За параметром WEIGHTS следует одно значение для каждого сортированного набора, включенного в команду — на это число умножаются оценки всех элементов. Первое число после опции WEIGHTS умножает оценку первого ключа, переданного команде, второе число умножает оценку второго ключа и так далее.

В следующем примере создается новый сортированный набор, содержащий общие элементы наборов NewKids и Nsync. Команда также увеличит оценки в ключе NewKids в три раза, а в Nsync — в семь раз:

zinterstore BoyBandsWeighted 2 NewKids Nsync WEIGHTS 3 7

Если опция WEIGHTS не включена, по умолчанию команды zinterstore и zunionstore применяют значение 1.

AGGREGATE принимает три подопции. Первая, SUM, реализует поведение zinterstore и zunionstore по умолчанию, складывая оценки совпадающих элементов.

Если вы выполняете операцию zinterstore или zunionstore на двух сортированных наборах, в которых есть один общий элемент, но у него разные оценки в каждом наборе, с помощью опции MIN в новом наборе вы можете присвоить ему наименьшую из двух оценок.

zinterstore BoyBandsWeightedMin 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MIN

В обоих сортированных наборах есть один совпадающий элемент, его оценки в наборах одинаковы (3), но значения WEIGHTS разные. Потому в новом наборе элемент будет иметь оценку 9:

zscore BoyBandsWeightedMin "Joey"
"9"

Аналогично, AGGREGATE в командах zinterstore или zunionstore может присвоить элементу наивысшую оценку из двух — для этого нужна опция MAX:

zinterstore BoyBandsWeightedMax 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MAX

Эта команда создает новый набор с одним элементом «Joey», который имеет большую оценку (из двух умноженных значений):

zscore BoyBandsWeightedMax "Joey"
"21"

WEIGHTS можно воспринимать как способ временно изменить оценки элементов до того, как они будут проанализированы. Аналогичным образом, AGGREGATE можно рассматривать как способ контроля оценок элементов, прежде чем они будут добавлены в новые наборы.

Заключение

В этом мануале мы подробно рассмотрели ряд команд для создания и управления сортированными наборами в Redis.

Tags: , , ,

Добавить комментарий