我使用Redis排序集来维护我的游戏排行榜。我有一种情况,我需要保持分数相同的用户的相同排名。例如
127.0.0.1:6379> zadd test-leaderboard 9 user1
(integer) 1
127.0.0.1:6379> zadd test-leaderboard 5 user2
(integer) 1
127.0.0.1:6379> zadd test-leaderboard 5 user3
(integer) 1
127.0.0.1:6379> zadd test-leaderboard 3 user4
(integer) 1
如果查询user2和user3等级,则会得到不同的结果
127.0.0.1:6379> zrank test-leaderboard user2
(integer) 1
127.0.0.1:6379> zrank test-leaderboard user3
(integer) 2
我检查了Redis文档,没有这样做的功能。因此,我想知道我必须做什么或实现此功能的最佳方法是什么。
注意:我的SET中有1万条记录,我需要在运行时维护它,而我使用的是Java语言。
排序的集首先按分数排序,然后按字典顺序排序,这就是为什么user2
和user3
的排名不同的原因。>>
您可以组合ZSCORE
,ZRANGEBYSCORE
和ZRANK
对其进行标准化。基本上,您获得user3
的分数,然后按字典顺序获得第一个用户,并获得该用户的排名。
> 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"
)维护用户列表的排行榜,也可以仅保留唯一分数来维护单独的排序集。我会选择第二个以提高效率。
添加新玩家[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
和ZREVRANK
。
使用Lua脚本
使用ZREVRANGEBYSCORE
,您可以使操作原子化并更快地执行它们。
这里举个例子。代替
ZREVRANGEBYSCORE
使用脚本:
Lua scripts用作:
> ZSCORE test-leaderboard user2
"5"
> ZRANK test-ranks 5
(integer) 1