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

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

我使用redis排序集来维护我的游戏排行榜。我有一个场景,我需要保持相同的排名的用户谁有相同的分数作为竞争排行榜。如。

  1. | member | score | rank |
  2. | member_1 | 50 | 1 |
  3. | member_2 | 50 | 1 |
  4. | member_3 | 30 | 3 |
  5. | member_4 | 30 | 3 |
  6. | member_5 | 10 | 5 |

到目前为止,我使用redis sorted set的默认实现,它按字典顺序返回排名。

  1. 127.0.0.1:6379> zadd test-leaderboard 9 user1
  2. (integer) 1
  3. 127.0.0.1:6379> zadd test-leaderboard 5 user2
  4. (integer) 1
  5. 127.0.0.1:6379> zadd test-leaderboard 5 user3
  6. (integer) 1
  7. 127.0.0.1:6379> zadd test-leaderboard 3 user4
  8. (integer) 1

如果我查询user2和user3排名,我会得到不同的结果

  1. 127.0.0.1:6379> zrank test-leaderboard user2
  2. (integer) 1
  3. 127.0.0.1:6379> zrank test-leaderboard user3
  4. (integer) 2

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

7cjasjjr

7cjasjjr1#

排序后的集合首先按分数排序,然后按字典排序,这就是为什么你会得到不同的排序 user2 以及 user3 .
你可以合并 ZSCORE , ZRANGEBYSCORE 以及 ZRANK 使之正常化。基本上,你得到的分数 user3 ,然后按字典顺序获得第一个并列的用户,并获得该用户的排名。

  1. > ZSCORE test-leaderboard user3
  2. "5"
  3. > ZRANGEBYSCORE test-leaderboard 5 5 LIMIT 0 1
  4. 1) "user2"
  5. > ZRANK test-leaderboard user2
  6. (integer) 1

这给你一个排名,与领带排名相同,但留下差距排名。

  1. user4 => 0
  2. user2 => 1
  3. user3 => 1
  4. user1 => 3

如果你想你的排名没有差距,你可以保持排行榜与用户名单在一个给定的分数每个条目( ZADD test-leaderboard 5 "user2,user3" ),或维护仅具有唯一分数的分离排序集。为了提高效率,我会选择第二个。
添加新玩家 [O(log(N))] :

  1. ZADD test-leaderboard 5 user2
  2. ZADD test-ranks 5 5

删除玩家 [O(log(N))] :

  1. > ZSCORE test-leaderboard user2
  2. "5"
  3. > ZREM test-leaderboard user2
  4. (integer) 1
  5. > ZRANGEBYSCORE test-leaderboard 5 5 LIMIT 0 1
  6. 1) "anotherUser" or (empty list or set)
  7. if(empty set)
  8. > ZREM test-ranks 5

更新玩家分数 [O(log(N))] :

  1. > ZSCORE test-leaderboard user2
  2. "5"
  3. > ZADD test-leaderboard 10 user2
  4. (integer) 1
  5. > ZADD test-ranks 10 10
  6. (integer) 1
  7. > ZRANGEBYSCORE test-leaderboard 5 5 LIMIT 0 1
  8. 1) "anotherUser" or (empty list or set)
  9. if(empty set)
  10. > ZREM test-ranks 5

获得玩家的等级 [O(log(N))] :

  1. > ZSCORE test-leaderboard user2
  2. "5"
  3. > ZRANK test-ranks 5
  4. (integer) 1

几个注意事项:
使用 ZREVXXX 如果高分是最高级别,则发出命令。 ZRANK 将最低分数排在第一位,使用 ZREVRANK 如果你想把最高分排在第一位。看到了吗 ZREVRANK 以及 ZREVRANGEBYSCORE .
使用lua脚本
使用lua脚本,可以使操作原子化并更快地执行。
这里有一个例子。而不是

  1. > ZSCORE test-leaderboard user2
  2. "5"
  3. > ZRANK test-ranks 5
  4. (integer) 1

使用脚本:

  1. local score = redis.call('ZSCORE', KEYS[1], ARGV[1])
  2. return redis.call('ZRANK', KEYS[2], score)

用作:

  1. > EVAL "local score = redis.call('ZSCORE', KEYS[1], ARGV[1]) \n return redis.call('ZRANK', KEYS[2], score)" 2 test-leaderboard test-ranks user2
  2. (integer) 1
展开查看全部

相关问题