Индексирование с использованием отсортированных наборов Redis

Я хотел бы получить отзывы и предложения относительно двух подходов, которые я рассматриваю для реализации поисковых индексов с использованием отсортированных наборов Redis.

Ситуация и цель

В настоящее время у нас есть несколько таблиц ключ-значение, которые мы храним в Cassandra, и для которых мы хотели бы иметь индексы. Например, одна таблица будет содержать записи о людях, а таблица Кассандры будет иметь идентификатор в качестве своего первичного ключа и сериализованный объект в качестве значения. Объект будет иметь такие поля, как first_name, last_name, last_updated и другие.

Мы хотим, чтобы мы могли выполнять поиск, такой как «last_name = 'Smith' AND first_name> 'Joel'", "last_name <'Aaronson'", "last_name = 'Smith' AND first_name = 'Winston'" и т. Д. , Поиск должен дать идентификаторы совпадений, чтобы мы могли затем извлечь объекты из Кассандры. Я думаю, что вышеупомянутые поиски могут быть выполнены с одним индексом, отсортированным лексикографически по last_name, first_name и last_updated. Если нам нужны некоторые поиски с использованием другого порядка (например, "first_name = 'Zeus'"), у нас может быть подобный индекс, который позволил бы их (например, first_name, last_updated).

Мы смотрим на использование Redis для этого, потому что мы должны иметь возможность обрабатывать большое количество записей в минуту. Я ознакомился с некоторыми распространенными способами использования отсортированных наборов Redis и предложил две возможные реализации:

Вариант 1: один отсортированный набор для каждого индекса

Для нашего индекса по last_name, first_name, last_updated мы должны иметь отсортированный набор в Redis по ключевым индексам: people: last_name: first_name: last_updated, который будет содержать строки в формате last_name: first_name: last_updated: id. Например:

кузнец: Joel: 1372761839.444: 0azbjZRHTQ6U8enBw6BJBw

(Для разделителя я мог бы использовать '::' вместо ':' или что-то еще, чтобы лучше работать с лексикографическим порядком, но давайте пока проигнорируем это)

Все элементы будут иметь оценку 0, так что отсортированный набор будет отсортирован лексикографически самими строками. Если я затем захочу сделать запрос наподобие «last_name = 'smith' И first_name <'bob'", мне нужно будет получить все элементы в списке, которые идут перед «smith: bob».

Насколько я могу судить, у этого подхода есть следующие недостатки:

Нет функции Redis для выбора диапазона на основе значения строки. Эта функция, называемая ZRANGEBYLEX, была предложена Сальваторе Санфилиппо вhttps://github.com/antirez/redis/issues/324 , но не реализовано, поэтому мне пришлось бы находить конечные точки с помощью бинарного поиска и самостоятельно получать диапазон (возможно, с использованием Lua или на уровне приложения с Python, который является языком, который мы используем для доступа к Redis).Если мы хотим включить время жизни для записей индекса, кажется, что самый простой способ сделать это - иметь регулярно запланированную задачу, которая проходит через весь индекс и удаляет элементы с истекшим сроком действия.

Вариант 2: небольшие отсортированные наборы, отсортированные по last_updated

Этот подход будет аналогичным, за исключением того, что у нас будет много меньших отсортированных наборов, каждый из которых будет иметь временное значение, например last_updated для баллов. Например, для одного и того же last_name, first_name, last_updated index у нас будет отсортированный набор для каждой комбинации last_name, first_name. Например, ключом могут быть indexes: people: last_name = smith: first_name = joel, и в нем будет запись для каждого человека, которого мы назвали Джоэл Смит. Каждая запись будет иметь в качестве имени идентификатор, а в качестве значения - значение last_updated. Например.:

значение: 0azbjZRHTQ6U8enBw6BJBw; оценка: 1372761839,444

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

Недостаток, который мне кажется очень большим:

Кажется, что гораздо сложнее управлять и искать таким образом. Например, нам нужно, чтобы индекс отслеживал все его ключи (например, в какой-то момент мы хотим очистить) и делал это иерархически. Поиск, такой как «last_name <'smith'», потребует сначала просмотреть список всех фамилий, чтобы найти те, которые идут перед кузнецом, затем для каждого из тех, кто ищет все содержащиеся в нем имена, затем для каждого из них. получить все предметы из своего отсортированного набора. Другими словами, много компонентов для создания и беспокойства.

Завершение

Так что, мне кажется, первый вариант будет лучше, несмотря на свои недостатки. Я был бы очень признателен за любые отзывы об этих двух или других возможных решениях (даже если они о том, что мы должны использовать что-то кроме Redis).

Ответы на вопрос(3)

Ваш ответ на вопрос