当前位置: 首页 > news >正文

使用Redis统计网站的UV/DAU

HyperLogLog/BitMap

统计UV、DAU需要用到Redis的高级数据类型

M

public class RedisKeyUtil {private static final String PREFIX_UV = "uv";private static final String PREFIX_DAU = "dau";// a single day's UVpublic static String getUVKey(String date){return PREFIX_UV + SPLIT + date;}// a series of days' UVpublic static String getUVKey(String startDate, String endDate){return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;}// get the DAU of a single daypublic static String getDAUKey(String date){return PREFIX_DAU + SPLIT + date;}// get the DAU of a series of dayspublic static String getDAUKey(String startDate, String endDate){return PREFIX_DAU + SPLIT + startDate + SPLIT + endDate;}
}

C

@Service
public class DataService {@Autowiredprivate RedisTemplate redisTemplate;private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");// add the specified IP address to the UVpublic void recordUV(String ip){String redisKey = RedisKeyUtil.getUVKey(dateFormat.format(new Date()));redisTemplate.opsForHyperLogLog().add(redisKey, ip);}// query the specified range of days' UVpublic long calculateUV(Date start, Date end) {if(start == null || end == null){throw new IllegalArgumentException("start and end must not be null");}if(start.after(end)){throw new IllegalArgumentException("start date should be before end date");}// get all the keys of those daysList<String> keyList = new ArrayList<>();Calendar calendar = Calendar.getInstance();calendar.setTime(start);while(!calendar.getTime().after(end)){String redisKey = RedisKeyUtil.getUVKey(dateFormat.format(calendar.getTime()));keyList.add(redisKey);// add calendar to 1calendar.add(Calendar.DATE, 1);}// merge all the UV of those daysString redisKey = RedisKeyUtil.getUVKey(dateFormat.format(start), dateFormat.format(end));redisTemplate.opsForHyperLogLog().union(redisKey, keyList.toArray());// return the statistics resultreturn redisTemplate.opsForHyperLogLog().size(redisKey);}// add the specified user to the DAUpublic void recordDAU(int userId){String redisKey = RedisKeyUtil.getDAUKey(dateFormat.format(new Date()));redisTemplate.opsForValue().setBit(redisKey, userId, true);}// query the specified range of days' DAVpublic long calculateDAU(Date start, Date end){if(start == null || end == null){throw new IllegalArgumentException("start and end must not be null");}if(start.after(end)){throw new IllegalArgumentException("start date should be before end date");}// get all the keys of those daysList<byte[]> keyList = new ArrayList<>();Calendar calendar = Calendar.getInstance();calendar.setTime(start);while(!calendar.getTime().after(end)){String key = RedisKeyUtil.getDAUKey(dateFormat.format(calendar.getTime()));keyList.add(key.getBytes());// add calendar to 1calendar.add(Calendar.DATE, 1);}// or operationreturn (long) redisTemplate.execute(new RedisCallback() {@Overridepublic Object doInRedis(RedisConnection connection) throws DataAccessException {String redisKey = RedisKeyUtil.getDAUKey(dateFormat.format(start), dateFormat.format(end));connection.stringCommands().bitOp(RedisStringCommands.BitOperation.OR,redisKey.getBytes(), keyList.toArray(new byte[0][0]));return connection.stringCommands().bitCount(redisKey.getBytes());}});}
}

使用拦截器记录访问

@Component
public class DataInterceptor implements HandlerInterceptor{@Autowiredprivate DataService dataService;@Autowiredprivate HostHolder hostHolder;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// record into the UVString ip = request.getRemoteHost();dataService.recordUV(ip);// record into the DAUUser user = hostHolder.getUser();if(user != null){dataService.recordDAU(user.getId());}return true;}
}

配置拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate DataInterceptor dataInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(dataInterceptor).excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");}
}

V

@Controller
public class DataController {@Autowiredprivate DataService dataService;// the page of the statistics@RequestMapping(path = "/data", method = {RequestMethod.GET, RequestMethod.POST})public String getDataPage() {return "/site/admin/data";}// calculates the UV of the site
//    @PostMapping(path = "/data/uv")@RequestMapping(path = "/data/uv", method = {RequestMethod.GET/*, RequestMethod.POST*/})public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,@DateTimeFormat(pattern = "yyyy-MM-dd") Date end, Model model) {long uv = dataService.calculateUV(start, end);model.addAttribute("uvResult", uv);model.addAttribute("uvStartDate", start);model.addAttribute("uvEndDate", end);// `forward` means this function just disposal a half of the request,// and the rest of request need to be executed by other functions// post request still be post after forwardingreturn "forward:/data";}// calculates the DAU of the site
//    @PostMapping(path = "/data/dau")@RequestMapping(path = "/data/dau", method = {RequestMethod.GET/*, RequestMethod.POST*/})public String getDAU(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,@DateTimeFormat(pattern = "yyyy-MM-dd") Date end, Model model) {long dau = dataService.calculateDAU(start, end);model.addAttribute("dauResult", dau);model.addAttribute("dauStartDate", start);model.addAttribute("dauEndDate", end);// `forward` means this function just disposal a half of the request,// and the rest of request need to be executed by other functions// post request still be post after forwardingreturn "forward:/data";}
}
http://www.lryc.cn/news/143501.html

相关文章:

  • 【python】报错:ImportError: DLL load failed: 找不到指定的模块 的详细解决办法
  • SemrushBot蜘蛛爬虫屏蔽方式
  • 6 ssh面密登录
  • 基于微信小程序的汽车租赁系统的设计与实现ljx7y
  • 优化学习体验的在线考试系统
  • 1267. 统计参与通信的服务器
  • 【考研数学】矩阵、向量与线性方程组解的关系梳理与讨论
  • 打造个人的NAS云存储-通过Nextcloud搭建私有云盘实现公网远程访问
  • FFI绕过disable_functions
  • 53 个 CSS 特效 2
  • ubuntu学习(六)----文件编程实现cp指令
  • wireshark过滤器的使用
  • Zookeeper 脑裂问题
  • 计算机网络高频面试题解(一)
  • 从0-1的docker镜像服务构建
  • RabbitMQ、Kafka、RocketMQ:特点和适用场景对比
  • 【实战】十一、看板页面及任务组页面开发(四) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十六)
  • 解决docker无法执行定时任务问题
  • 【FreeRTOS】【STM32】中断详细介绍
  • stm32串口通信(PC--stm32;中断接收方式;附proteus电路图;开发方式:cubeMX)
  • 计算机毕设 基于机器学习与大数据的糖尿病预测
  • 【数据结构】——查找、散列表的相关习题
  • 提升Java开发效率:掌握HashMap的常见方法与基本原理
  • PostgreSQL系统概述
  • 掌握AI助手的魔法工具:解密Prompt(提示)在AIGC时代的应用「中篇」
  • git svn:使用 git 命令来管理 svn 仓库
  • 软考高级系统架构设计师系列论文九十一:论分布式数据库的设计与实现
  • GeoHash之存储篇
  • 后端项目开发:集成接口文档(swagger-ui)
  • 代码随想录训练营29天|●* 491.递增子序列 * 46.全排列 * 47.全排列 II