libilibi项目总结(16)数据统计、查询

server/2024/12/21 15:04:41/

statistics_info

CREATE TABLE `statistics_info` (`statistics_date` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '统计日期',`user_id` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户ID',`data_type` tinyint(1) NOT NULL COMMENT '数据统计类型',`statistics_count` int DEFAULT NULL COMMENT '统计数量',PRIMARY KEY (`statistics_date`,`user_id`,`data_type`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='数据统计';

定时任务统计数据

java">//每晚12点统计
@Scheduled(cron = "0 0 0 * * ?")public void statisticsData() {statisticsInfoService.statisticsData();}

statisticsInfoService.statisticsData();

java">	@Overridepublic void statisticsData() {List<StatisticsInfo> statisticsInfoList = new ArrayList<>();final String statisticsDate = DateUtil.getBeforeDayDate(1);//统计播放量Map<String, Integer> videoPlayCountMap = redisComponent.getVideoPlayCount(statisticsDate);List<String> playVideoKeys = new ArrayList<>(videoPlayCountMap.keySet());//去除前缀,得到视频id//例如easylive:video:playcount:2024-11-23:41bMMoxp70//转为41bMMoxp70playVideoKeys = playVideoKeys.stream().map(item -> item.substring(item.lastIndexOf(":") + 1)).collect(Collectors.toList());//根据视频id列表查询视频列表VideoInfoQuery videoInfoQuery = new VideoInfoQuery();videoInfoQuery.setVideoIdArray(playVideoKeys.toArray(new String[playVideoKeys.size()]));List<VideoInfo> videoInfoList = videoInfoMapper.selectList(videoInfoQuery);//生成<userId,videoCount>Map集合Map<String, Integer> videoCountMap = videoInfoList.stream().collect(Collectors.groupingBy(VideoInfo::getUserId,Collectors.summingInt(item -> videoPlayCountMap.get(Constants.REDIS_KEY_VIDEO_PLAY_COUNT + statisticsDate + ":" + item.getVideoId()))));videoCountMap.forEach((k, v) -> {StatisticsInfo statisticsInfo = new StatisticsInfo();statisticsInfo.setStatisticsDate(statisticsDate);statisticsInfo.setUserId(k);statisticsInfo.setDataType(StatisticsTypeEnum.PLAY.getType());statisticsInfo.setStatisticsCount(v);statisticsInfoList.add(statisticsInfo);});//统计粉丝量List<StatisticsInfo> fansDataList = this.statisticsInfoMapper.selectStatisticsFans(statisticsDate);for (StatisticsInfo statisticsInfo : fansDataList) {statisticsInfo.setStatisticsDate(statisticsDate);statisticsInfo.setDataType(StatisticsTypeEnum.FANS.getType());}statisticsInfoList.addAll(fansDataList);//统计评论List<StatisticsInfo> commentDataList = this.statisticsInfoMapper.selectStatisticsComment(statisticsDate);for (StatisticsInfo statisticsInfo : commentDataList) {statisticsInfo.setStatisticsDate(statisticsDate);statisticsInfo.setDataType(StatisticsTypeEnum.COMMENT.getType());}statisticsInfoList.addAll(commentDataList);//统计 弹幕、点赞、收藏、投币List<StatisticsInfo> statisticsInfoOthers = this.statisticsInfoMapper.selectStatisticsInfo(statisticsDate,new Integer[]{UserActionTypeEnum.VIDEO_LIKE.getType(), UserActionTypeEnum.VIDEO_COIN.getType(), UserActionTypeEnum.VIDEO_COLLECT.getType()});for (StatisticsInfo statisticsInfo : statisticsInfoOthers) {statisticsInfo.setStatisticsDate(statisticsDate);if (UserActionTypeEnum.VIDEO_LIKE.getType().equals(statisticsInfo.getDataType())) {statisticsInfo.setDataType(StatisticsTypeEnum.LIKE.getType());} else if (UserActionTypeEnum.VIDEO_COLLECT.getType().equals(statisticsInfo.getDataType())) {statisticsInfo.setDataType(StatisticsTypeEnum.COLLECTION.getType());} else if (UserActionTypeEnum.VIDEO_COIN.getType().equals(statisticsInfo.getDataType())) {statisticsInfo.setDataType(StatisticsTypeEnum.COIN.getType());}}statisticsInfoList.addAll(statisticsInfoOthers);this.statisticsInfoMapper.insertOrUpdateBatch(statisticsInfoList);}

这段代码是一个定时任务,用于每天统计并记录用户在平台上的各种行为数据,主要包括播放量、粉丝量、评论量、点赞量、收藏量、投币量等。统计结果会被保存到statistics_info表中。

1. 表结构分析 (statistics_info)

statistics_info记录了用户的各类行为数据,包含以下字段:

  • statistics_date:统计日期,格式为yyyy-MM-dd
  • user_id:用户ID。
  • data_type:数据类型,使用数字表示不同的统计类型(如播放量、评论、点赞等)。
  • statistics_count:统计数量,记录该类型行为发生的次数或数量。

表的主键statistics_date + user_id + data_type,保证了每个用户在每一天每种数据类型的唯一性。

2. 定时任务 (@Scheduled(cron = "0 0 0 * * ?"))

这段代码使用了Spring的定时任务注解@Scheduled,使得statisticsData()方法每天在午夜12点(即00:00)自动执行,进行数据统计。cron表达式"0 0 0 * * ?"表示每天的0点0分0秒执行。

3. statisticsData() 方法分析

(1) 获取统计日期
java">final String statisticsDate = DateUtil.getBeforeDayDate(1);

这里获取的是前一天的日期,并将其作为统计日期。方法DateUtil.getBeforeDayDate(1)返回的是当前日期的前一天。

(2) 统计播放量
java">Map<String, Integer> videoPlayCountMap = redisComponent.getVideoPlayCount(statisticsDate);

从Redis中获取前一天所有视频的播放量数据。返回的是一个Map,键是视频的Redis键(例如 easylive:video:playcount:2024-11-23:41bMMoxp70),值是视频的播放次数。

java">List<String> playVideoKeys = new ArrayList<>(videoPlayCountMap.keySet());
playVideoKeys = playVideoKeys.stream().map(item -> item.substring(item.lastIndexOf(":") + 1)).collect(Collectors.toList());

提取视频ID(即去掉Redis键的前缀部分),得到一个只包含视频ID的列表。

java">VideoInfoQuery videoInfoQuery = new VideoInfoQuery();
videoInfoQuery.setVideoIdArray(playVideoKeys.toArray(new String[0]));
List<VideoInfo> videoInfoList = videoInfoMapper.selectList(videoInfoQuery);

根据提取到的视频ID,查询数据库,获取对应的VideoInfo对象。每个VideoInfo包含视频的详细信息,其中最重要的是视频所属的用户ID。

java">Map<String, Integer> videoCountMap = videoInfoList.stream().collect(Collectors.groupingBy(VideoInfo::getUserId,Collectors.summingInt(item -> videoPlayCountMap.get(Constants.REDIS_KEY_VIDEO_PLAY_COUNT + statisticsDate + ":" + item.getVideoId()))));

根据视频信息生成一个Map<String, Integer>,其中键是用户ID,值是该用户视频的总播放量。groupingBy按用户ID分组,并通过summingInt将相同用户的视频的播放量累加起来。

java">videoCountMap.forEach((k, v) -> {StatisticsInfo statisticsInfo = new StatisticsInfo();statisticsInfo.setStatisticsDate(statisticsDate);statisticsInfo.setUserId(k);statisticsInfo.setDataType(StatisticsTypeEnum.PLAY.getType());statisticsInfo.setStatisticsCount(v);statisticsInfoList.add(statisticsInfo);
});

