java—如何使用redis排序集实现竞争排行榜

aydmsdu9  于 2021-06-09  发布在  Redis
关注(0)|答案(1)|浏览(643)

我使用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 sorted set的默认实现,它按字典顺序返回排名。

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文档,没有这样的功能。所以我想知道我必须做什么,或者什么是实现这个功能的最佳方式。
注意:我在集合中有10k条记录,我需要在运行时维护它,我使用的是java编程语言。

7cjasjjr

7cjasjjr1#

排序后的集合首先按分数排序,然后按字典排序,这就是为什么你会得到不同的排序 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 以及 ZREVRANGEBYSCORE .
使用lua脚本
使用lua脚本,可以使操作原子化并更快地执行。
这里有一个例子。而不是

> 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

相关问题