2012-07-29 11 views
5

consideri un Redis ordinati in set con i seguenti membri:Reverse Impaginazione attraverso un Redis Ordinati Set

ZADD mySortedSet 11 "A" 
ZADD mySortedSet 21 "B" 
ZADD mySortedSet 32 "C" 
ZADD mySortedSet 46 "D" 
ZADD mySortedSet 53 "E" 
ZADD mySortedSet 68 "F" 
ZADD mySortedSet 72 "G" 
ZADD mySortedSet 82 "H" 
ZADD mySortedSet 94 "I" 
ZADD mySortedSet 104 "J" 
ZADD mySortedSet 113 "K" 

Se voglio fare impaginazione in ordine inverso, a partire da una fetta d'arbitrario, posso iniziare con questo:

// Returns G, F, E, as expected. 
ZREVRANGEBYSCORE mySortedSet 72 (46 

Ora, sapendo solo che il mio limite superiore è 46, posso ottenere i precedenti 3 articoli nel set, D, C, B e, senza conoscere il limite inferiore facendo:

ZREVRANGEBYSCORE mySortedSet 46 -inf LIMIT 0, 3 

La mia domanda è, come posso ottenere i seguenti 3 elementi nel set, J, I e H, in questo ordine, sapendo solo che il limite superiore è 72?

// Good start, returns K, J, I, H 
ZREVRANGEBYSCORE mySortedSet +inf (72 

// Returns K, J, I, due to the offset of 0. I don't know what the correct offset is because it's from the start of the range, not the end. 
ZREVRANGEBYSCORE mySortedSet +inf (72 LIMIT 0, 3 

Quello che penso di volere è un offset negativo, che non credo sia supportato.

// Would return J, I, H, but actually returns an empty set. 
ZREVRANGEBYSCORE mySortedSet +inf (72 LIMIT -1, 3 

posso fingere con una marcia in avanti, e poi invertire le voci, ma sto cercando una soluzione nativa Redis, se ne esiste uno.

// Returns H, I, J - the items I want, but reversed. 
ZRANGEBYSCORE mySortedSet (72 +inf LIMIT 0, 3 

Qualche idea?

Per essere chiari, so che c'è ZRANGE e ZREVRANGE, ma in questo profilo di query, non conoscerò l'indice attuale, solo il punteggio.

+0

Non c'è un modo semplice per farlo. Vedo tre opzioni. (1) Reverse sul tuo client (2) reverse usando LUA (3) usa ZCOUNT per conoscere il numero di elementi e sottostrati da lì come sostituzione di indici negativi. – seppo0010

+0

Hey seppo0010, grazie per il tuo contributo. Al momento sto facendo 1, e volevo solo vedere se c'era un modo migliore. Non è un fan degli script LUA per qualcosa del genere, ma considereremo certamente l'approccio ZCOUNT, dato che la query viene eseguita all'interno di MULTI, quindi rimarrà atomica. – majelbstoat

risposta

1

È semplice ottenere il rango per un elemento e quindi lavorare per indici. Presumendo che gli unici ingressi disponibili per l'applicazione sono i limiti punteggio iniziale di 72 e 46, si può fare questo:

redis 127.0.0.1:6379> ZREVRANGEBYSCORE mySortedSet 72 (46 
1) "G" 
2) "F" 
3) "E" 
redis 127.0.0.1:6379> ZREVRANK mySortedSet G 
(integer) 4 
redis 127.0.0.1:6379> ZREVRANGE mySortedSet 1 3 
1) "J" 
2) "I" 
3) "H" 
redis 127.0.0.1:6379> 

L'unica chiamata supplementare è la O (log (N)) ZREVRANK chiamata. Da lì, è un po 'di matematica lato client per ottenere i nuovi indici per la gamma che ti interessa, e ZREVRANGE per ottenere i valori desiderati.

Ho provato questo su Redis 2.6rc5, ma dovrebbe funzionare su qualsiasi versione su 2.0.

+0

Grazie, anche questo sembra un approccio ragionevole. L'unico problema è che dovrei suddividere la richiesta in più chiamate, oppure scrivere uno script LUA per gestire il calcolo dell'intervallo intermedio. A seconda del profilo dei dati, O (log (N)) dove N, la cardinalità dell'insieme è grande, potrebbe anche essere più dispendioso in termini di tempo rispetto all'inversione di un "intervallo ordinato in avanti", che avrà M, il conteggio del ritorno. – majelbstoat

+0

Sì, a seconda delle dimensioni dei dati, afferrandoli tutti e invertendoli potrebbe essere migliore; non dimenticare però, si finisce per pagare i costi di trasferimento di rete per ciò che non si usa. Sfortunatamente, il pipelining non ti porta molto qui, dato che hai bisogno dei valori intermedi per costruire le query successive. Non sei sicuro di quali altre opzioni hai a disposizione per ridisegnare le cose a monte per fornire input diversi. –

Problemi correlati