根据统计结果构造StatisticsInfo对象,并将其加入到statisticsInfoList中。这些对象记录了每个用户的播放量。

(3) 统计粉丝量
java">List<StatisticsInfo> fansDataList = this.statisticsInfoMapper.selectStatisticsFans(statisticsDate);

通过statisticsInfoMapper查询出前一天所有用户的粉丝量。

java">for (StatisticsInfo statisticsInfo : fansDataList) {statisticsInfo.setStatisticsDate(statisticsDate);statisticsInfo.setDataType(StatisticsTypeEnum.FANS.getType());
}
statisticsInfoList.addAll(fansDataList);

设置统计日期为前一天,数据类型设置为粉丝量,然后将查询到的粉丝数据加入到统计列表。

(4) 统计评论量
java">List<StatisticsInfo> commentDataList = this.statisticsInfoMapper.selectStatisticsComment(statisticsDate);

查询出前一天的评论量数据。

java">for (StatisticsInfo statisticsInfo : commentDataList) {statisticsInfo.setStatisticsDate(statisticsDate);statisticsInfo.setDataType(StatisticsTypeEnum.COMMENT.getType());
}
statisticsInfoList.addAll(commentDataList);

设置数据类型为评论量,并将数据加入到统计列表。

(5) 统计弹幕、点赞、收藏、投币
java">List<StatisticsInfo> statisticsInfoOthers = this.statisticsInfoMapper.selectStatisticsInfo(statisticsDate,new Integer[]{UserActionTypeEnum.VIDEO_LIKE.getType(), UserActionTypeEnum.VIDEO_COIN.getType(), UserActionTypeEnum.VIDEO_COLLECT.getType()});

