php TP5 redis 实现排行榜功能 (日榜 周榜 月榜)

php 结合tp5框架进行redis开发排行榜功能 下面附上我自己封装的redis类;数据持久化我目前是这么想的;同步存;然后定时检测是否过期,或者是否存在在去读数据遍历重新存储

<?php
namespace app\api\controller;
/**
 * redis->排行榜操作
 * @author yiwang
 *
 */
class UserRedis
{

    /**
     *
     * @var object redis client
     */
    private $redis;
    /**
     *
     * @var string 放置排行榜的key
     */
    private $leaderboard;

    /**
     * 构造函数
     * @param object $redis 已连接redis的phpredis的对象
     * @param string $leaderboard 字符串,排行榜的key名
     */
    public function __construct($leaderboard = '')
    {
        $this->redis = new \Redis();
        $this->redis->connect('127.0.0.1','6379');
        if ($leaderboard) {
            //这里不会检查当前的key值是否存在,是为了方便重新访问对应的排行榜
            $this->leaderboard = $leaderboard;
        } else {
            $this->leaderboard = 'leaderboard:' . mt_rand(1, 100000);
            while (!empty($this->redis->exists($this->leaderboard))) {
                $this->leaderboard = 'leaderboard:' . mt_rand(1, 100000);
            }
        }

    }
    /**
     * 获取当前的排行榜的key名
     * @return string
     */
    public function getLeaderboard()
    {
        return $this->leaderboard;
    }
    /**
     * 将对应的值填入到排行榜中
     * @param  $node 对应的需要填入的值(比如商品的id)
     * @param number $count 对应的分数,默认值为1
     * @return Long 1 if the element is added. 0 otherwise.
     */
    public function add($node, $count = 1)
    {
        return $this->redis->zAdd($this->leaderboard, $count, $node);
    }
    /**
     * 给出对应的排行榜
     * @param int $number 需要给出排行榜数目
     * @param bool $asc 排序顺序 true为按照高分为第0
     * @param bool $withscores 是否需要分数
     * @param callback $callback 用于处理排行榜的回调函数
     * @return [] 对应排行榜
     */
    public function getLeadboard($number, $asc = true, $withscores = false,$callback = null)
    {
        if ($asc) {
            $nowLeadboard =  $this->redis->zRevRange($this->leaderboard, 0, $number -1, $withscores);//按照高分数顺序排行;
        } else {
            $nowLeadboard =  $this->redis->zRange($this->leaderboard, 0, $number -1, $withscores);//按照低分数顺序排行;
        }
        if ($callback) {
            //使用回调处理
            return $callback($nowLeadboard);
        } else {
            return $nowLeadboard;
        }
    }

    /**
     * 返回指定成员区间
     * @param $start 开始位置
     * @param $end  结束位置
     * @param $withscores true 高到低  false 低到高
     * @return array
     */
    public function zRevRange($start=0,$end=0,$withscores){
       return $this->redis->zRevRange($this->leaderboard, $start, $end -1, $withscores);//按照高分数顺序排行;
    }

    /**
     * 分页返回成员区间
     * @param $page  分页数量
     * @param $limit  分页数
     * @param $withscores true 高到低  false 低到高
     * @return array   返回数据
     */
    public function zRevRangeLimit($page=1,$limit=10,$withscores=true){
        return $this->redis->zRevRange($this->leaderboard, ($page-1)*$limit, ($page*$limit)-1, $withscores);//按照高分数顺序排行;
    }
    /**
     * 获取给定节点的排名
     * @param string $node 对应的节点的key名
     * @param string $asc 是否按照分数大小正序排名, true的情况下分数越大,排名越高
     * @return 节点排名,根据$asc排序,true的话,第一高分为0,false的话第一低分为0
     */
    public function getNodeRank($node, $asc = true)
    {
        if ($asc) {
            //zRevRank 分数最高的排行为0,所以需要加1位
            $num= $this->redis->zRevRank($this->leaderboard, $node);
            return $num+1;
        } else {
            $num= $this->redis->zRank($this->leaderboard, $node);
            return $num+1;
        }
    }
    //返回指定份数区间的成员数量
    public function zCount($min,$max){

        return $this->redis->Zcount($this->leaderboard, $min,$max);
    }
    //删除指定成员
    public function getZrem($member,$member2 = null, $memberN = null){
        return $this->redis->Zrem($this->leaderboard, $member,$member2,$memberN);
    }

    //指定成员增减分数
    public function  getZincrby($member='',$num=0){
        return $this->redis->Zincrby($this->leaderboard, $num,$member);
    }

    //获取指定成员的分数
    public function getZscore($member=''){
        return $this->redis->Zscore($this->leaderboard,$member);
    }

    //计算给定的一个或多个有序集的交集;周榜月榜
    public function getZinterstore($arr=[],$arr2=[],$conut='sum'){
        return $this->redis->zInter($this->leaderboard,$arr,$arr2,$conut);
    }

