Skip to content

Instantly share code, notes, and snippets.

@wonjun27
Last active August 11, 2021 16:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save wonjun27/3f9dc04712056829d338 to your computer and use it in GitHub Desktop.
Save wonjun27/3f9dc04712056829d338 to your computer and use it in GitHub Desktop.
Leaderboard Using Redis
Leaderboard Using Redis
http://labs.strava.com/blog/koms-powered-by-redis/
Strava KOMS, Powered by Redis
----------------
http://aimeeault.com/2014/06/22/making-the-most-of-redis-and-sorted-sets/
For example, what if I only want to see a leaderboard of members who are between the ages of 18 and 49? The Sorted Set contains no information on how old each member is. And I don’t want to maintain a separate Redis Sorted Set for just these users, because that’s kind of redundant, right? You probably don’t want to fetch every single one of the potentially hundreds of thousands of records and filter individually… that’s not very efficient! There’s a couple of ways you could approach this with Redis. One is by way of Lua scripting with use of EVAL (which runs Lua) and ZSCAN (which can be used for matching keys and values by rules, similar to regular expressions).
ZINTERSTORE "new_leaderboard" 10 "leaderboard" "temp_users_set"
--------------------
http://openmymind.net/Data-Modeling-In-Redis/
redis.set '23323:1:leto', {:points => 9001, :time => ..., :level -> ...}
redis.set '23323:1:ghanima', {:points => 3994, :time => ..., :level -> ...}
users = redis.zrevrange '23323:1', 0, 10
redis.mget users.map{|u| "23323:1:#{u}" }
-> Use sorted set, zadd instead of set below to keep track of scores. This allows using zreverange
-> Note sets here are used to hold additional values?
http://openmymind.net/2011/5/8/Practical-NoSQL-Solving-a-Real-Problem-w-Mongo-Red/
The first change we made, which is small (but I want to cover anyways), is that
we no longer store the date and time the score was created at. Instead, we store the start of the given leaderboard scope.
So, if we are storing a daily score to a leaderboard with a UTC offset of 4,
we'll actually store 2011/05/07 20:00 (assuming today is May 8th).
Why? For two reasons. First, grabbing a leaderboard now turns into a == rather than a >=.
Also, we can move to a 32bit int field rather than a 64bit date field, resulting in less memory used by our index.
Redis.zadd("3234_daily_201105072000", 1000000, "device1-leto")
Redis.zadd("3234_daily_201105072000", 200000, "device1-paul")
Redis.zadd("3234_daily_201105072000", 300000, "device-2-jess")
Redis.zrevrank("3234_daily_201105072000", "device1-paul") # gives us 1 (it's 0 based)
=> extend this to hoursly leadearboard, then combine the last 24 hours depending on the user request time.
-----
Create a daily/weekly/monthly leaderboard for each challenge, group, everyone. Leaderboard per activity doesn't take too long, so fall back to SQL.
--------
Also many times you want to have different listings with different filters. When this filters are limited in number (for example categories) you can simply use a different Redis list for every different filter you have. After all you are just taking 5000 items per list, and Redis can hold millions of items with little memory. As usually is a compromise, use your creativity!
Show a leaderboard with the top #100 scores.
Show the user its current global rank.
This operations are trivial using a Redis sorted set, even if you have millions of users and millions of new scores per minute.
To get the top 100 users by score is as easy as ZREVRANGE leaderboard 0 99.
Similarly to tell the user its global rank you just do ZRANK leaderboard <username>.
Implement expires on items
Another way to use sorted sets is to index stuff by time. We just use the unix time as score. This can be used in general to index things by time, but a notable usage is to expire things in our main database when a given amount of time has elapsed.
http://oldblog.antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment