zoukankan      html  css  js  c++  java
  • 使用 Redis 实现排行榜功能

    排行榜功能是一个很普遍的需求。使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择。

    一般排行榜都是有实效性的,比如“用户积分榜”。如果没有实效性一直按照总榜来排,可能榜首总是几个老用户,对于新用户来说,那真是太令人沮丧了。

    首先,来个“今日积分榜”吧,排序规则是今日用户新增积分从多到少。

    那么用户增加积分时,都操作一下记录当天积分增加的有序集合。
    假设今天是 2015 年 04 月 01 日,UID 为 1 的用户因为某个操作,增加了 5 个积分。
    Redis 命令如下:

    ZINCRBY rank:20150401 5 1
    

    假设还有其他几个用户也增加了积分:

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

    看看现在有序集合 rank:20150401 中的数据(withscores 参数可以附带获取元素的 score):

    ZRANGE rank:20150401 0 -1 withscores
    
    1) "2"
    2) "1"
    3) "1"
    4) "5"
    5) "3"
    6) "10"
    

    按照分数从高到低,获取 top10:

    ZREVRANGE rank:20150401 0 9 withscores
    
    1) "3"
    2) "10"
    3) "1"
    4) "5"
    5) "2"
    6) "1"
    

    因为只有三个元素,所以就查询出了这些数据。

    如果每天记录当天的积分排行榜,那么其他花样百出的榜单也就简单了。
    比如“昨日积分榜”:

    ZREVRANGE rank:20150331 0 9 withscores
    

    利用并集实现多天的积分总和,实现“上周积分榜”:

    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
    

    这样就将 7 天的积分记录合并到有序集合 rank:last_week 中了。权重因子 WEIGHTS 如果不给,默认就是 1。为了不隐藏细节,特意写出。
    那么查询上周积分榜 Top10 的信息就是:

    ZREVRANGE rank:last_week  0 9 withscores
    

    “月度榜”、“季度榜”、“年度榜”等等就以此类推。

    <?php
    class Ranks{
    	const PREFIX = 'zhengban';
    	protected $redis = '';
    	/*
    	初始化
    	 */
    	public function __construct(redis $redis){
    		$this->redis = $redis;
    	}
    	/*
    	添加到排行榜
    	 */
    	public function addScores($gameid,$score){
    		$key = self::PREFIX . date('Ymd');
    		return $this->redis->zIncrBy($key, $score, $gameid);
    	}
    	/*
    	获取特定一天的排行榜数据
    	返回一维数组,key是gameid,value是score
    	 */
    	public function getOneDayRankings($date,$start,$end){
    		$key = self::PREFIX . $date;
            return $this->redis->zRevRange($key, $start, $end, true);
    	}
    	/*
    	获取几天数据的排行榜
    	 */
    	public function getMultiDaysRankings($dates,$start,$end){
    		$outKey = null;
    		foreach ($dates as $v){
    			$keys[] = self::PREFIX . $v;
    		}
            //$weights = array_fill(0, count($keys), 1);
            //$this->redis->zUnion($outKey, $keys,$weights);
            $this->redis->zUnion($outKey, $keys);
            return $this->redis->zRevRange($outKey, $start, $end, true);
    	}
    }
    
    
    	$host = "192.168.1.114";
    	$port = 6379;
    	$pwd = "123456";
    	$redis = new Redis();
    	if ($redis->connect($host, $port) == false) {
    		exit('{"result":"-1"}');   //连接失败
    	}
    	/* AUTH的密码 */
    	if ($redis->auth($pwd) == false) {
    		exit('{"result":"-2"}');   //认证失败
    	}
    
    	$Ranks = new Ranks($redis);
    	//$Ranks->addScores(12,1);
    	$order = $Ranks->getMultiDaysRankings(array(20151021,20151022,20151020),0,9);
    	var_dump($order);
    
    	
    

     结果

    array
      10 => string '11' (length=2)
      1 => string '10' (length=2)
      3 => string '6' (length=1)
      2 => string '5' (length=1)
      5 => string '4' (length=1)
      4 => string '3' (length=1)
      12 => string '2' (length=1)
      16 => string '1' (length=1)
      15 => string '1' (length=1)
      14 => string '1' (length=1)
    
  • 相关阅读:
    不可或缺 Windows Native (15)
    不可或缺 Windows Native (14)
    不可或缺 Windows Native (13)
    不可或缺 Windows Native (12)
    不可或缺 Windows Native (11)
    不可或缺 Windows Native (10)
    不可或缺 Windows Native (9)
    不可或缺 Windows Native (8)
    不可或缺 Windows Native (7)
    不可或缺 Windows Native (6)
  • 原文地址:https://www.cnblogs.com/mr-amazing/p/4897859.html
Copyright © 2011-2022 走看看