    /**
     * 计算给定的一个或多个有序集的并集;周榜月榜
     * @param $key  新的key
     * @param array $arr 合并的redis-key数组
     * @param null $arr2  对应权重数组
     * @param string $conut 计算方式
     * @return mixed
     */
    public function getzUnion($key,$arr=[],$arr2=null,$conut='sum'){

       return $this->redis->Zunionstore($key,$arr,$arr2,$conut);
    }

    //删除指定键值(指定键值下 所有成员全部清空)
    public function del($name=''){

        return $this->redis->del($name);
    }

}

贴一个测试周榜的数据(月榜和周榜一样;数组多少不一样罢了)

<?php

namespace app\api\controller;
use app\common\controller\Api;
/**
 * 会员接口
 */
class User extends Api
{
 
    public function redis_cs(){
        $user=new UserRedis('rank:last_week');
        $list=['20220101','20220102','20220103','20220104','20220105','20220106','20220107'];
        foreach($list as $k=>$v){
            $res2[]='member'.$v;
            $user=new UserRedis('member'.$v);
            for ($i=0;$i<10;$i++){
                $user->add('member_'.$v.$i,$this->rand());
           }
            $data=$user->getLeadboard(1000,true,true);
        }
       $res=$user->getzUnion('rank:last_week',$res2);
    }
    public function rand(){

        $list=rand(111111,999999);
        return $list;
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,需要明确排行榜实现方式。一般而言,排行榜可以使用有序集合(sorted set)来实现,其中成员为需要排名的对象,分数为该对象的分数(或者得分、积分等),分数越高排名越靠前。 接下来,我们针对日榜周榜分别进行实现。 ## 日榜 对于日榜,我们可以使用 Redis 的 ZINCRBY 命令来增加某个对象的分数,并使用 ZREVRANGE 命令来获取分数最高的前 N 个对象,从而得到日榜排名。 具体实现步骤如下: 1. 每当一个对象获得分数时,使用 ZINCRBY 命令将其分数增加; 2. 使用 ZREVRANGE 命令获取排序后的前 N 个对象。 例如,假设我们要维护一个日榜,其中每个用户有一个得分,我们可以使用以下代码实现: ```php // 增加用户得分 $redis->zincrby('daily_ranking', $score, $user_id); // 获取前 N 名用户 $result = $redis->zrevrange('daily_ranking', 0, $n - 1, 'WITHSCORES'); ``` 其中,$score 为用户得分,$user_id 为用户 ID,$n 为需要获取的前 N 名用户数量。 ## 周榜 对于周榜,我们可以使用 Redis 的事务(transaction)来实现。具体实现步骤如下: 1. 获取当前日期所在的周的编号; 2. 在 Redis 中创建一个键名为 "weekly_ranking:周编号" 的有序集合(sorted set); 3. 使用事务,将该周内所有用户的得分分别增加到对应的有序集合中; 4. 使用 ZREVRANGE 命令获取分数最高的前 N 个对象。 例如,假设我们要维护一个周榜,其中每个用户有一个得分,我们可以使用以下代码实现: ```php // 获取当前日期所在的周的编号 $week_number = date('W'); // 开启 Redis 事务 $redis->multi(); // 增加用户得分 $redis->zincrby("weekly_ranking:$week_number", $score, $user_id); // 获取前 N 名用户 $redis->zrevrange("weekly_ranking:$week_number", 0, $n - 1, 'WITHSCORES'); // 执行事务 $result = $redis->exec(); ``` 其中,$score 为用户得分,$user_id 为用户 ID,$n 为需要获取的前 N 名用户数量。 ## 对于,与周榜类似,我们可以使用 Redis 的事务来实现。具体实现步骤如下: 1. 获取当前日期所在的份; 2. 在 Redis 中创建一个键名为 "monthly_ranking:年份-份" 的有序集合(sorted set); 3. 使用事务,将该内所有用户的得分分别增加到对应的有序集合中; 4. 使用 ZREVRANGE 命令获取分数最高的前 N 个对象。 例如,假设我们要维护一个,其中每个用户有一个得分,我们可以使用以下代码实现: ```php // 获取当前日期所在的份 $month = date('Y-m'); // 开启 Redis 事务 $redis->multi(); // 增加用户得分 $redis->zincrby("monthly_ranking:$month", $score, $user_id); // 获取前 N 名用户 $redis->zrevrange("monthly_ranking:$month", 0, $n - 1, 'WITHSCORES'); // 执行事务 $result = $redis->exec(); ``` 其中,$score 为用户得分,$user_id 为用户 ID,$n 为需要获取的前 N 名用户数量。 需要注意的是,以上实现仅供参考,具体实现方式还要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是誰萆微了承諾

你的鼓励是对我最大的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值