2012-01-17 1 views
11

У меня есть список redis, который я создал, я использую его как очередь в момент, который меняет время от времени. Моя проблема в том, что я хотел бы получить индекс элемента в этой очереди/списке по значению.Получить индекс элемента по значению в списке redis

Пример

Если у меня есть список со следующими значениями:

{"dan","eduardo","pedro"} 

Индексы будут:

0 : "dan" 
1 : "eduardo" 
2 : "pedro" 

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

Как «eduardo» и верните «1».

Возможно ли это, если да, как бы вы это сделали?

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

В настоящее время я использую node.js 0.6.6 и последний модуль redis с последней версией версии 2.4.4.

Я рад за решение только в redis-cli.

Кроме того, нет ограничений, кроме того, это должно быть возможно сделать с помощью redis в отдельности, без внешнего процесса и т. Д. Однако, если вы хотите использовать команду EVAL с lua для этого.

Редактировать

Кроме того, я думаю, что мой ответ может быть отсортированные наборы не очередей.

ответ

8

Я не знаю деталей узла nodejs для этого, но следующее представляет собой реализацию очень простой команды indexOf в lua.

В моем файле indexof.lua у меня есть следующий код:

local key = KEYS[1] 
local obj = ARGV[1] 
local items = redis.call('lrange', key, 0, -1) 
for i=1,#items do 
    if items[i] == obj then 
     return i - 1 
    end 
end 
return -1 

Позволяет нажать несколько значений в mylist.

> rpush mylist foo bar baz qux 
(integer) 4 

Мы можем использовать сценарий lua, чтобы найти индекс любого значения в списке. Команда O (N).

$ redis-cli --eval indexof.lua mylist , bar 
(integer) 1 

индекса bar был 1

> lindex mylist 1 
"bar" 

индекса nil является -1

$ redis-cli --eval indexof.lua mylist , nil 
(integer) -1 

Посмотрите на http://redis.io/commands/eval дополнительной документации по команде EVAL.

+2

Это интересный пример использования Lua. Однако стоимость - это полная копия списка, а также линейный поиск в Lua. Он может применяться только к небольшим спискам. Для больших списков он задерживает цикл Redis в течение нескольких секунд и потребляет слишком много памяти. –

+1

Это зависит от приложения, если решение, данное в этом ответе, является хорошим выбором. Учитывая описание вопроса, нет никаких указаний на то, насколько велика или мала очередь. Чтобы иметь более низкую накладную память, нам нужно использовать другой алгоритм поиска, и для этого список нужно упорядочить по значению. Кроме того, я думаю, что использование zrank и отсортированных наборов звучит как лучшее решение, если это операция, выполняемая в большом списке элементов. –

+0

Длина очереди может достигать 10000 единиц. и он изменяется, то есть элементы получают разблокировку и ставят в очередь каждые 200 миллисекунд. – dmportella

1

Используя отсортированные наборы (ZADD и т. Д.), Вы можете использовать ZRANK.

Редактировать: Мой старый ответ ниже не работает, потому что ваш список изменяется, несмотря на то, что он имеет список, который растет только с помощью RPUSH.

Вы можете хранить индекс со значением (или его хэш) в качестве ключа:

set listvalue listindex 

Для того, чтобы сохранить ваш Redis организованы, вы можете использовать префикс этих ключей с названиерассылкой:

set listname:listvalue listindex 
+0

Я не уверен, что вы имеете в виду, можете ли вы привести пример? – dmportella

+0

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

+0

ZRANK возвращает ранг (т.е. индекс) ключа в отсортированном наборе. – mtsr

7

Используйте отсортированные множества для реализации очереди.

Добавить участников и использовать временную метку в качестве оценки.

> ZADD queue 1326990501 foo 1326990502 bar 1326990503 baz 1326990504 qux 
(integer) 4 

Вы можете вернуть пользователей в FIFO и LIFO порядка с использованием ZRANGE и ZREVRANGE соответственно.

FIFO:

> ZRANGE queue 0 0 
"foo" 

LIFO:

> ZREVRANGE queue 0 0 
"qux" 

Чтобы найти индекс элемента использовать ZRANK. ZRANK оп является O (журнал (N))

> ZRANK queue bar 
(integer) 1 
+0

, если я перемещаю элементы на множестве, самим обновлением оценок? т. е. если все оценки составляют от 1 до 100, если я изменил первый элемент в наборе на 101, оценка для другого не изменится? – dmportella

+0

Я не уверен, что понимаю вопрос. Если вы измените оценку члена в отсортированном наборе, его ранг (индекс) также может измениться. Ранг любого данного члена зависит от оценки всех остальных членов сортированного набора. Следовательно, ZRANK - это O (log (N)). Я не уверен, отвечает ли это на ваш вопрос, но вы можете просто поиграть с отсортированными наборами в redis-cli, и вы, вероятно, найдете ответы, которые вы ищете. –

+0

капитальный ремонт. Я думаю, что у вас есть большая часть его сортировки, но она управляет оценками на сортированном наборе, который действует как очередь, что элементы перемещаются от верхней части к нижней и могут отменить, например. элементы из нижней части, перемещающиеся в верхнюю часть, будут обладать большими накладными расходами, так как элементы перемещаются каждые 250 миллисекунд. Не поймите меня неправильно, ваш ответ хорош, но я не могу взять на себя управление счетом. – dmportella

4

Как за билет 140 в списке вопросов redis.io

Feature Request: lRank

«Привет, эта команда будет скорее всего, не будет реализована, так как это как команда O (N), так и одна, которая обычно ощущается по мере необходимости только тогда, когда в дизайне макета данных есть некоторая ошибка ». по Salvatore Sanfilippo по телефону https://github.com/antirez/redis/issues/140.

Я не совсем уверен, почему и как получить индекс элемента по значению может быть ошибкой в ​​дизайне данных. Однако он поясняет, что вы можете использовать код lua и/или отсортированные наборы.

Так выстрел из этого является то, что нет никакого способа узнать индекс элемента в списке, то с помощью Lua скрипт.

Однако, в зависимости от реализации, т. Е. Проектирования данных, лучше рассматривать отсортированные множества вместо списков.

5

Как вы можете сказать, Redis не поддерживает такую ​​операцию (грустное лицо).

Хотя кто-то сделал довольно неплохо remarks on why such operation would make sense, похоже, что Сальваторе не будет реализовывать его в ближайшее время.

Есть в основном два способа решения (как было указано другими ответами):

  • Используйте пользовательский Lua скрипт для поиска индекса в списке;
  • Используйте отсортированный набор (вместо списка) с меткой времени и счетом ZRANK для индекса.

Поскольку первый является O(N) и последний раз O(log(N)) вы, вероятно, может сказать, какой один обгоняет другие.

Anyway I decided to put to the test *:

╔════════════════╦═══════════════════════╦══════════════════════╗ 
║    ║ Sorted Set with ZRANK ║ List with lua script ║ 
╠════════════════╬═══════════════════════╬══════════════════════╣ 
║ 1000 elements ║ 0.0638264 seconds ║ 0.2723238 seconds ║ 
╠════════════════╬═══════════════════════╬══════════════════════╣ 
║ 10000 elements ║ 00.4484714 seconds ║ 41.0661683 seconds ║ 
╚════════════════╩═══════════════════════╩══════════════════════╝ 

Да, это ошеломляющие 41 секунд всего за десять тысяч элементов.

* В Windows 7, Redis 2.8 (MSOpenTech port), .NET 4 с включенной оптимизацией компилятора и StackExchange.Redis 1.0.488.

+0

Благодарим вас за информацию – dmportella

Смежные вопросы