toxic

备忘录

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

注: 统计都是要在当日凌晨统计前一日的数据,所以当日凌晨统计的时候 基准日期应当为前一日的日期 也就是说统计的是 前一日的留存数据 而不是今日凌晨的 今日凌晨的需明日才能统计到。

 例如2014-4-11日的3日留存率 今日只是把空数据写入表 然后等日后来更新  并不是当天来统计 而是2014-4-14日再来更新今日的留存率(还在登录的人数)

涉及的统计表

| dgs_remain | CREATE TABLE `dgs_remain` (
  `auto_id` int(11) NOT NULL AUTO_INCREMENT,
  `reg_num` int(11) NOT NULL DEFAULT '0' COMMENT '每日新注册用户',
  `statistics_time` int(11) NOT NULL DEFAULT '0' COMMENT '统计时间',
  `statistics_date` int(11) NOT NULL DEFAULT '0' COMMENT '统计日期',
  `second_day_num` smallint(6) DEFAULT NULL COMMENT '次日留存原数据(当前日期次日还在登录的人数)',
  `third_day_num` smallint(6) DEFAULT NULL COMMENT '三日留存原数据,当前日期后三日还在登录的人数',
  `seven_day_num` smallint(6) DEFAULT NULL COMMENT '七日留存原数据,当前日期后七日还在登录的人数',
  `thirty_day_num` smallint(6) DEFAULT NULL COMMENT '三十日留存原数据,当前日期后三十日还在登录的人数',
  `platform_id` int(11) NOT NULL COMMENT '平台ID',
  `dist_id` int(11) NOT NULL COMMENT '服务器ID',
  `fifty_day_num` smallint(6) DEFAULT NULL COMMENT '15日留存,当前日期后15日还在登录的人数',
  PRIMARY KEY (`auto_id`),
  UNIQUE KEY `UIndex_1` (`statistics_date`,`platform_id`,`dist_id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 |

 

 

放在游戏服务端的守护进程:

<?php
/**
 * Created by PhpStorm.
 * User: buhuan
 * Date: 14-4-11
 * Time: 下午1:46
 * 给GM端推留存率的数据
 */

namespace Application\Process;


use Application\Core\ProcessBase;
use Application\Core\Pusher;
use Application\Interfaces\IProcess;

class Retention extends ProcessBase implements IProcess{

    private $diff = 60;//时间间隔 分钟
    private $push_hour = 0;//推送的小时  0就是0点推送

    /**
     * 开始执行命令。
     */
    function execute()
    {
        print '留存统计守护进程启动[pid:'.getmypid().']@'.date('Y-m-d H:i:s').'|检测间隔为'.$this->diff.'分钟,推送间隔为1天'.chr(10);
        $timediff = $this->diff * 60;
        // TODO: Implement execute() method.
        while(1){
            $hour = intval(date('H'));
            if($hour == $this->push_hour){//如果是$push_hour点 则开始发送数据
                $time = time();
                $current_time = $time-24*60*60;//计算的基准时间
                $start_datetime = date('Y-m-d',$current_time).' 00:00:00';
                $end_datetime = date('Y-m-d',$current_time).' 23:59:59';
                //查询当前前一天的注册人数
                $sql = "SELECT COUNT(user_id) as reg_num FROM user_info_ext WHERE user_active_time > '$start_datetime' AND user_active_time < '$end_datetime'";
                $d = $this->scope->db->fetch($sql);
                $reg_num = $d['reg_num'];

                //查询当前前一天登录的用户
                $sql = "SELECT user_id FROM user_info_ext WHERE user_last_login_time > '$start_datetime' AND user_last_login_time < '$end_datetime' ";
                $d = $this->scope->db->fetchAll($sql);
                $login_users = $d;

                $reg_nums = array();
                $reg_nums['day1'] = $this->nDayUsers(1,$current_time);
                $reg_nums['day3'] = $this->nDayUsers(3,$current_time);
                $reg_nums['day7'] = $this->nDayUsers(7,$current_time);
                $reg_nums['day15'] = $this->nDayUsers(15,$current_time);
                $reg_nums['day30'] = $this->nDayUsers(30,$current_time);

                $data = array(
                    'currentTime' => $time,
                    'reg_num' => $reg_num,
                    'reg_nums' => $reg_nums,
                    'login_users' => $login_users
                );

                Pusher::instance($this->scope)->doPushStat(106,$data);
            }
            sleep($timediff);
        }
    }


    /**
     * @param int $n 1=1日 3=3日。。。
     * @param int $current_time 基准时间
     * @return array
     */
    private function nDayDate($n,$current_time){
        $diff = 24*60*60;
        $start_datetime = date('Y-m-d',$current_time-$n*$diff).' 00:00:00';
        $end_datetime = date('Y-m-d',$current_time-$n*$diff).' 23:59:59';
        $date = array();
        $date[0] = $start_datetime;
        $date[1] = $end_datetime;
        return $date;
    }

    /**
     * 得到基准日期前第n日的注册用户集合
     * @param $n
     * @param $current_time
     * @return array
     */
    private function nDayUsers($n,$current_time){
        $dates = $this->nDayDate($n,$current_time);
        //查询次日注册用户
        $sql = "SELECT user_id FROM user_info_ext WHERE user_active_time > '{$dates[0]}' AND user_active_time < '{$dates[1]}'";
        return $this->scope->db->fetchAll($sql);
    }
} 

 

综合服务端的接口 用来接收游戏端发送过来的数据如下面的&$data :

<?php
/**
 * Created by PhpStorm.
 * User: buhuan
 * Date: 14-4-11
 * Time: 上午11:31
 * 留存
 */

namespace Apps\Process\GearmanWorker;


use Apps\Common\Retention;
use Apps\Interfaces\IGearmanWorker;
use Apps\Process\GearmanWorkerBase;

class RetentionStatistics extends GearmanWorkerBase implements IGearmanWorker{
    /**
     * 释放资源。
     */
    function dispose()
    {
        // TODO: Implement dispose() method.
    }

    /**
     * 处理任务数据。
     *
     * @param string $data 指定任务数据对象引用。
     * @param int $p 指定平台ID。
     * @param int $s 指定服务器ID。
     */
    function execute(&$data, $p, $s)
    {
        $currentTime = intval($data['currentTime'])-24*60*60;
        $reg_num = $data['reg_num'];
        $reg_nums = $data['reg_nums'];
        $login_users = $data['login_users'];

        // TODO: Implement execute() method.
        Retention::instance($this->scope)
                    ->setCurrentTime($currentTime)
                    ->setDist_id($s)
                    ->setPlatform_id($p)
                    ->setRegNum($reg_num)
                    ->setRegNums($reg_nums)
                    ->setLoginUsers($login_users)
                    ->createData()
                    ->setRetentionData(1)
                    ->setRetentionData(3)
                    ->setRetentionData(7)
                    ->setRetentionData(15)
                    ->setRetentionData(30);
    }

} 

 

以上需要用到的留存率的统计类:

<?php
namespace Apps\Common;
use Application\Base\Base;
use Application\Core\Console;
use Application\Core\DbPdo;

/**
 * Created by PhpStorm.
 * User: buhuan
 * Date: 14-4-11
 * Time: 上午10:12
 * 留存率
 */

class Retention extends Base{

    /**
     * @var 当前基准日期时间戳
     */
    private $current_time = 0;

    /**
     * @var array(array('user_id'=>1),array('user_id'=>2)) 当前基准日期时间戳登录的用户(包括user_id)
     */
    private $login_users = NULL;

    private $platform_id = 0;

    private $dist_id = 0;

    /**
     * @var int 当前基准日期的注册数
     */
    private $reg_num = 0;

    /**
     * @var array 统计其他天数的注册用户数组
     * @struct array(
     *      'day1' => array(array('user_id'=>1),array('user_id'=>2)) //前一日
     *      'day3' => array(array('user_id'=>1),array('user_id'=>2)), //前三日
     *      'day7' => array(array('user_id'=>1),array('user_id'=>2)), //前七日
     *      'day15' => array(array('user_id'=>1),array('user_id'=>2)), //前15日
     *      'day30' => array(array('user_id'=>1),array('user_id'=>2))  //前三十日
     *      ...
     * )
     */
    private $reg_nums = NULL;

    public static function instance($scope){
        static $_instance;
        if($_instance == NULL){
            $_instance = new Retention($scope);
        }
        return $_instance;
    }


    function __construct($scope){
       parent::__construct($scope);
    }


    public function setCurrentTime($param){
        $this->current_time = $param;
        return $this;
    }


    public function setLoginUsers($param){
        $this->login_users = $param;
        return $this;
    }


    public  function setPlatform_id($param){
        $this->platform_id = $param;
        return $this;
    }


    public function setDist_id($param){
        $this->dist_id = $param;
        return $this;
    }

    public function setRegNum($param){
        $this->reg_num = $param;
        return $this;
    }

    public function setRegNums($param){
        $this->reg_nums = $param;
        return $this;
    }

    /**
     * 创建当天的统计数据
     */
    public function createData(){
        $this->checkProperties();
        $current_date = strtotime(date('Y-m-d',$this->current_time));
        $sql = "INSERT INTO dgs_remain (reg_num,statistics_time,statistics_date,dist_id,platform_id)
                VALUES ($this->reg_num,$this->current_time,$current_date,$this->dist_id,$this->platform_id)";
        if($this->scope->db->execute($sql,NULL,DbPdo::SQL_TYPE_INSERT))
            Console::debug('当前基准时间'.date('Y-m-d',$this->current_time).'统计数据写入成功');
        return $this;
    }


    /**
     * @param $nDay int N日留存  1日=1 3日=3 ....
     */
    public function setRetentionData($nDay){
            $this->checkProperties();
            $daytime = 24*60*60;
            //===================================================N日留存
            $ratio_day = 0;
            $date = date('Y-m-d',$this->current_time-$daytime*$nDay);//N日的日期
            $time = strtotime($date);//$nDay日的时间戳
            //查找当前日期前$nDay日的新增注册
            $sql = "SELECT reg_num FROM dgs_remain WHERE statistics_date = $time";
            $d = $this->scope->db->fetch($sql);
            $login_users_again = 0;//$nDay日还在登录的用户数
            if(isset($d['reg_num'])){//如果dgs_remain中有当前日期前$nDay日的数据的话 则进行前$nDay日的$nDay日留存更新
                //查找当前日期前$nDay日注册的用户数组
                if(!empty($this->login_users) && !empty($this->reg_nums)){
                    $active_users = $this->reg_nums['day'.$nDay];

                    foreach($this->login_users as $login){
                        foreach($active_users as $active){
                            if($login['user_id'] == $active['user_id']){
                                $login_users_again++;
                                break 1;
                            }
                        }
                    }
                }
            }

            switch($nDay){
                    case 1: $sql = "UPDATE dgs_remain SET second_day_num = $login_users_again
                            WHERE statistics_date = $time and platform_id = $this->platform_id and dist_id = $this->dist_id";
                            break;

                    case 3: $sql = "UPDATE dgs_remain SET third_day_num = $login_users_again
                            WHERE statistics_date = $time and platform_id = $this->platform_id and dist_id = $this->dist_id";
                            break;

                    case 7: $sql = "UPDATE dgs_remain SET seven_day_num = $login_users_again
                            WHERE statistics_date = $time and platform_id = $this->platform_id and dist_id = $this->dist_id";
                            break;

                    case 15: $sql = "UPDATE dgs_remain SET fifty_day_num = $login_users_again
                            WHERE statistics_date = $time and platform_id = $this->platform_id and dist_id = $this->dist_id";
                            break;

                    case 30: $sql = "UPDATE dgs_remain SET thirty_day_num = $login_users_again
                            WHERE statistics_date = $time and platform_id = $this->platform_id and dist_id = $this->dist_id";
                            break;
            }

            $this->scope->db->execute($sql,NULL,DbPdo::SQL_TYPE_UPDATE);
            Console::debug("当前日期".date('Y-m-d',$this->current_time)." 的前 $nDay 日[".$date."]留存率更新成功");
            return $this;
    }


    private function checkProperties(){
        if($this->current_time == 0){
            Console::debug("请设置基准时间戳");
            exit;
        }

        if($this->platform_id == 0){
            Console::debug("请设置平台ID");
            exit;
        }

        if($this->dist_id == 0){
            Console::debug("请设置服务器ID");
            exit;
        }
    }

} 

 

posted on 2014-04-11 20:15  toxic  阅读(429)  评论(0编辑  收藏  举报