Tegic Blog

bitmap 统计网站活跃度

位图 bitmaps 的使用场景


bitmaps 类型其实并非一种数据类型,而是支持对 string 类型的 value 进行二进制置位运算。

使用场景:活跃用户统计

主要命令

setbit

getbit

bitop

bitpos

使用bitmaps实现活跃用户统计

很多网站的活跃用户是指登录用户或者付费用户,这里以登录用户为例。

$weekStart = strtotime('-7 day');
$weekEnd = time();
for($i = $weekStart; $i<=$weekEnd ; $i += 86400) {
    if($redis->get('destKey7')) {
        $redis->bitop('OR', 'destKey7', 'destKey7', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey7', $redis->get('login:'.date('Ymd', $i)));
    }
}
$dataList[1] = $redis->bitcount('destKey7');

$weekStart = strtotime('-7 day');
$weekEnd = time();
for($i = $weekStart; $i<=$weekEnd ; $i += 86400) {
    if($redis->get('destKey7and')) {
        $redis->bitop('AND', 'destKey7and', 'destKey7and', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey7and', $redis->get('login:'.date('Ymd', $i)));
    }
}
$dataList[2] = $redis->bitcount('destKey7and');
if (isset($_POST['submit'])) {
    $userId = (int) $_POST['userId'];
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $key = 'login:'.date('Ymd');
    if($userId){
        $result = $redis->setbit($key, $userId, 1);
        header('Location:index.php');
    }
}

显示页

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'login:'.date('Ymd');
$dataList = $details = array();
//过去35天内每天的活跃用户数
$startTime = strtotime('-35 day');
$endTime = time();
for($start = $startTime ; $start <= $endTime; $start += 86400) {
    $key = 'login:'.date('Ymd', $start);
    $details[] = array('date'=>date('Y-m-d', $start), 'num'=>$redis->bitcount($key));
}
//今天登录的用户数
$dataList[0] = $redis->bitcount($key);
//7天活跃用户数
$weekStart = strtotime('-7 day');
$weekEnd = time();
for($i = $weekStart; $i<=$weekEnd ; $i += 86400) {
    if($redis->get('destKey7')) {
        $redis->bitop('OR', 'destKey7', 'destKey7', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey7', $redis->get('login:'.date('Ymd', $i)));
    }
    if($redis->get('destKey7and')) {
        $redis->bitop('AND', 'destKey7and', 'destKey7and', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey7and', $redis->get('login:'.date('Ymd', $i)));
    }
}
//14天活跃用户数
$halfMonthStart = strtotime('-14 day');
$halfMonthEnd = time();
for($i = $halfMonthStart; $i<=$halfMonthEnd ; $i += 86400) {
    if($redis->get('destKey14')) {
        $redis->bitop('OR', 'destKey14', 'destKey14', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey14', $redis->get('login:'.date('Ymd', $i)));
    }
    if($redis->get('destKey14and')) {
        $redis->bitop('AND', 'destKey14and', 'destKey14and', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey14and', $redis->get('login:'.date('Ymd', $i)));
    }
}
//30天活跃用户数
$monthStart = strtotime('-30 day');
$monthEnd = time();
for($i = $monthStart; $i<=$monthEnd ; $i += 86400) {
    if($redis->get('destKey30')) {
        $redis->bitop('OR', 'destKey30', 'destKey30', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey30', $redis->get('login:'.date('Ymd', $i)));
    }
    if($redis->get('destKey30and')) {
        $redis->bitop('AND', 'destKey30and', 'destKey30and', 'login:'.date('Ymd', $i));
    }
    else {
        $redis->set('destKey30and', $redis->get('login:'.date('Ymd', $i)));
    }
}
$dataList[1] = $redis->bitcount('destKey7');
$dataList[2] = $redis->bitcount('destKey7and');
$dataList[3] = $redis->bitcount('destKey14');
$dataList[4] = $redis->bitcount('destKey14and');
$dataList[5] = $redis->bitcount('destKey30');
$dataList[6] = $redis->bitcount('destKey30and');
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$startTime = strtotime('-35 day');
$endTime = time();
for($start = $startTime ; $start <= $endTime; $start += 86400) {
    $key = 'login:'.date('Ymd', $start);
    for($userId = 301; $userId < 30000; $userId++) {
        $value = array_rand(array(0, 1));
        $redis->setbit($key, $userId, $value);
    }
}