2012-01-17 17 views
11

Ho una lista redis che ho creato, la sto usando come una coda al momento che si inverte una volta ogni tanto. Il mio problema è che mi piacerebbe essere in grado di ottenere l'indice di un articolo su quella coda/lista per valore.Ottieni l'indice di un elemento in base al valore in un elenco redis

Esempio

Se ho una lista con i seguenti valori:

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

Gli indici sarebbero:

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

Voglio essere in grado passando nel valore per ottenere l'indice di quel valore sulla mia lista.

Come "eduardo" e tornare '1'.

È possibile, se sì, come lo faresti?

Anche una cosa che dovrei dire è che sto eseguendo i comandi in coda alla mia lista, rimuovendo gli elementi dall'alto e aggiungendoli in fondo.

Attualmente sto usando node.js 0.6.6 e l'ultimo modulo redis con l'ultima versione redis 2.4.4.

Sono felice per una soluzione solo in redis-cli.

Inoltre non vi è alcun vincolo a parte, quindi deve essere possibile eseguirlo con solo redis, nessun processo esterno ecc. Tuttavia se si desidera utilizzare il comando EVAL con lua go for it.

Modifica

Inoltre penso che la mia risposta potrebbe essere sul set non ordinati code.

risposta

8

Non conosco i dettagli del client nodejs per questo, ma quanto segue è un'implementazione di un comando indexOf molto semplice in lua.

In un mio file indexof.lua Ho il codice seguente:

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 

Lets spingere alcuni valori ad un mylist.

> rpush mylist foo bar baz qux 
(integer) 4 

Possiamo usare lo script lua per trovare l'indice di qualsiasi valore all'interno dell'elenco. Il comando è O (N).

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

indice bar era 1

> lindex mylist 1 
"bar" 

indice nil è -1

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

sguardo al http://redis.io/commands/eval, ulteriore documentazione su comando eval.

+2

Questo è un esempio interessante dell'uso di Lua. Tuttavia, il costo è una copia completa della lista, più una ricerca lineare in Lua. Può essere applicato solo su piccoli elenchi. Per elenchi di grandi dimensioni, blocca il loop di Redis per diversi secondi e consuma troppa memoria. –

+1

Dipende dall'applicazione se la soluzione fornita in questa risposta è una buona scelta. Dato dalla descrizione della domanda non ci sono indicazioni su quanto sia grande o piccola la coda. Per avere un sovraccarico di memoria inferiore, è necessario utilizzare un algoritmo di ricerca diverso e per fare ciò è necessario ordinare l'elenco in base al valore. Inoltre, penso che l'uso di zrank e set ordinati suona come una soluzione migliore se si tratta di un'operazione eseguita su un ampio elenco di elementi. –

+0

La coda può contenere fino a 10000 elementi. e cambia le voci che vengono rimosse dalla coda e accodate ogni 200 millisecondi. – dmportella

1

Utilizzando set ordinati (ZADD, ecc.) È possibile utilizzare ZRANK.

Modifica: La mia vecchia risposta di seguito non funziona, perché la lista cambia, anche se lo fa, con una lista che cresce solo usando RPUSH.

Si potrebbe archiviare l'indice con il valore (o il suo hash) come una chiave:

set listvalue listindex 

Al fine di mantenere i Redis organizzati, si potrebbe precedere quelle chiavi con il listname:

set listname:listvalue listindex 
+0

Non sono sicuro di cosa intendi, potresti fornire un esempio? – dmportella

+0

Penso che usare set ordinati funzionerebbe, ma avrei bisogno di aggiornare index.score per tutti ad ogni modifica alla tabella se volevo mantenere i numeri corretti. – dmportella

+0

ZRANK restituisce il rango (cioè l'indice) della chiave nel set ordinato. – mtsr

7

Utilizzare set ordinati per implementare una coda.

Aggiungere membri e utilizzare la data/ora come punteggio.

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

È possibile tornare membri in FIFO e l'ordine LIFO con l'uso di ZRANGE e ZREVRANGE rispettivamente.

FIFO:

> ZRANGE queue 0 0 
"foo" 

LIFO:

> ZREVRANGE queue 0 0 
"qux" 

Per trovare l'indice di un membro di utilizzare ZRANK. ZRANK op è O (log (N))

> ZRANK queue bar 
(integer) 1 
+0

se sposto oggetti sul set, i punteggi si aggiornano da soli? cioè se tutti i punteggi sono da 1 a 100, se cambio il primo oggetto sul set a 101 il punteggio per l'altro non cambierà? – dmportella

+0

Non sono sicuro di aver capito la domanda. Se cambi il punteggio di un membro nel set ordinato, anche il suo grado (indice) potrebbe cambiare. Il rango di un dato membro dipende dal punteggio di tutti gli altri membri nel set ordinato. Quindi, perché ZRANK è O (log (N)). Non sono sicuro che questo risponda alla tua domanda, ma puoi semplicemente giocare con i set ordinati in redis-cli e probabilmente troverai le risposte che stai cercando. Revisione –

+0

Penso che la maggior parte di essa sia stata ordinata gestendo i punteggi su un set ordinato, che si comporta come una coda che gli elementi vengono spostati dall'alto verso il basso e potrebbero invertire ad es. gli oggetti dal basso verso l'alto sarebbero un sovraccarico poiché gli articoli si muovono ogni 250 millisecondi. Non fraintendermi, la tua risposta è buona, ma non riesco a prendere il controllo della gestione. – dmportella

4

Come per ogni biglietto 140 nella lista delle questioni di redis.io

Caratteristica Richiesta: lRank

"Ciao, questo comando probabilmente non sarà implementato in quanto è un comando O (N) e uno che di solito viene sentito come necessario solo quando c'è qualche errore nella progettazione del layout dei dati. " di Salvatore Sanfilippo su https://github.com/antirez/redis/issues/140.

Non sono del tutto sicuro perché e in che modo voler scoprire l'indice di un elemento in base al valore potrebbe essere un errore nella progettazione dei dati. Tuttavia chiarisce che puoi usare il codice lua e/o i set ordinati.

Quindi il colpo su di esso è che non c'è modo per scoprire l'indice di un elemento in un elenco a parte poi utilizzando uno script lua.

Tuttavia, a seconda dell'implementazione, ad esempio la progettazione dei dati, potrebbe essere preferibile considerare set ordinati anziché elenchi.

5

Come puoi già dire, i Redis non supportano tale operazione (faccia triste).

Anche se qualcuno ha fatto qualcosa di bello remarks on why such operation would make sense, sembra che Salvatore non l'abbia implementato in tempi brevi.

Ci sono fondamentalmente due soluzioni (come sottolineato da altre risposte):

  • uso uno script lua personalizzata per trovare l'indice nella lista;
  • Utilizzare un set ordinato (anziché un elenco) con un timestamp come punteggio e ZRANK per l'indice.

Dal momento che il primo è O(N) e il secondo solo O(log(N)) probabilmente si può dire che uno supera l'altro.

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

Yup, che è incredibile cifra di 41 secondi per appena diecimila elementi.

* Su Windows 7, Redis 2.8 (MSOpenTech port), .NET 4 con ottimizzazioni del compilatore attivate e StackExchange.Redis 1.0.488.

+0

grazie per la ver informazioni utile – dmportella

Problemi correlati