查询出前一天的点赞投币收藏等行为的数据。

java">for (StatisticsInfo statisticsInfo : statisticsInfoOthers) {statisticsInfo.setStatisticsDate(statisticsDate);if (UserActionTypeEnum.VIDEO_LIKE.getType().equals(statisticsInfo.getDataType())) {statisticsInfo.setDataType(StatisticsTypeEnum.LIKE.getType());} else if (UserActionTypeEnum.VIDEO_COLLECT.getType().equals(statisticsInfo.getDataType())) {statisticsInfo.setDataType(StatisticsTypeEnum.COLLECTION.getType());} else if (UserActionTypeEnum.VIDEO_COIN.getType().equals(statisticsInfo.getDataType())) {statisticsInfo.setDataType(StatisticsTypeEnum.COIN.getType());}
}
statisticsInfoList.addAll(statisticsInfoOthers);

将查询到的行为数据类型根据不同的UserActionTypeEnum做转换,设置数据类型为点赞收藏投币,并加入到统计列表中。

(6) 批量插入或更新数据
java">this.statisticsInfoMapper.insertOrUpdateBatch(statisticsInfoList);

最后,将收集到的所有统计数据(包括播放量、粉丝量、评论量、行为量等)批量插入或更新到statistics_info表中。

总结:

这段代码通过定时任务每天统计用户的各类行为数据,包括播放量、粉丝量、评论量、点赞量、投币量等。统计数据从Redis中获取并结合数据库中的视频信息,生成统计结果,并最终存入数据库表中。这些数据可以用于后续的分析、展示或其他业务需求。

获取前一天的数据

controller

java">	//获取前一天的数据@RequestMapping("/getActualTimeStatisticsInfo")@GlobalInterceptorpublic ResponseVO getActualTimeStatisticsInfo() {//获取前一天的日期String preDate = DateUtil.getBeforeDayDate(1);TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();StatisticsInfoQuery param = new StatisticsInfoQuery();param.setStatisticsDate(preDate);param.setUserId(tokenUserInfoDto.getUserId());List<StatisticsInfo> preDayData = statisticsInfoService.findListByParam(param);//根据数据类型和数据对应的数量构建mapMap<Integer, Integer> preDayDataMap = preDayData.stream().collect(Collectors.toMap(StatisticsInfo::getDataType, StatisticsInfo::getStatisticsCount, (item1, item2) -> item2));//web端查询粉丝数,后台查询总数量Map<String, Integer> totalCountInfo = statisticsInfoService.getStatisticsInfoActualTime(tokenUserInfoDto.getUserId());Map<String, Object> result = new HashMap<>();result.put("preDayData", preDayDataMap);result.put("totalCountInfo", totalCountInfo);//测试定时任务使用statisticsInfoService.statisticsData();return getSuccessResponseVO(result);}
Map<String, Integer> totalCountInfo = statisticsInfoService.getStatisticsInfoActualTime(tokenUserInfoDto.getUserId());
java">	@Overridepublic Map<String, Integer> getStatisticsInfoActualTime(String userId) {Map<String, Integer> result = statisticsInfoMapper.selectTotalCountInfo(userId);if (!StringTools.isEmpty(userId)) {//查询粉丝数result.put("userCount", userFocusMapper.selectFansCount(userId));} else {//管理端查询用户总数result.put("userCount", userInfoMapper.selectCount(new UserInfoQuery()));}return result;}

