簡體   English   中英

如何使用 redis 排序集實現競賽排行榜

[英]How to implement Competition leaderboard using redis sorted set

我正在使用 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 編程語言。

已排序的集合首先按分數排序,然后按字典順序排序,這就是為什么您會為user2user3獲得不同的排名。

您可以組合ZSCOREZRANGEBYSCOREZRANK來規范化它。 基本上,您獲得user3的分數,然后按字典順序獲得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 腳本,您可以使操作原子化並更快地執行它們。

這里有一個例子。 代替

> 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM