问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

redis的setbit这个bit怎么理解,配合bitcount使用

发布网友 发布时间:2022-05-03 14:54

我来回答

2个回答

懂视网 时间:2022-05-03 19:16

首先我们看一个场景:一个网站,需要统计一周内连续登陆的用户,以及一个月内登陆过的用户。

如果用传统的数据库如Mysql来实现的话,很难做到。但如果用Redis来做的话,就很简便。Redis的集合类型和Bitmap类型都可以很容易的做到。今天,我们主要来谈谈如何用Bitmaps来实现统计活跃用户的功能。

Bitmaps

在计算机系统中,最小的信息单位是字节,1个字节等于8位,每一位都只可能是0或1(计算机只认识这两个数)。使用Bitmaps可以直接对位进行操作。

可以把bigmaps看做一个数组,数组里每一位只可能是0或者1,数组的下标在这里看做偏移量。

下面我们来介绍几个和Bitmaps相关的命令:

setbit

setbit key offset value:给对应的位设置值

比如今天有用户3、8、23、32访问了网站,则

setbit user:view:2020-5-17 3 1
setbit user:view:2020-5-17 8 1
setbit user:view:2020-5-17 23 1
setbit user:view:2020-5-17 32 1

开发提示:很多应用id都不是从1开始,有许多是从指定数字开始的,比如1001、10001开始。对于这些,我们在设置的时候可以先减去初始值,防止浪费空间

getbit

getbit key offset 获取指定位的值

如果我想知道今天8号用户和45号用户是否登录过,则

127.0.0.1:6379> getbit user:view:2020-5-17 8
(integer) 1
127.0.0.1:6379> getbit user:view:2020-5-17 45
(integer) 0

可以看到8号用户今天登录过,但是45号用户今天还没有登录。

bitcount

bitcount key [start] [end] 获取指定范围为1的个数

我想知道今天有多少用户登陆过了,则

127.0.0.1:6379> bitcount user:view:2020-5-17
(integer) 4

Bitmaps间的操作

bitop op destkey key [key ...]

bitop命令可以对多个bitmaps做交集(and)、并集(or)、非(not)、异或(xor),并将操作结果存放在destkey中。

如果想知道连续三天都登陆过的用户,即5月17日、18日、19日都登陆的用户数量。