获取一周的数据

controller

java">	//获取一周的数据@RequestMapping("/getWeekStatisticsInfo")@GlobalInterceptorpublic ResponseVO getWeekStatisticsInfo(Integer dataType) {TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();List<String> dateList = DateUtil.getBeforeDates(7);StatisticsInfoQuery param = new StatisticsInfoQuery();//设置数据类型param.setDataType(dataType);param.setUserId(tokenUserInfoDto.getUserId());param.setStatisticsDateStart(dateList.get(0));param.setStatisticsDateEnd(dateList.get(dateList.size() - 1));param.setOrderBy("statistics_date asc");List<StatisticsInfo> statisticsInfoList = statisticsInfoService.findListByParam(param);//按照日期分组Map<String, StatisticsInfo> dataMap =statisticsInfoList.stream().collect(Collectors.toMap(item -> item.getStatisticsDate(), Function.identity(), (data1, data2) -> data2));List<StatisticsInfo> resultDataList = new ArrayList<>();for (String date : dateList) {StatisticsInfo dataItem = dataMap.get(date);//没有数据就设为默认0if (dataItem == null) {dataItem = new StatisticsInfo();dataItem.setStatisticsCount(0);dataItem.setStatisticsDate(date);}resultDataList.add(dataItem);}return getSuccessResponseVO(resultDataList);}

后台获取实时数据

java">	//获取实时数据@RequestMapping("/getActualTimeStatisticsInfo")public ResponseVO getActualTimeStatisticsInfo() {String preDate = DateUtil.getBeforeDayDate(1);StatisticsInfoQuery param = new StatisticsInfoQuery();param.setStatisticsDate(preDate);List<StatisticsInfo> preDayData = statisticsInfoService.findListTotalInfoByParam(param);//查询用户总数,替换类型为粉丝的数量Integer userCount = userInfoService.findCountByParam(new UserInfoQuery());preDayData.forEach(item -> {if (StatisticsTypeEnum.FANS.getType().equals(item.getDataType())) {item.setStatisticsCount(userCount);}});//根据数据类型和数据对应的数量构建mapMap<Integer, Integer> preDayDataMap = preDayData.stream().collect(Collectors.toMap(StatisticsInfo::getDataType, StatisticsInfo::getStatisticsCount, (item1,item2) -> item2));Map<String, Integer> totalCountInfo = statisticsInfoService.getStatisticsInfoActualTime(null);Map<String, Object> result = new HashMap<>();result.put("preDayData", preDayDataMap);result.put("totalCountInfo", totalCountInfo);return getSuccessResponseVO(result);}

获取这一周的数据

controller

java">//获取这一周的数据@RequestMapping("/getWeekStatisticsInfo")public ResponseVO getWeekStatisticsInfo(Integer dataType) {List<String> dateList = DateUtil.getBeforeDates(7);List<StatisticsInfo> statisticsInfoList = new ArrayList<>();StatisticsInfoQuery param = new StatisticsInfoQuery();param.setDataType(dataType);param.setStatisticsDateStart(dateList.get(0));param.setStatisticsDateEnd(dateList.get(dateList.size() - 1));param.setOrderBy("statistics_date asc");if (!StatisticsTypeEnum.FANS.getType().equals(dataType)) {statisticsInfoList = statisticsInfoService.findListTotalInfoByParam(param);} else {statisticsInfoList = statisticsInfoService.findUserCountTotalInfoByParam(param);}//根据数据类型进行分组Map<String, StatisticsInfo> dataMap = statisticsInfoList.stream().collect(Collectors.toMap(item -> item.getStatisticsDate(), Function.identity(), (data1,data2) -> data2));List<StatisticsInfo> resultDataList = new ArrayList<>();for (String date : dateList) {StatisticsInfo dataItem = dataMap.get(date);if (dataItem == null) {dataItem = new StatisticsInfo();dataItem.setStatisticsCount(0);dataItem.setStatisticsDate(date);}resultDataList.add(dataItem);}return getSuccessResponseVO(resultDataList);}

