使用Redis实现一个排行榜功能

该功能主要使用到Redis的有序集合(SortedSet)来实现的,主要参考的https://blog.csdn.net/pbymw8iwm/article/details/81130639
来实现这样一个功能,由于最近写的是PHP项目,所以使用PHP+predis的代码实现。

Predis 操作手册https://www.cnblogs.com/houdj/p/6859719.html

1、首先实现对每个用户增加集分的操作:
遇到问题:由于Zset提供了丰富的功能,但是不存在一个提供判断ZSet中某个键是否存在指定成员的函数,
新增一个Set中的Key方法是Zadd,增加Score的方法是Zincrby,无法给一个不存在的成员增加Score。
解决方案参考:https://blog.csdn.net/sparkexpert/article/details/78351558 使用Zrank 排名大于等于0则存在,null则不存在。

源码:

    public function rankIncrease($key,$user,$count = 1)
    {
        //var_dump($user['id']);die;
        $rediskey = $key . date('Ymd');
        try {
            //如果当天排行不存在则创建Key并设置过期时间
            if(!Redis::exists($rediskey)) {
                $value = $user['id'] . '|' . $user['name'] . '|' . $user['avatar'];
                Redis::zadd($rediskey, $count, $value);
                Redis::expire($rediskey, $this->key_timeout);
            }
            else {
                $value = $user['id'] . '|' . $user['name'] . '|' . $user['avatar'];
                //如果已存在的key 增加计量数,如果不存在则插入新的记录
                if (Redis::zrank($rediskey, $value) >= 0)
                {
                    Redis::zincrby($rediskey,$count,$value);
                }
                else {
                    Redis::zadd($rediskey, $count, $value);
                }
            }
            return 0;
        }
        catch(Exception $e)
        {
            return $e;
        }
    }
image.png

2 获取日榜 周榜 月榜
这里日榜是时时数据,周榜和月榜是根据日榜合并一个周或者一个月,过期时间1一个小时,如果存在周榜或者月榜这个key直接查询,如果过期时间到了 则重新合并一个周榜或者月榜。

   /**
     * 获取排行榜单(日|周|月)
     * @param $key 活跃榜|问答榜
     * @param $type 日|月|周
     * @param $user request->user()
     * @return \Exception
     */

    public function getRank($key,$type,$user)
    {
        try {
            //日榜
            if ($type == self::DAY) {
                $rediskey = $key . date('Ymd');
               if(Redis::exists($rediskey)) {//如果当天没人操作
                    $dayRank = Redis::zrevrange($rediskey, 0, $this->ranksize - 1);
                    return $dayRank;
                }
                else
                {
                    return array();
                }
            }
            else
            {
               $rediskeyarray = $this->getKeyArray($key,$type);
               $rediskey = $key . date('Ymd') . $type;
               if(Redis::exists($rediskey))//如果存在这个周榜或月榜Key
               {
                   return Redis::zrevrange($rediskey,0,$this->ranksize-1);
               }
               else
               {
                   Redis::zunionstore($rediskey,$rediskeyarray);
                   Redis::expire($rediskey, 60*60);//设置一小时过期时间
                   return Redis::zrevrange($rediskey,0,$this->ranksize-1);
               }
            }
        } catch (\Exception $e)
        {
            return $e;
        }

    }

    /**
     * 获取月榜 周榜的rediskey array
     * @param $key (用户榜or问答榜)
     * @param $type week or month
     * @return array
     */
    public function getKeyArray($key,$type)
    {
        if($type == self::WEEK)
        {
            $keyarray = array();
            for($x = 0;$x < 7;$x++)
            {
                if($x == 0)
                {
                    $rediskey = $key . date('Ymd');
                }
                else {
                    $rediskey = $key . date('Ymd', strtotime("'-{$x} day'"));
                }
               // var_dump($rediskey);die;
                if(Redis::exists($rediskey))//如果存在这个key 就加入array
                {
                    array_push($keyarray,$rediskey);
                }
            }
            return $keyarray;
        }
        else if($type == self::MONTH)
        {
            $keyarray = array();
            for($x = 0;$x < 30;$x++)
            {
                if($x == 0)
                {
                    $rediskey = $key . date('Ymd');
                }
                else {
                    $rediskey = $key . date('Ymd', strtotime("'-{$x} day'"));
                }
                // var_dump($rediskey);die;
                if(Redis::exists($rediskey))//如果存在这个key 就加入array
                {
                    array_push($keyarray,$rediskey);
                }
            }
            return $keyarray;
        }
    }

如果对您有帮助的 麻烦给个喜欢吧 谢谢

你可能感兴趣的:(使用Redis实现一个排行榜功能)