Redis
 sql >> Baza danych >  >> NoSQL >> Redis

Jak uzyskać tę samą rangę za te same wyniki w ZRANK Redis?

Każde prawdziwe rozwiązanie musi odpowiadać wymaganiom, których brakuje w pierwotnym pytaniu. Moja pierwsza odpowiedź zakładała mały zestaw danych, ale to podejście nie skaluje się, ponieważ robi się gęsty ranking (np. przez Lua) przynajmniej w O(N).

Tak więc, zakładając, że jest wielu użytkowników z wynikami, lepszy jest kierunek sugerowany przez for_stack, w którym łączy się wiele struktur danych. Wierzę, że to jest sedno jego ostatniej uwagi.

Do przechowywania wyników użytkowników możesz użyć skrótu. Chociaż koncepcyjnie można użyć jednego klucza do przechowywania wartości skrótu wszystkich użytkowników, w praktyce warto haszować, aby był on skalowany. Aby ten przykład był prosty, zignoruję skalowanie skrótu.

W ten sposób możesz dodać (zaktualizować) wynik użytkownika w Lua:

local hscores_key = KEYS[1]
local user = ARGV[1]
local increment = ARGV[2]
local new_score = redis.call('HINCRBY', hscores_key, user, increment)

Następnie chcemy śledzić bieżącą liczbę użytkowników na dyskretną wartość wyniku, więc przechowujemy w tym celu kolejny skrót:

local old_score = new_score - increment
local hcounts_key = KEYS[2]
local old_count = redis.call('HINCRBY', hcounts_key, old_score, -1)
local new_count = redis.call('HINCRBY', hcounts_key, new_score, 1)

Teraz ostatnią rzeczą, którą musimy utrzymywać, jest ranking na wynik, z posortowanym zestawem. Każda nowa partytura jest dodawana jako członek zset, a partytury, które nie mają więcej użytkowników, są usuwane:

local zdranks_key = KEYS[3]
if new_count == 1 then
  redis.call('ZADD', zdranks_key, new_score, new_score)
end
if old_count == 0 then
  redis.call('ZREM', zdranks_key, old_score)
end

Złożoność tego 3-częściowego skryptu wynosi O(logN) ze względu na użycie posortowanego zbioru, ale zauważ, że N to liczba dyskretnych wartości punktacji, a nie użytkowników w systemie. Uzyskiwanie gęstego rankingu użytkownika odbywa się za pomocą innego, krótszego i prostszego skryptu:

local hscores_key = KEYS[1]
local zdranks_key = KEYS[2]
local user = ARGV[1]

local score = redis.call('HGET', hscores_key, user)
return redis.call('ZRANK', zdranks_key, score)


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Redis to pojedynczy wątek. Dlaczego więc powinienem używać sałaty?

  2. jak skonfigurować limit czasu działania bazy JedisConnectionFactory na frameworku Spring Boot

  3. Nie można załadować pliku lub zestawu System.Runtime.CompilerServices.Unsafe

  4. Redis — najlepszy sposób na przechowywanie dużej mapy (słownik)

  5. Dlaczego mój skrypt Redis Lua nie może atomowo aktualizować kluczy w różnych węzłach klastra Redis?