这三天登陆情况如下:

  • 5月17日3、8、23、32用户登陆过

  • 5月18日3、23、43、54号用户登陆过

  • 5月19日3、5、23、 32、56、78号用户登陆过

  • 127.0.0.1:6379> bitop and three:and user:view:2020-5-17 user:view:2020-5-18 user:view:2020-5-19
    127.0.0.1:6379> bitcount three:and
    (integer) 2

    如果想知道,这三天有多少用户登陆过。

    127.0.0.1:6379> bitop or three:or user:view:2020-5-17 user:view:2020-5-18 user:view:2020-5-19
    (integer) 10
    127.0.0.1:6379> bitcount three:or
    (integer) 9

    可以看到,这三天共有9位用户登陆过。

    实战

    讲完上面所讲知识后,我们就可以来完成想要的需求:需要统计一周内连续登陆的用户,以及一个月内登陆过的用户。

    首先模拟用户30天内登陆情况,伪代码如下:

    for ($i = 0; $i < 20000; $i++) {
     $userId = mt_rand(1, 10000);
     $date = time() - 86400 * mt_rand(0, 30);
     $key = 'userlogin_'.date('Ymd', $date);
     
     $redis->setBit($key, $userId, 1);
    }

    获取一周内都登陆的用户,当然我们不会一次性全部取,而是想分页那样,一次取一定数量的,伪代码如下:

    for ($i = 1; $i <= 7; $i ++) {
     $key = "userlogin_".date('Ymd', time() - (86400*$i));
     
     if ($i == 1) {
     $redis->bitOp('and', 'week_logined', $key);
     } else {
     $redis->bitOp('and', 'week_logined', 'week_logined', $key);
     }
    }
     
    // 获取前50个用户
    $userIds = [];
    for ($i=1; $i<=10000; $i++) {
     $ret = $redis->getBit('week_logined', $i);
     $ret && $userIds[] = $i;
     
     if (count($userIds) >=50) break;
    }

    这里面有一个注意点,也是易错点,在bitop时候,第一次的时候,因为week_logined还不存在,所以进行op的键只有一个。当从第二次开始时候,进行op的键就为2个了。

    获取一个月内登陆的用户,思路基本和上面一样,只是将and改为or

    for ($i = 1; $i <= 3; $i ++) {
     $key = "userlogin_".date('Ymd', time() - (86400*$i));
     $redis->bitOp('or', 'month_loginOnce', 'month_loginOnce', $key);
    }
     
    // 获取一个月内登陆过的用户
    $userIds = [];
    for ($i=1; $i<=10000; $i++) {
     $ret = $redis->getBit('month_loginOnce', $i);
     $ret && $userIds[] = $i;
    }

    可以看到,在进行or的时候和and还是有些区别的。or的时候,无需对第一次进行判断。个中缘由,大家自己体会体会。

    热心网友 时间:2022-05-03 16:24

    Redis的 setbit(key, offset, value)操作对指定的key的value的指定偏移(offset)的位置1或0,时间复杂度是O(1)。

    在Redis中获取此bitmap的key值是通过用户执行操作的类型和时间戳获得的。

        这个简单的例子中,每次用户登录时会执行一次redis.setbit(daily_active_users, user_id, 1)。将bitmap中对应位置的位置为1,时间复杂度是O(1)。统计bitmap结果显示有今天有9个用户登录。Bitmap的key是daily_active_users,它的值是1011110100100101。

    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    WIN7不会自动安装AHCI驱动是怎么回事?每次重装系统后都得我自己安装_百... 钉钉录播课能否查看观看时长 为什么城市轨道要有身高条件 城轨交通运营管理专业现身高吗 城市轨道交通运营管理这个专业是否有身高要求 读城轨专业需要什么条件 学习城轨专业需要什么条件? 城市轨道专业最低的身高要求多少?身高158毕业出来好找工作吗? 城轨专业要求身材吗 城轨专业有身高限制吗 redis安装环境,Linux是redis的最好安装环境,很多人都建议把它按哪里, 微信的摇一摇功能里面可以利用打招呼这个功能进行多次聊天吗? 用微信摇一摇功能摇出来的好友可以看到我的微信中个人信息吗? 用微信摇一摇的时候 摇一下以后 就一直是 正在搜索同一时刻摇晃手机的人 一直没反映是怎么回事 php可以实现微信摇一摇的功能吗 怎么样才能实现微信自动摇一摇 redis过期时间设置 redis 从服务器无法启动 怎样改回主服务 C:&#92;&gt;Redis&#92;redis&gt;redis-server.exe redis.windows.conf 拒绝访问. redis创建报错怎么办? linux将redis的redis.conf中的daemonize配置为yes但还是前台启动 为什么redis开启服务也会报错啊 redis能进入客户端,但是IP号前面少了redis,并且运行命令也没反应,怎么解决? 命令行启动redis队列,报这个错,求助 redisdesktopmanager 使用什么协议连接redis windows防火墙 3. 名词解释 (1)通信协议 (2)接口 (3)计算机网络体系结构 (4)IP地址 求教电表(电度表)通信协议(protocol),我们想开发通信模块,谢谢!顺便告诉电表的品牌。 计算机网络中的规程(procedure)和协议(protocol)有什么区别和关系? php 连接 redis 是什么协议 redis主从时,从库执行lru吗 怎么统计redis的hash中的某个字段个数,在线等 怎样将bitmap添加到mysql数据库中 redis什么时候可以搭 redis是否收费 redis做聊天系统可靠吗 java聊天室用redis数据库怎么做 哪里有基于redis的订阅发布实现的网页聊天室或网页推送系统 django-redis 支持哪些命令 django from django_redis import get_redis_connection后如何为该redis添加分布式锁呢? django redis 多少用户访问 php 加单引号后 就报MYSQL错误! 求解! mysql 插入 单引号&#39;mysql 插入单引号&#39;会出错,如Jim&#39;s mysql单引号和双引号的区别 mysql 的单引号和双引号有什么区别吗 求教mysql中单引号和双引号的区别! mysql为什么大双引号标红? mysql,怎么根据一个时间段,然后查询出这个时间段的全部时间?? 图形界面的linux怎么安装redis redis桌面管理工具 怎么启动 至于为什么不使用redis的muti,expire,watch等机制