用户签到

BitMap功能演示

背景
存储用户签到信息表
image.png
假设1000w用户,平均每人每年签到10此,一年数据量1亿。
每签到一次使用(8+8+1+1+3+1)22内存,一个月最多600多字节。

BitMap用法
按月统计用户签到信息,签到记录1、未签到0
image.png把每一个bit位对应当月每一天,形成映射关系。用0和1标示业务状态,这种思路称为位图(BitMap)
Redis中利用String类型数据结构实现BitMap,最大上限512M,转化为bit是2^32bit位
BitMap操作命令:
image.png

实现签到功能

image.png

  1. @Override
  2. public Result sign() {
  3. //1.获取当前用户登录信息
  4. Long userId = UserHolder.getUser().getId();
  5. //2.获取日期
  6. LocalDateTime now = LocalDateTime.now();
  7. //3.拼接key
  8. String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
  9. String key = USER_SIGN_KEY + userId + keySuffix;
  10. //4.获取今天是本月的第几天
  11. int dayOfMonth = now.getDayOfMonth();
  12. //5.写入Redis SETBIT key offset 1
  13. stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
  14. return Result.ok();
  15. }

统计连续签到

image.png

需求:实现接口,统计当前用户截止当前时间在本月连续签到天数
image.png

UserServiceImpl:

  1. @Override
  2. public Result signCount() {
  3. //1.获取当前用户登录信息
  4. Long userId = UserHolder.getUser().getId();
  5. //2.获取日期
  6. LocalDateTime now = LocalDateTime.now();
  7. //3.拼接key
  8. String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
  9. String key = USER_SIGN_KEY + userId + keySuffix;
  10. //4.获取今天是本月的第几天
  11. int dayOfMonth = now.getDayOfMonth();
  12. //5.获取本月截至今天为止的所有签到记录,返回是一个十进制数 BITFIELD GET u14 0
  13. List<Long> result = stringRedisTemplate.opsForValue().bitField(
  14. key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
  15. );
  16. //健壮性判断...
  17. if(result == null || result.isEmpty()){
  18. return Result.ok(0);
  19. }
  20. Long num = result.get(0);
  21. if(num == null || num ==0){
  22. return Result.ok(0);
  23. }
  24. //6.循环遍历
  25. int count = 0;
  26. while(true){
  27. //6.1.让这个数字与1做与运算,得到数字的最后一个bit位 判断这个bit位是否为0
  28. if((num & 1) == 0){
  29. //0.未签到,结束
  30. break;
  31. }else{
  32. //1.已签到,计数器+1
  33. count++;
  34. }
  35. //数字右移一位,抛弃最后一个bit位
  36. num >>>= 1;
  37. }
  38. return Result.ok(count);
  39. }

UV统计

背景:
image.png

HyperLogLog用法

image.png

实现UV统计

  1. @Test
  2. void testHyperLogLog() {
  3. String[] values = new String[1000];
  4. int j = 0;
  5. for (int i = 0; i < 1000000; i++) {
  6. j = i % 1000;
  7. values[j] = "user_" + i;
  8. if(j == 999){
  9. // 发送到Redis
  10. stringRedisTemplate.opsForHyperLogLog().add("hl2", values);
  11. }
  12. }
  13. // 统计数量
  14. Long count = stringRedisTemplate.opsForHyperLogLog().size("hl2");
  15. System.out.println("count = " + count);
  16. }