Как получить элементы набора Redis, которые НЕ соответствуют глобальному ключу? - PullRequest
0 голосов
/ 22 февраля 2020

Как получить все ключи, которые НЕ имеют соответствующего глобального ха sh?

Я храню свои основные данные в хешах с уникальными ключами, например:

person_1: name: Anna, gender: female
person_2: name: Mark, gender: male
person_3: name: Pat, gender: female
person_4: name: Jo, gender: female
person_5: name: Robert, gender: male

Давайте скажем, я поддерживаю индекс всех лиц мужского пола в виде SET, например, так:

male_persons: 2, 5, 6

Как вы можете видеть, я пробрался в "ошибку", так как не было person_6. Делая сортировку, я могу легко создать «реляционный запрос», который дает мне всех мужчин:

SORT "male_persons" BY nosort GET # GET "person_*->name"

Ожидаемый результат примерно такой:

"2", "Mark",
"5", "Robert",
"6", nil

Мой вопрос, как можно Я получаю в 1 или 2 запроса только ключи SET, у которых НЕТ соответствующего человека, то есть как мне создать только эту строку в приведенном выше примере:

"6", nil

или даже лучше:

"6"

или:

person_6

В SQL это будет примерно так:

SELECT id FROM male_person_index WHERE male_person_index.id NOT IN (SELECT person.id FROM person);

Я знаю, что один из способов сделать это - написать скрипт Lua , но это кажется настолько основополагающим c, что должно быть возможно сделать это в 1 или 2 стандартных запросах, и я просто пропускаю это. В этом конкретном случае производительность не является супер существенной, поэтому достаточно 1, 2 или даже 3 стандартных запросов, выполняемых один за другим.

Обновление: я написал решение в виде Lua сценария, но как как было сказано ранее, я не доволен этим:

eval 'local out = {}; local i = 1; local exists; for _, key in ipairs(redis.call("SMEMBERS", KEYS[1])) do exists = redis.call("EXISTS", "persons_" .. key); if exists == 0 then out[i] = key .. " -> " .. exists; i = i + 1; end; end; return out;' 1 "male_persons"

Причина, по которой я недоволен, заключается в том, что это "зацикливается" и медленно и вызывает EXISTS потенциально тысячи или миллионы раз. Я все еще считаю, что это должно быть сделано в 2 или 3 транзакциях, а не с тысячами или миллионами.

Элегантное решение будет принимать выходной массив команды SORT, STORE it, а затем каким-то образом вычитать из этого результата другой массив результатов запроса, в один sw oop, чтобы уменьшить конечный результат по ключам, которые НЕ осиротели, давая мне, в конце концов, только сиротские ключи.

Возможно ли это?

1 Ответ

1 голос
/ 22 февраля 2020

Вы можете попробовать действительно очень хитрый способ:

Solutoin

  1. Используйте решение для сортировки и сохраните результат в списке: list1 .

    SORT "male_persons" BY nosort GET # GET "person_*->name" store list1
    
  2. Сортировка male_persons по person _ * -> name в лексикографическом порядке (то есть ALPHA option) и сохраните результат в виде списка: list2 :

    SORT "male_persons" BY person_*->name ALPHA GET # GET "person_*->name" store list2
    
  3. Удалите все пустые строки в list1 и получите количество удаленных элементов: num :

    num = LREM list1 0 ""
    
  4. Получить первые num * 2 элементов из list2 :

    LRANGE list2 0 (num * 2 - 1)
    

Объясните:

  1. С данными, отсортированными в лексикографическом порядке, то есть шаг 2, мы можем гарантировать, что несуществующие члены в начале списка результатов, то есть list2 , а соответствующее значение - пустая строка:
127.0.0.1:6379> lrange list2 0 -1
1) "6"
2) ""
3) "2"
4) "Mark"
5) "5"
6) "Robert"
Мы можем удалить все пустые строки из list1 , т. Е. Шаг 1 и шаг 3, чтобы мы могли получить число членов, которых не существует, в ha sh.

ПРИМЕЧАНИЕ : мы НЕ сортируем на шаге 1 для экономии затрат.

127.0.0.1:6379> lrem list1 0 ""
(integer) 1
Тогда первые num * 2 элементов в list2 являются результатом, то есть шаг 4:
127.0.0.1:6379> lrange list2 0 1
1) "6"
2) ""
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...