xml

<select id="selectListTotalInfoByParam" resultMap="base_result_map">select ifnull(sum(statistics_count),0) statistics_count,statistics_date,data_type from statistics_info s group by data_type,statistics_date</select><select id="selectUserCountTotalInfoByParam" resultMap="base_result_map">select count(1) statistics_count,DATE_FORMAT(join_time,'%Y-%m-%d') statistics_date from user_info group by statistics_date order by statistics_date asc</select>

http://www.ppmy.cn/server/151971.html

相关文章

javaScript中slice()和splice()的用法与区别

定义和功能 slice()方法&#xff1a; slice()方法用于从一个数组&#xff08;或字符串&#xff09;中提取指定范围的元素&#xff08;或字符&#xff09;&#xff0c;它不会改变原始数组&#xff08;或字符串&#xff09;&#xff0c;而是返回一个新的数组&#xff08;或字符串…

基础二层交换组网(静态IP)

拓扑图 实验目的 掌握并了解网络中静态IP默认无路由影响的情况。 实验过程 1.创建拓扑 2.配置PC1、PC2 IP地址 PC1&#xff1a; IP地址&#xff1a;192.168.0.1 子网掩码&#xff1a;255.255.255.0PC2&#xff1a; IP地址&#xff1a;192.168.0.2 子网掩码&#xff1a;255.…

开启新征程——QML

文章目录 前言什么是 QML&#xff1f;QML 的主要特点&#xff1a; 什么是 Qt Quick&#xff1f;Qt Quick 的主要特点&#xff1a; QML 与 C 的结合开发工具总结 文章目录 前言什么是 QML&#xff1f;QML 的主要特点&#xff1a; 什么是 Qt Quick&#xff1f;Qt Quick 的主要特点…

计算机网络基础--WebSocket

什么是 WebSocket? WebSocket 是一种基于 TCP 连接的全双工通信协议&#xff0c;即客户端和服务器可以同时发送和接收数据。 WebSocket 协议在 2008 年诞生&#xff0c;2011 年成为国际标准&#xff0c;几乎所有主流较新版本的浏览器都支持该协议。不过&#xff0c;WebSocke…

新能源汽车产销数据分析

新能源汽车产销数据分析 一、读取数据1.打印表头信息2.查看前几行数据3.打印数据基本统计信息4.检查缺失值情况5.缺失值处理方法二、绘图1.统计"车型大类"的分布2.制造厂累计销量对比&#xff08;前90%&#xff09;3.当期销量随时间变化折线图4.累计同比分布箱线图5.…

js 中数组、对象遍历方法总结

文章目录 数组方法类数组及对象应用对象应用补充 数组方法 push() 功能&#xff1a;向数组的末尾添加一个或多个元素&#xff0c;并返回新的长度。示例&#xff1a; let arr [1, 2, 3]; let newLength arr.push(4); console.log(arr); // [1, 2, 3, 4] console.log(newLengt…

ESP32单片机开发

目录 一、ESP32 单片机的初印象 &#xff08;一&#xff09;基本概念解读 &#xff08;二&#xff09;开发环境搭建 1. Arduino IDE 2. ESP-IDF 二、ESP32 单片机开发语言知多少 三、ESP32 单片机开发常见问题及解决 &#xff08;一&#xff09;硬件连接相关问题 &…

四、CSS3

一、CSS3简介 1、CSS3概述 CSS3 是 CSS2 的升级版本&#xff0c;他在CSS2的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题。 CSS在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …