一、使用场景:统计用户签到、连续登录或者总登录次数
二、速度要快、占用空间要小。仅用于统计。综上特点:选择redis的BitMap功能。
三、命令行实现BitMap签到
签到
-
用户id为123的用户2021年3月1号签到
$ setBit sign:123:202103 0 1
-
用户id为123的用户2021年3月2号签到
$ setBit sign:123:202103 1 1
获取签到
-
查看用户id为123的用户2021年3月1号签到
$ getBit sign:123:202103 0
-
查看用户id为123的用户2021年3月2号签到
$ getBit sign:123:202103 1
-
查看用户id为123的用户2021年3月 首次签到
$ bitPos sign:123:202103 1
-
查看用户id为123的用户2021年3月 首次漏签
$ bitPos sign:123:202103 0
-
查看用户指定范围内的签到 返回的是十进制
bitfield sign:123:202103 get u3 6
统计签到
四、PHP实现BitMap签到
签到
-
用户id为123的用户2021年3月8号签到
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$day = 8;
$redis->setBit($key, $day, 1);
?>
-
用户id为123的用户2021年3月10号签到
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$day = 10;
$redis->setBit($key, $day, 1);
?>
查看签到
-
查看用户id为123的用户2021年3月10号签到
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$day = 8;
$sign = $redis->getBit($key, $day);
var_dump($sign);
?>
-
查看用户id为123的用户2021年3月份的签到情况( bitmap 实际就是 string 类型,使用 Get)
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$sign = $redis->get($key); //这里查出来的是二进制字符串
$bitmap_bin_str = StrToBin($sign);
for($i = 1; $i <= 31; $i++) {
echo $i.'号签到'.$bitmap_bin_str{$i-1}.PHP_EOL;
}
# 二进制字符串转字符
function StrToBin($str){
$arr = preg_split('/(?<!^)(?!$)/u', $str);
foreach($arr as &$v){
$temp = unpack('H*', $v); $v = base_convert($temp[1], 16, 2);
unset($temp);
}
return join(' ',$arr);
}
?>
-
查看用户id为123的用户2021年3月 首次签到
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$day = $redis->bitPos($key,1);
var_dump($day);
?>
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$day = $redis->bitPos($key,0);
var_dump($day);
?>
-
查看用户id为123的用户2021年3月 首次漏签
统计签到
-
查看用户id为123的用户2021年3月份签到次数
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$count = $redis->bitcount($key,0,-1);
var_dump($count);
?>
-
查看用户id为123的用户2021年3月8号连续签到次数
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'sign:123:202103';
$str = '1111001110000000000000000000000'; //用户当月签到情况
$day = 8;
if ($str{$day-1} == '0') {
var_dump(0);
exit;
}
$count = 1;
for ($i=$day; $i>=0; $i--) {
// var_dump($i-1);
$sign = ($str{$i-1}) & ($str{$i-2});
if ($sign == 1) {
$count += 1;
} else {
break;
}
}
var_dump($count);
?>
五、使用经验和资料参考
使用经验
-
BitMap 是 sting 类型,最大 512 MB
-
注意 setbit 时的偏移量,可能有较大耗时
-
位图不是绝对好,获取不到签到的准确时间,只能判断指定日期有没有签到。
-
redis配合mysql使用,当月数据存redis,上月数据同步到mysql(一个月数据的签到存一条mysql数据)。
-
签到日志可以配合nongoDB使用。
参考文章:
https://blog.csdn.net/han_xuefeng/article/details/115962109
https://my.oschina.net/magebyte/blog/5057536
https://blog.csdn.net/qq_23564667/article/details/110631589
https://blog.csdn.net/a772304419/article/details/103969412
|