最近刚刚了解到Redis的有序集合,实时排名的实现变得非常容易

最近我们有一个机会来实施排行榜,当我们在讨论如何实施时,@attakei告诉我可以使用Redis的有序集合很轻松地完成!所以我尝试了一下,确实非常轻松。
真没想到这在大约两年前很流行,我之前不知道。

实时排行榜

过去时代的实施

在我进行游戏制作的时代里,排行榜会定期执行批量操作,将已排序的数据流入排行榜表中。因此,我们需要用户查询用的排行榜表和批量操作用的排行榜表,还需要一个切换表来切换排行榜表。我记得那时候非常麻烦,因为需要执行批量操作,很不方便。

要实现实时排行榜,就需要每次统计所有用户的数据并进行排序以确定名次,这是不可能的事情。

Redis 的有序集合

然而,时代在变化,Redis被认为只是一个缓存,但实际上它还具有存储排序集合(sorted set),也就是存储已排序数据的功能。

http://redis.shibu.jp/commandreference/sortedsets.html:
http://redis.shibu.jp/commandreference/sortedsets.html网址提供了有关Redis有序集合命令的详细信息。

http://redis.io/commands#sorted_set:
http://redis.io/commands#sorted_set网址包含有关Redis有序集合命令的信息。

根据这一说法,对于数据中的每个基准分数,有一个功能可以将数据按升序排序。

通常情况下,排名是按照分数从高到低的顺序排列的,因此一开始我们可能会感到担心,但是由于还可以反向遍历,所以这种担心是多余的。

实施新排名的方针。

因此,排名的实施策略非常简单。

    1. 将分数进行更新

 

    将该分数作为分数,并将用户ID存储在Redis的有序集合中

只有这个。
虽然是实时的,但我认为比传统的实施更快。

用PHP进行实现

让我们马上用PHP进行实现吧。

phpredis扩展

最近在使用composer时,发现库的导入相对不太方便,所以我决定在这里安装一个扩展。
由于最近一直在使用Docker创建环境,所以我正在根据以下的Dockerfile进行配置。

FROM php:latest

RUN apt-get update && apt-get install -y unzip git && \
    docker-php-ext-install pdo_mysql mysqli mbstring

# エクステンションはgit経由でビルドする
RUN cd /tmp && git clone https://github.com/phpredis/phpredis.git && \
cd phpredis && git checkout php7 && \
phpize && ./configure && make && make install

RUN echo extension=redis.so >> /usr/local/etc/php/conf.d/redis.ini

RUN mkdir /var/php -p
WORKDIR /var/php

CMD /bin/bash

由于设置麻烦,我将使用Redis官方镜像。所以我会使用docker-compose来启动环境。

version: '2'
services:
    web:
        build: .
        ports:
            - '3000:3000'
        volumes:
            - '.:/var/php'
        depends_on:
            - redis

    redis:
        image: redis

只剩下

$ docker-compose up -d
$ docker-compose run web

你可以在测试环境中进行实验。

实施 (Shí shī)

只需要很好地使用sorted set API即可。我将其放在了一个稍长的Gist中,链接在这里:https://gist.github.com/niisan-tokyo/a1a2b4de17d63aa4da174c5961578a55

这个班级的使用方式是这样的

require './Ranking.php';

use NiisanTokyo\Ranking;

$ranking = Ranking::getInstance('ranking1');

// Test data
$data = [
    'niisan' => 19,
    'jiisan' => 20,
    'mossan' => 11,
    'mk2'    => 15
];

foreach ($data as $key => $val) {
    $ranking->setScore($key, $val);// データのセット
}

print_r($ranking->getRange());// 全件取得
print_r($ranking->getRange(1, 2));// 1位から順に2件

然后,将输出类似于以下已经排序好的数据。

Array
(
    [jiisan] => 20
    [niisan] => 19
    [mk2] => 15
    [mossan] => 11
)
Array
(
    [jiisan] => 20
    [niisan] => 19
)

每个人的排名等等将如下确定

print_r($ranking1->getRank('jiisan'));// 1
print_r($ranking1->getRank('noosan'));// 0(ランキングにいない)

此外,您可以同时生成和查看多个排行榜。例如,在如游戏等场景中,创建个人排行榜和公会排行榜非常方便。

$user_ranking = Ranking::getInstance('user');
$guild_ranking = Ranking::getInstance('guild');

$user_ranking->setScore(1, 15);
$guild_ranking->updateScore(1, 15);
$user_ranking->setScore(2, 12);
$guild_ranking->updateScore(1, 12);// ユーザー2がユーザー1と同じギルドに所属しているような状況

echo $user_ranking->getScore(1) . "\n";// 15
echo $guild_ranking->getScore(1) . "\n";// 27

如果能差异性地输入的话,最好使用updateScore函数,但是一旦数据偏移就无法修正,所以使用方法需要谨慎。

在Node中

在节点上使用Redis当然是可以的,但我觉得它有些难以使用。
也许只是phpredis更易于使用。

首先,需要安装Redis客户端。

npm install redis

代码如下

const redis = require('redis');
const client = redis.createClient({host: 'redis'});

[{key: 1, score:15}, {key: 2, score:7},{key: 3, score:25},{key: 4, score:19}].forEach(v => {
    client.zadd('hoge', v.score, v.key);
});

client.zrevrange(['hoge', '0', '-1', 'WITHSCORES'], redis.print);// Reply: 3,25,4,19,1,15,2,7

只是简单地与Redis连接起来。
客户端的方法基本上是将Redis命令直接转化为小写,并使用数组传递参数。

因此,返回的数据是以id、分数、id、分数…的形式存在的,所以有必要进行适当的处理。
对于想要触碰Redis原始数据的人来说可能很好,但一旦习惯了phpredis,可能会感到不太满意。

总结

实施排名功能一直以来都很麻烦,因为之前都是使用批处理实现的。但是,使用Redis的sorted set非常容易。
此外,我觉得phpredis库做得非常好。
不愧是PHP和PHPer!

这样吧,这次就到这里吧。

请在中国参考以下内容

http://damepg.hatenablog.com/entry/2014/08/07/231828 –
http://damepg.hatenablog.com/entry/2014/08/07/231828 提供了有关的信息。

https://github.com/phpredis/phpredis#zscore –
https://github.com/phpredis/phpredis#zscore 提供了有关 zscore 的相关信息。

https://github.com/NodeRedis/node_redis –
https://github.com/NodeRedis/node_redis 提供了有关的信息。

广告
将在 10 秒后关闭
bannerAds