Сортированные наборы сортируются сначала по баллам, а затем лексикографически, поэтому вы получаете различный ранг для user2
и user3
.
Вы можете комбинировать ZSCORE
, ZRANGEBYSCORE
и ZRANK
нормализовать это. По сути, вы получаете оценку за user3
, затем вводите лексикографически первого пользователя в ie и получаете ранг для этого пользователя.
> ZSCORE test-leaderboard user3
"5"
> ZRANGEBYSCORE test-leaderboard 5 5 LIMIT 0 1
1) "user2"
> ZRANK test-leaderboard user2
(integer) 1
Это дает вам ранг, а связи оценивают то же самое, но оставляя пробелы для ранжирования.
user4 => 0
user2 => 1
user3 => 1
user1 => 3
Если вы хотите, чтобы ваши ранги были без пробелов, вы можете либо сохранить таблицу лидеров со списком пользователей с заданным баллом за запись (ZADD test-leaderboard 5 "user2,user3"
), либо сохранить отдельный отсортированный набор только с уникальными баллами. Я бы go со вторым по эффективности.
Добавление нового игрока [O(log(N))]
:
ZADD test-leaderboard 5 user2
ZADD test-ranks 5 5
Удаление игрока [O(log(N))]
:
> ZSCORE test-leaderboard user2
"5"
> ZREM test-leaderboard user2
(integer) 1
> ZRANGEBYSCORE test-leaderboard 5 5 LIMIT 0 1
1) "anotherUser" or (empty list or set)
if(empty set)
> ZREM test-ranks 5
Обновить счет игрока [O(log(N))]
:
> ZSCORE test-leaderboard user2
"5"
> ZADD test-leaderboard 10 user2
(integer) 1
> ZADD test-ranks 10 10
(integer) 1
> ZRANGEBYSCORE test-leaderboard 5 5 LIMIT 0 1
1) "anotherUser" or (empty list or set)
if(empty set)
> ZREM test-ranks 5
Получить звание игрока [O(log(N))]
:
> ZSCORE test-leaderboard user2
"5"
> ZRANK test-ranks 5
(integer) 1
Пара нот:
Используйте ZREVXXX
команды, если высший балл имеет высший ранг .
ZRANK
занимает наименьшее количество баллов первым, используйте ZREVRANK
, если хотите, чтобы наивысший балл был на первом месте. См. ZREVRANK
и ZREVRANGEBYSCORE
.
Использование Lua сценариев
С Lua scripts , вы можете сделать ваши операции атомами c и выполнять их быстрее.
Вот пример. Вместо
> ZSCORE test-leaderboard user2
"5"
> ZRANK test-ranks 5
(integer) 1
Используйте скрипт:
local score = redis.call('ZSCORE', KEYS[1], ARGV[1])
return redis.call('ZRANK', KEYS[2], score)
Используйте как:
> EVAL "local score = redis.call('ZSCORE', KEYS[1], ARGV[1]) \n return redis.call('ZRANK', KEYS[2], score)" 2 test-leaderboard test-ranks user2
(integer) 1