Redisによるランキング機能の実装

5847 ワード

ランキング機能は一般的なニーズです.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" 

上位から下位までのスコアでtop 10を取得します.
ZREVRANGE rank:20150401 0 9 withscores 
1) "3" 2) "10" 3) "1" 4) "5" 5) "2" 6) "1" 

3つの要素しかないので、これらのデータがクエリーされます.
その日のポイントランキングを毎日記録すれば、他の種類のランキングも簡単です.例えば「昨日のポイントランキング」です.
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です.細部を隠さないように、わざわざ書きます.では、先週のポイントランキングTop 10を調べると、
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)