Hệ thống Xếp Hạng Người Dùng Sử Dụng Redis

Xếp hạng người dùng là một tính năng phổ biến trong nhiều ứng dụng. Việc sử dụng cấu trúc tập hợp sắp xếp của Redis để thực hiện chức năng này là lựa chọn hiệu quả và nhanh chóng.

Những bảng xếp hạng thường có tính thời gian, ví dụ như bảng xếp hạng điểm số người dùng. Nếu không có yếu tố thời gian, xếp hạng sẽ dựa trên tổng điểm số, khiến những người dùng lâu năm luôn dẫn đầu, gây cảm giác chán chường cho người dùng mới.

Bắt đầu bằng việc tạo một bảng xếp hạng "Điểm số ngày hôm nay", với quy tắc xếp hạng là số điểm tăng thêm trong ngày từ cao đến thấp.

Khi người dùng tăng điểm, chúng ta sẽ cập nhật vào tập hợp sắp xếp ghi lại các điểm tăng trong ngày.

Giả sử hôm nay là ngày 01 tháng 04 năm 2015, người dùng UID 1 tăng thêm 5 điểm do một hành động nào đó:

ZINCRBY diemngay_20150401 5 1

Còn một số người dùng khác cũng tăng điểm:

ZINCRBY diemngay_20150401 1 2
ZINCRBY diemngay_20150401 10 3

Xem nội dung của tập hợp sắp xếp diemngay_20150401 (tham số withscores giúp lấy cả điểm số):

ZRANGE diemngay_20150401 0 -1 withscores

Kết quả:

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

Lấy top 10 người dùng có điểm số cao nhất:

ZREVRANGE diemngay_20150401 0 9 withscores

Kết quả:

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

Nếu ghi lại bảng xếp hạng hàng ngày, việc tạo ra các bảng xếp hạng khác như "Điểm số ngày hôm qua", "Tuần trước", "Tháng này" trở nên đơn giản.

Ví dụ về bảng xếp hạng "Ngày hôm qua":

ZREVRANGE diemngay_20150331 0 9 withscores

Tạo bảng xếp hạng "Tuần trước" bằng cách kết hợp các điểm số từ 7 ngày:

ZUNIONSTORE diem_tuantruoc 7 diemngay_20150323 diemngay_20150324 diemngay_20150325 diemngay_20150326 diemngay_20150327 diemngay_20150328 diemngay_20150329

Lấy top 10 người dùng từ bảng xếp hạng tuần trước:

ZREVRANGE diem_tuantruoc 0 9 withscores

Các bảng xếp hạng "Tháng này", "Quý này", "Năm nay" có thể được xây dựng tương tự.

Dưới đây là một ví dụ đơn giản về cách thực hiện bằng PHP. Sử dụng thư viện PhpRedis để tương tác với Redis và Carbon để xử lý thời gian.

<?php

namespace MyProject\Leaderboard;

use Redis;
use Carbon\Carbon;

class UserLeaderboard {
    const KEY_PREFIX = 'diemngay_';

    private $redis;

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

    public function updateScore($userId, $points) {
        $key = self::KEY_PREFIX . date('Ymd');
        return $this->redis->zIncrBy($key, $points, $userId);
    }

    private function getDailyLeaders($date, $start, $end) {
        $key = self::KEY_PREFIX . $date;
        return $this->redis->zRevRange($key, $start, $end, true);
    }

    private function getWeeklyLeaders($dates, $outputKey, $start, $end) {
        $keys = array_map(function($date) {
            return self::KEY_PREFIX . $date;
        }, $dates);

        $this->redis->zUnionStore($outputKey, $keys);
        return $this->redis->zRevRange($outputKey, $start, $end, true);
    }

    public function getYesterdayTop10() {
        $yesterday = Carbon::yesterday()->format('Ymd');
        return $this->getDailyLeaders($yesterday, 0, 9);
    }

    public static function getCurrentMonthDates() {
        $startDate = Carbon::now()->startOfMonth();
        $endDate = Carbon::now()->endOfMonth();
        $dates = [];

        for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
            $dates[] = $date->format('Ymd');
        }

        return $dates;
    }

    public function getMonthlyLeaders() {
        $monthDates = self::getCurrentMonthDates();
        return $this->getWeeklyLeaders($monthDates, 'diem_thangnay', 0, 9);
    }
}
?>

Thẻ: Redis Leaderboard php Carbon

Đăng vào ngày 23 tháng 6 lúc 08:45