2012-01-17 24 views
11

Tengo una lista de redis que he creado, la estoy usando como una cola en el momento que se invierte de vez en cuando. Mi problema es que me gustaría poder obtener el índice de un elemento en esa cola/lista por valor.Obtener el índice de un artículo por valor en una lista redis

Ejemplo

Si tengo una lista con los siguientes valores:

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

Los índices serían:

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

quieren ser capaces mediante el paso en el valor para obtener el índice de ese valor en mi lista.

Me gusta "eduardo" y get back '1'.

¿Es posible si es así cómo lo haría?

También algo que debo decir es que estoy ejecutando comandos de cola en mi lista, eliminando elementos de la parte superior y agregándolos en la parte inferior.

Actualmente estoy usando node.js 0.6.6 y el último módulo de redis con la última versión de redis 2.4.4.

Estoy contento por la solución solo en redis-cli.

Además, no hay ninguna otra restricción, entonces debe ser posible hacerlo con redis solo, sin proceso externo, etc. Sin embargo, si desea utilizar el comando EVAL con lua, haga clic en él.

Editar

También creo que mi respuesta podría estar en conjuntos ordenados no pone en cola.

Respuesta

8

No conozco los detalles del cliente nodejs para esto, pero la siguiente es una implementación de un comando indexOf muy simple en lua.

En un archivo de mi indexof.lua tengo el siguiente código:

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 

Permite empujar unos valores a un mylist.

> rpush mylist foo bar baz qux 
(integer) 4 

Podemos usar la secuencia de comandos lua para encontrar el índice de cualquier valor dentro de la lista. El comando es O (N).

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

índice de bar era 1

> lindex mylist 1 
"bar" 

índice de nil es -1

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

Mira la http://redis.io/commands/eval documentación adicional sobre comando EVAL.

+2

Este es un ejemplo interesante del uso de Lua. Sin embargo, el costo es una copia completa de la lista, más una búsqueda lineal en Lua. Solo se puede aplicar en listas pequeñas. Para listas grandes, congelará el ciclo Redis durante varios segundos y consumirá demasiada memoria. –

+1

Depende de la aplicación si la solución dada en esta respuesta es una buena opción. Dada la descripción de la pregunta, no hay indicios de cuán grande o pequeña es la cola. Para tener una sobrecarga de memoria menor, necesitamos usar un algoritmo de búsqueda diferente, y para hacer eso, la lista debe ordenarse por valor. Además, creo que usar conjuntos discontinuos y ordenados suena como una mejor solución si se trata de una operación realizada en una gran lista de elementos. –

+0

La cola puede tener hasta 10000 elementos. y cambia, es decir, los artículos se quitan de la cola y se enrutan cada 200 milisegundos. – dmportella

1

Usando conjuntos ordenados (ZADD, etc.) puede usar ZRANK.

Editar: Mi respuesta anterior a continuación no funciona, porque su lista cambia, aunque lo hace, con una lista que solo crece utilizando RPUSH.

Se puede almacenar el índice con el valor (o su hash) como clave:

set listvalue listindex 

Con el fin de mantener sus Redis organizados, se puede prefijar las teclas con el nombre de la lista:

set listname:listvalue listindex 
+0

No estoy seguro de lo que quiere decir ¿podría dar un ejemplo? – dmportella

+0

Creo que usar conjuntos ordenados funcionaría, pero necesitaría actualizar la puntuación del índice para todos en cada cambio en la tabla si quería mantener los números correctos. – dmportella

+0

ZRANK devuelve el rango (es decir, índice) de la clave en el conjunto ordenado. – mtsr

7

Usa conjuntos ordenados para implementar una cola.

Agregar miembros y usar la marca de tiempo como puntaje.

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

Puede volver miembros en FIFO y LIFO fin por el uso de ZRANGE y ZREVRANGE respectivamente.

FIFO:

> ZRANGE queue 0 0 
"foo" 

LIFO:

> ZREVRANGE queue 0 0 
"qux" 

Para hallar el índice de un miembro de utilizar ZRANK. ZRANK op es O (log (n))

> ZRANK queue bar 
(integer) 1 
+0

si muevo elementos en el conjunto, para que se actualicen los puntajes? es decir, si todos los puntajes son de 1 a 100, si cambio el primer elemento en el conjunto a 101, ¿el puntaje del otro no cambiará? – dmportella

+0

No estoy seguro de entender la pregunta. Si cambia la puntuación de un miembro en el conjunto ordenado, su rango (índice) también podría cambiar. El rango de cualquier miembro depende del puntaje de todos los demás miembros en el conjunto ordenado. Por lo tanto, por qué el ZRANK es O (log (N)). No estoy seguro de que esto responda a su pregunta, pero puede simplemente jugar con conjuntos ordenados en redis-cli y probablemente encontrará las respuestas que está buscando. –

+0

overhaul Creo que tiene la mayoría ordenada, sin embargo, administra los puntajes en un conjunto ordenado, que actúa como una cola que los elementos se mueven de arriba hacia abajo y pueden revertir, por ejemplo. los elementos de la parte inferior que se desplazan hacia la parte superior implican una gran sobrecarga, ya que los elementos se mueven cada 250 milisegundos. No me malinterprete su respuesta es buena, pero no puedo tomar la gestión de puntaje por encima. – dmportella

4

Como por entrada 140 en la lista de temas de redis.io

función de solicitud: lRank

"Hola, este comando probablemente no se implemente, ya que es a la vez un comando O (N) y uno que normalmente se considera necesario solo cuando hay algún error en el diseño del diseño de datos ". por Salvatore Sanfilippo en https://github.com/antirez/redis/issues/140.

No estoy muy seguro de por qué y cómo querer averiguar el índice de un artículo por valor podría ser un error en el diseño de datos. Sin embargo, deja en claro que puedes usar el código lua y/o los conjuntos ordenados.

Así que el tiro de él es que no hay manera para averiguar el índice de un elemento de una lista a continuación, otra utilizando un script lua.

Sin embargo, dependiendo de la implementación, es decir, del diseño de datos, puede ser mejor considerar conjuntos ordenados en lugar de listas.

5

Como puede ver por ahora, Redis no es compatible con tal operación (cara triste).

Aunque alguien hizo algo muy bueno remarks on why such operation would make sense, parece que Salvatore no lo implementará pronto.

Hay básicamente dos soluciones (como se ha señalado por las otras respuestas):

  • utilizar un script lua personalizada para encontrar el índice de la lista;
  • Utilice un conjunto ordenado (en lugar de una lista) con una marca de tiempo como puntaje y ZRANK para el índice.

Desde la primera es O(N) y el segundo simplemente O(log(N)) es probable que pueda decir que uno supera al otro.

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 ║ 
╚════════════════╩═══════════════════════╩══════════════════════╝ 

Sí, eso es asombrosa cifra de 41 segundos por sólo diez mil elementos.

* En Windows 7, Redis 2.8 (MSOpenTech port), .NET 4 con optimizaciones del compilador activadas y StackExchange.Redis 1.0.488.

+0

gracias por la información que ha sido útil – dmportella

Cuestiones relacionadas