东莞网站优化seo,哪个网站做国内销海外的,如何免费做一个网页,网站seo心态BitMap功能演示
我们针对签到功能完全可以通过mysql来完成#xff0c;比如说以下这张表 用户一次签到#xff0c;就是一条记录#xff0c;假如有1000万用户#xff0c;平均每人每年签到次数为10次#xff0c;则这张表一年的数据量为 1亿条 每签到一次需要使用#xff08…BitMap功能演示
我们针对签到功能完全可以通过mysql来完成比如说以下这张表 用户一次签到就是一条记录假如有1000万用户平均每人每年签到次数为10次则这张表一年的数据量为 1亿条 每签到一次需要使用8 8 1 1 3 1共22 字节的内存一个月则最少需要600多字节这种方案内存消耗过大 我们可以采用类似这样的方案来实现我们的签到需求。 我们按月来统计用户签到信息签到记录为1未签到则记录为0. 把每一个bit位对应当月的每一天形成了映射关系。用0和1标示业务状态这种思路就称为位图BitMap。这样我们就用极小的空间来实现了大量数据的表示 Redis中是利用string类型数据结构实现BitMap因此最大上限是512M转换为bit则是 2^32个bit位。 BitMap的操作命令有 SETBIT向指定位置offset存入一个0或1 GETBIT 获取指定位置offset的bit值 BITCOUNT 统计BitMap中值为1的bit位的数量 BITFIELD 操作查询、修改、自增BitMap中bit数组中的指定位置offset的值 BITFIELD_RO 获取BitMap中bit数组并以十进制形式返回 BITOP 将多个BitMap的结果做位运算与 、或、异或 BITPOS 查找bit数组中指定范围内第一个0或1出现的位置 使用setbit进行赋值用于设置签到状态未赋值的会初始化成0 使用getbit来获取签到状态 实现签到功能 需求实现签到接口将当前用户当天签到信息保存到Redis中 思路我们可以把年和月作为bitMap的key然后保存到一个bitMap中每次签到就到对应的位上把数字从0变成1只要对应是1就表明说明这一天已经签到了反之则没有签到。 UserController PostMapping(/sign)public Result sign(){return userService.sign();}
UserServiceImpl
由于前端没有传递相应的时间参数我们只需要在后端自己获取即可
Override
public Result sign() {// 1.获取当前登录用户Long userId UserHolder.getUser().getId();// 2.获取日期LocalDateTime now LocalDateTime.now();// 3.拼接keyString keySuffix now.format(DateTimeFormatter.ofPattern(:yyyyMM));String key USER_SIGN_KEY userId keySuffix;// 4.获取今天是本月的第几天int dayOfMonth now.getDayOfMonth();// 5.写入Redis SETBIT key offset 1stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);return Result.ok();
}
由于今天是五号从左往右数第五位就是1 签到统计
从最后一次签到开始向前统计直到遇到第一次未签到为止计算总的签到次数就是连续签到天数。 Java逻辑代码获得当前这个月的最后一次签到数据定义一个计数器然后不停的向前统计直到获得第一个非0的数字即可每得到一个非0的数字计数器1直到遍历完所有的数据就可以获得当前月的签到总天数了 假设今天是10号那么我们就可以从当前月的第一天开始获得到当前这一天的位数是10号那么就是10位去拿这段时间的数据就能拿到所有的数据了那么这10天里边签到了多少次呢统计有多少个1即可。 我们只需要执行以下的redis命令即可 BITFIELD key GET u[dayOfMonth] 0 我们还要解决如何从后向前遍历这些比特位的问题 注意bitMap返回的数据是10进制哪假如说返回一个数字8那么我哪儿知道到底哪些是0哪些是1呢我们只需要让得到的10进制数字和1做与运算就可以了因为1只有遇见1 才是1其他数字都是0 我们把签到结果和1进行与操作每与一次就把签到结果向右移动一位依次内推我们就能完成逐个遍历的效果了。 需求实现下面接口统计当前用户截止当前时间在本月的连续签到天数
有用户有时间我们就可以组织出对应的key此时就能找到这个用户截止这天的所有签到记录再根据这套算法就能统计出来他连续签到的次数了 UserController
GetMapping(/sign/count)
public Result signCount(){return userService.signCount();
}
UserServiceImpl
Override
public Result signCount() {// 1.获取当前登录用户Long userId UserHolder.getUser().getId();// 2.获取日期LocalDateTime now LocalDateTime.now();// 3.拼接keyString keySuffix now.format(DateTimeFormatter.ofPattern(:yyyyMM));String key USER_SIGN_KEY userId keySuffix;// 4.获取今天是本月的第几天int dayOfMonth now.getDayOfMonth();// 5.获取本月截止今天为止的所有的签到记录返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0ListLong result stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));if (result null || result.isEmpty()) {// 没有任何签到结果return Result.ok(0);}Long num result.get(0);if (num null || num 0) {return Result.ok(0);}// 6.循环遍历int count 0;while (true) {// 6.1.让这个数字与1做与运算得到数字的最后一个bit位 // 判断这个bit位是否为0if ((num 1) 0) {// 如果为0说明未签到结束break;}else {// 如果不为0说明已签到计数器1count;}// 把数字右移一位抛弃最后一个bit位继续下一个bit位num 1;}return Result.ok(count);
}
UV统计
相关概念 UV全称Unique Visitor也叫独立访客量是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站只记录1次。 PV全称Page View也叫页面访问量或点击量用户每访问网站的一个页面记录1次PV用户多次打开页面则记录多次PV。往往用来衡量网站的流量。 通常来说UV会比PV大很多所以衡量同一个网站的访问量我们需要综合考虑很多因素所以我们只是单纯的把这两个值作为一个参考值 UV统计在服务端做会比较麻烦因为要判断该用户是否已经统计过了需要将统计过的用户信息保存。但是如果每个访问的用户都保存到Redis中数据量会非常恐怖那怎么处理呢 Hyperloglog(HLL)是从Loglog算法派生的概率算法用于确定非常大的集合的基数而不需要存储其所有值。相关算法原理大家可以参考HyperLogLog 算法的原理讲解以及 Redis 是如何应用它的 - 掘金 Redis中的HLL是基于string结构实现的单个HLL的内存永远小于16kb内存占用低的令人发指作为代价其测量结果是概率性的有小于0.81的误差。不过对于UV统计来说这完全可以忽略。 百万数据测试
测试代码 String[] users new String[1000];int index 0;for (int i 1; i 1000000; i) {index i % 1000;users[index] user_ i;if (i % 1000 0) {index 0;stringRedisTemplate.opsForHyperLogLog().add(hills, users);}}Long size stringRedisTemplate.opsForHyperLogLog().size(hills);System.out.println(size size);
未测试前redis的内存空间 测试之后发现确实内存消耗不大