Tutorial using Redis to achieve user points leader

  • 2020-05-06 12:00:06
  • OfStack

Leaderboard functionality is a common requirement. Using the feature of ordered collections in Redis to implement leaderboards is a good and fast choice.

General leaderboards are effective, such as "user points". If there is no effectiveness according to the total ranking, may always top several old users, for new users, that is really frustrating.

First, let's have a "today's scoreboard". The sorting rule is that the number of points added by users today is from the most to the least.

So when the user increases the score, he or she operates on an ordered set that records the score increase of the day.
So let's say today is April 1st, 2015, and the user with UID of 1 has gained 5 credits for an operation.
The Redis command is:


ZINCRBY rank:20150401 5 1

Suppose there are a few other users who have also added points:


ZINCRBY rank:20150401 1 2
ZINCRBY rank:20150401 10 3

Look at the data now in the ordered collection rank:20150401 (the withscores parameter can be attached to the score of the retrieved element) :


ZRANGE rank:20150401 0 -1 withscores

1) "2"
2) "1"
3) "1"
4) "5"
5) "3"
6) "10"

Get top10:

, score from high to low

ZREVRANGE rank:20150401 0 9 withscores

1) "3"
2) "10"
3) "1"
4) "5"
5) "2"
6) "1"

Because there are only three elements, the data is queried.

If you keep a daily tally of the day's points, the rest of the lists will be easy.
For example, "yesterday's scoreboard" :


ZREVRANGE rank:20150331 0 9 withscores

The use of union to achieve the sum of points for many days, the realization of "last week's scoreboard" :


ZUNIONSTORE rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 rank:20150326 rank:20150327 rank:20150328 rank:20150329 WEIGHTS 1 1 1 1 1 1 1

In this way, the 7-day integral records are merged into the ordered set rank:last_week. If the weight factor WEIGHTS is not given, the default is 1. Write to avoid hiding details.
So the query last week's scoreboard Top10 information is:


ZREVRANGE rank:last_week 0 9 withscores

Monthly, quarterly, annual and so on.

Here is a simple implementation of the PHP version. Using Redis relies on PHP to extend PhpRedis, and the code also relies on the Carbon library for processing time. The amount of code is small, so I don't type comments.


<?php

namespace Blog\Redis;

use \Redis;
use Carbon\Carbon;


class Ranks {

  const PREFIX = 'rank:';

  protected $redis = null;


  public function __construct(Redis $redis) {
    $this->redis = $redis;
  }


  public function addScores($member, $scores) {
    $key = self::PREFIX . date('Ymd');
    return $this->redis->zIncrBy($key, $scores, $member);
  }


  protected function getOneDayRankings($date, $start, $stop) {
    $key = self::PREFIX . $date;
    return $this->redis->zRevRange($key, $start, $stop, true);


Related articles: