首先了解用户行为,用户打开app说我要听音乐,后台推送音乐,前端进行播放,开始播放同时记录一条状态为1(开始播放状态)的日志;当用户点击暂停时,则前端暂停播放同时记录一条状态为2(暂停播放状态)的日志;当用户取消暂停时,则前端继续播放同时记录一条状态为1(开始播放状态)的日志,如果用户再次暂停则复用暂停逻辑;最后内容播完或则用户直接切歌,则记录一条状态为3(结束播放状态)的日志
总结出用户正常情况可能产生数据集合
- 1、3 开始——>结束
- 1,2,1,3 开始——>暂停——>开始——>结束
- 1,2,1,2,1,2,1,3 开始——>暂停——>开始——>暂停——>开始——>暂停——>开始——>结束(即暂停次数较多)
- 1,2,3 开始——>暂停——>结束
单曲循环时则以上数据集合根据真实情况进行组合,比如(1,3,1,2,1,3 开始——>结束——>开始——>暂停——>开始——>结束)
前端会10分钟批量上报埋点日志,后台首先将日志放入redis中进行缓存,使用的是list集合
后台定时进行异步消费
第一步:批量分页获取redis中的日志,将日志进行分组,即拆分出以uuid+内容+用户ID为准的日志集合(map集合,key为uuid+内容+用户ID,value为对应的日志List集合)
第二步:循环分组map集合,对每个分组下的日志集合进行垃圾数据清理(清理的标准验证是否满足上面用户正常情况可能产生数据集合场景)
循环这个日志集合:拿到当前日志跟下一条日志的状态进行比较
1、如果当前日志为播放,下一条日志也为播放时,则当前日志为垃圾数据,将当前日志所在下标存入移除下标集合中
2、如果当前日志为暂停,下一条日志也为暂停时,则下一条日志为垃圾数据,将下一条日志所在下标存入移除下标集合中
3、如果当前日志为结束,下一条日志也为结束时,则下一条日志为垃圾数据,将下一条日志所在下标存入移除下标集合中
最终找到所有需要移除的日志下标后,进行移除即可(查找垃圾数据下标代码如下图)
第三步:数据清理后,对清理后的数据进行循环计算
循环日志集合:根据当前日志状态和下一个日志状态进行比较
1、当前日志状态为播放,下一条日志状态为暂停或结束时,则累计播放时长
2、当前日志状态为暂停,下一条日志状态为开始或结束时,则累计暂停时长
循环完毕,最终得出播放时长和暂停时长(代码如下图)