Redis sorted set leader board ranking on same score
Asked Answered
M

2

15

I'm using Redis sorted set to implement the leaderboard of my game, where I show the user ranking in descending order. I'm stuck in a case where two or more users have the same score. So in this case, I want the higher ranking of the user who gets the score first. For example, I'm adding the following entries in Redis.

127.0.0.1:6379> zadd testing-key 5 a
(integer) 1
127.0.0.1:6379> zadd testing-key 4 b
(integer) 1
127.0.0.1:6379> zadd testing-key 5 c
(integer) 1

and when I'm querying for the rank in reverse order, I'm getting this

127.0.0.1:6379> zrevrange testing-key 0 10
1) "c"
2) "a"
3) "b"

but in my case, the ranking should be like

1) "a"
2) "c"
3) "b"

So is there any provision in Redis to give higher precedence to the entity which entered first in the set with the same score?

Metacarpal answered 5/10, 2018 at 6:9 Comment(0)
M
12

I found one solution to this problem. In my case, the score is an integer so I converted it into decimal and added Long.MAX_VALUE - System.nanoTime() after decimal. So the final score code will be like

double finalScore = score.(Long.MAX_VALUE - System.nanoTime());

So the final score of the player who scored first would be higher than the second one. Please let me know if you have any better solution.

Metacarpal answered 29/10, 2018 at 5:38 Comment(2)
But isn't that what I (perhaps tersely and succinctly, but hopefully not inaccurately and certainly with only the of best intentions intended) answered in my first paragraph?Ileus
Only appending timestamp with score will not produce the desired result if we call zrevrange(In my case). Because timestamp field should be descending order to give high ranking to the user who scored first, so the final score should be mainScore.(Some max value - System.nanoTime())Metacarpal
I
13

If your leaderboard's scores are "small" enough, you may get away with using a combination of the score and the timestamp (e.g. 123.111455234, where 123 is the score). However, since the Sorted Set score is a double floating point, you may lose precision.

Alternatively, keep two Sorted Sets - one with each player's leaderboard score and the other with each player's score timestamp, and use both to determine the order.

Or, use a single sorted set for the leader board, encode the timestamp as part of the member and rely on lexicographical ordering.

Ileus answered 5/10, 2018 at 10:21 Comment(1)
Can you advice the optimal way to do increments of scores and update of timestamps in its decimal part? Thank you for valuable answers.Sporogenesis
M
12

I found one solution to this problem. In my case, the score is an integer so I converted it into decimal and added Long.MAX_VALUE - System.nanoTime() after decimal. So the final score code will be like

double finalScore = score.(Long.MAX_VALUE - System.nanoTime());

So the final score of the player who scored first would be higher than the second one. Please let me know if you have any better solution.

Metacarpal answered 29/10, 2018 at 5:38 Comment(2)
But isn't that what I (perhaps tersely and succinctly, but hopefully not inaccurately and certainly with only the of best intentions intended) answered in my first paragraph?Ileus
Only appending timestamp with score will not produce the desired result if we call zrevrange(In my case). Because timestamp field should be descending order to give high ranking to the user who scored first, so the final score should be mainScore.(Some max value - System.nanoTime())Metacarpal

© 2022 - 2024 — McMap. All rights reserved.