2016-06-30 35 views
5

Attualmente memorizzo circa 50k hash nella mia tabella Redis, ognuno ha 5 coppie chiave/valore. Una volta al giorno eseguo un processo batch che aggiorna i valori hash, inclusa l'impostazione di alcuni valori chiave sul valore dell'altra chiave in un hash.Redis: il modo migliore per ottenere tutti i valori hash

Ecco il mio codice python che scorre chiavi e set old_code per new_code se il valore new_code esiste per un hash dare:

pipe = r.pipeline() 

for availability in availabilities: 
    pipe.hget(availability["EventId"], "new_code") 

for availability, old_code in zip(availabilities, pipe.execute()): 
    if old_code: 
     availability["old_code"] = old_code.decode("utf-8") 

for availability in availabilities: 
    if "old_code" in availability: 
     pipe.hset(
      availability["EventId"], "old_code", availability["old_code"]) 
    pipe.hset(availability["EventId"], "new_code", availability["MsgCode"]) 
pipe.execute() 

E 'un po' strano per me che devo scorrere le chiavi due volte per ottenere lo stesso risultato, c'è un modo migliore per farlo?

Un'altra cosa che sto cercando di capire è come ottenere tutti i valori hash con le migliori prestazioni. Ecco come ho attualmente faccio:

d = [] 
pipe = r.pipeline() 
keys = r.keys('*') 
for key in keys: 
    pipe.hgetall(key) 
for val, key in zip(pipe.execute(), keys): 
    e = {"event_id": key} 
    e.update(val) 
    if "old_key" not in e: 
     e["old_key"] = None 
    d.append(e) 

Quindi, in pratica io keys * poi iterare con HGETALL in tutte le chiavi per ottenere i valori. Questo è troppo lento, specialmente l'iterazione. C'è un modo più veloce per farlo?

+0

Puoi spiegare un po 'di più sulla prima parte della domanda, Cosa devi fare, senza usare alcun linguaggio di programmazione. – Malinga

+1

http://stackoverflow.com/questions/38065714/is-there-a-command-in-redis-for-hash-data-structure-similar-to-mget/38066688#38066688 controlla la mia risposta qui – Malinga

+0

Per ogni hash/row Raccolgo il codice corrente e lo memorizzo come new_code, salvando il new_code corrente come old_code (per registrare lo stato precedente e confrontare old_code e new_code su ogni estrazione di dati). –

risposta

5

Che ne dite di un cambiamento inaspettato. Trasponi il modo in cui memorizzi i dati.

Invece di avere 50k hash ognuno con 5 valori. Hanno 5 hash ognuno con 50k valori.

Per esempio il vostro hash dipende eventid e memorizzare new_code, old_code e altri animali all'interno che hash

Ora, per new_code avere una mappa di hash che conterrà eventid come membro e il suo valore come valore. Quindi new_code da solo è una mappa hash contenente una coppia di valori membro 50k.

Quindi il ciclo di 5 anziché 50k sarà relativamente più veloce.

ho fatto un piccolo esperimento e in seguito sono i numeri

50k hashes * 5 elements 
Memory : ~12.5 MB 
Time to complete loop through of elements : ~1.8 seconds 

5 hashes * 50k elements 
Memory : ~35 MB 
Time to complete loop through of elements : ~0.3 seconds. 

ho testato con le stringhe semplici come KEY_i e VALUE_i (dove i è l'incrementatore) in modo memoria può aumentare nel tuo caso. E anche io ho appena attraversato i dati, non ho fatto nessuna manipolazione quindi anche il tempo cambierà nel tuo caso.

Come si può vedere questo cambiamento può dare 5x prestazioni amplificare, e 2 volte più memoria.

Redis esegue la compressione per gli hash in un intervallo (512 - impostazione predefinita). Dato che stiamo archiviando più di quell'intervallo (50k) abbiamo questo picco in memoria.

Fondamentalmente è un compromesso e spetta a te scegliere il migliore che si adatti alla tua applicazione.

Per la vostra prima domanda:

  1. si stanno ottenendo valori di new_code in ogni hash, ora avete tutto in un unico hash -> solo una singola chiamata.
  2. Quindi si aggiornano old_code e new_code uno per uno. Ora puoi eseguirli usando hmset usando una singola chiamata.

Spero che questo aiuti.

0

Non esiste alcun comando simile, gli hash redis funzionano all'interno dell'hash, quindi HMGET funziona all'interno di un hash e fornisce tutti i campi in tale hash. Non è possibile accedere a tutti i campi in più hash a quelli.

ci sono 2 opzioni

  1. Uso gasdotto
  2. Uso LUA

Tuttavia entrambi di questo sono soluzioni alternative, non è una soluzione al vostro problema. Per sapere come fare questo controllo La mia risposta in questa domanda: Is there a command in Redis for HASH data structure similar to MGET?

2

Per il tuo primo problema, l'utilizzo di uno script Lua sicuramente migliorerà le prestazioni. Questo non è stato verificato, ma qualcosa di simile:

update_hash = r.register_script(""" 
    local key = KEYS[1] 
    local new_code = ARGS[1] 

    local old_code = redis.call("HGET", key, "new_code") 
    if old_code then 
     redis.call("HMSET", key, "old_code", old_code, "new_code", new_code) 
    else 
     redis.call("HSET", key, "new_code", new_code) 
    end 
""") 

# You can use transaction=False here if you don't need all the 
# hashes to be updated together as one atomic unit. 
pipe = r.pipeline() 

for availability in availabilities: 
    keys = [availability["EventId"]] 
    args = [availability["MsgCode"]] 

    update_hash(keys=keys, args=args, client=pipe) 

pipe.execute() 

Per il tuo secondo problema, potresti ancora una volta rendere più veloce la scrittura di un breve script Lua. Invece di ottenere tutte le chiavi e restituirle al client, lo script otterrebbe le chiavi e i dati associati e restituirle in un'unica chiamata.

(Nota, però, che chiamando keys() è intrinsecamente lento, ovunque lo si fa. E si noti che in entrambi gli approcci si sta essenzialmente tirando l'intero set di dati Redis in memoria locale, che potrebbe o non potrebbe diventare un problema.)

Problemi correlati