【问题标题】:How to implement Competition leaderboard using redis sorted set如何使用redis排序集实现竞赛排行榜
【发布时间】:2020-02-24 15:07:30
【问题描述】:

我正在使用 Redis 排序集来维护我的游戏排行榜。我有一个场景,我需要保持与竞赛排行榜得分相同的用户的相同排名。例如。

| member | score | rank |
— — — — — — — — — — —
| member_1 | 50 | 1 |
| member_2 | 50 | 1 |
| member_3 | 30 | 3 |
| member_4 | 30 | 3 |
| member_5 | 10 | 5 |

到目前为止,我正在使用 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 中有 10K 条记录,我需要在运行时对其进行维护,并且我使用的是 Java 编程语言。

【问题讨论】:

标签: java redis leaderboard sortedset


【解决方案1】:

排序后的集合首先按分数排序,然后按字典顺序排序,这就是user2user3 排名不同的原因。

您可以结合ZSCOREZRANGEBYSCOREZRANK 来规范化它。基本上,您获得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。见ZREVRANKZREVRANGEBYSCORE

使用 Lua 脚本

使用Lua scripts,您可以使您的操作原子化并更快地执行它们。

这里是一个例子。而不是

> 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-23
    • 1970-01-01
    • 2013-10-14
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多