sql >> Databasteknik >  >> NoSQL >> Redis

Hur får man samma rang för samma poäng i Redis ZRANK?

Alla verkliga lösningar måste uppfylla kraven, som liksom saknas i den ursprungliga frågan. Mitt första svar hade antagit en liten datauppsättning, men detta tillvägagångssätt skalas inte eftersom tät rangordning görs (t.ex. via Lua) i O(N) åtminstone.

Så, förutsatt att det finns många användare med poäng, är riktningen som for_stack föreslog bättre, där flera datastrukturer kombineras. Jag tror att detta är kärnan i hans sista anmärkning.

För att lagra användarnas poäng kan du använda en Hash. Även om du begreppsmässigt kan använda en enda nyckel för att lagra en Hash av alla användarpoäng, skulle du i praktiken vilja hasha Hash så att den skalas. För att hålla det här exemplet enkelt ignorerar jag Hash-skalning.

Så här lägger du till (uppdatera) en användares poäng i Lua:

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

Därefter vill vi spåra det aktuella antalet användare per diskret poängvärde så vi behåller en annan hash för det:

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)

Nu är det sista vi behöver behålla rankningen per poäng, med en sorterad uppsättning. Varje ny poäng läggs till som medlem i zset, och poäng som inte har fler användare tas bort:

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

Detta 3-delade skripts komplexitet är O(logN) på grund av användningen av den sorterade uppsättningen, men notera att N är antalet diskreta poängvärden, inte användarna i systemet. Att få en användares täta rankning görs via ett annat, kortare och enklare skript:

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. Unikt index i mongoose fungerar inte

  2. Mongoose near(...)-fråga på 2dsphere-indexerat fält ger inte giltiga resultat

  3. Pizza Tribes - Ett webbläsarbaserat realtidsstrategispel för flera spelare

  4. MongoDB-prestanda - att ha flera databaser