跳到主要内容

设备活跃、运行时长与留存统计

“设备活跃”“设备首次激活”“设备运行时长”是三个不同业务事实。活跃表示某周期出现过设备活动,首次激活来自设备档案,运行时长来自上报的开机区间。后续留存、流失及新增统计组合这些事实,不能把字段名相似当成口径相同。

活跃:按来源和周期去重​

saveDeviceActivityIfNotExist 先向 Redis 集合加入设备标识,首次加入后分别向日、月、年数据源写一条 TDengine 记录。ts 归一到周期开始,record_time 是便于筛选的数字日期;region_id 标记地区,device_id 关联设备主档案,ip/sdk_version 保留本次活动上下文。域名分发消费者调用相同入口,但选择独立来源。

uotaType当前源码含义库名族
1 / 缺省默认,聚合新旧 UOTAdevice_activity_day/month/year
2域名分发device_activity_day/month/year_uota2
3旧 UOTA,旧包名 com.android.netservicedevice_activity_day/month/year_uota_old
4新 UOTA,新包名 com.soft.updatedevice_activity_day/month/year_uota_new

表中斜杠表示三个独立数据库名称的展开,不是实际库名的一部分。12 个库均实测存在 device_activity_detail 超级表;普通列为 ts,data_key,mac,cpu,ip,device_id,sdk_version,TAG 为 record_time,region_id。tbname 是 TDengine 子表伪列,不是需要补建的普通字段。

子表当前由 DeviceActivityDetailBO.getTbname() 生成 {yyyyMMdd或yyyyMM或yyyy}_{regionId},而非旧注释中的 device_activity_detail_日期。data_key 由去掉冒号的 MAC 加可选 _CPU 组成;Redis 去重键的 MAC/CPU 拼接与此不同,因此迁移去重逻辑时不能只照抄数据库拼接规则。

物理字典入口:默认日、默认月、默认年、域名分发日、域名分发月、域名分发年、旧 UOTA 日、旧 UOTA 月、旧 UOTA 年、新 UOTA 日、新 UOTA 月、新 UOTA 年。

运行时长:区间明细与周期汇总​

DeviceRuntimeConsumer 接收上报区间,剔除结束时间不晚于开始时间的记录,将毫秒差换算为秒写 device_runtime.device_runtime_detail,同时形成日统计。管理端明细服务用于查询和导出,其普通新增/修改/删除接口明确不支持,不能因存在通用 CRUD 方法名便认为它是主要写入入口。

对象数据粒度与关联实测结构
device_runtime.device_runtime_detail每台设备的运行区间;子表名由 mac_cpu 生成start_time/end_time/device_duration 普通列,mac/cpu TAG;时长单位为秒
device_runtime_count_day.device_runtime_count每设备每日累计运行秒数ts,data_key,mac,cpu,device_duration 普通列,record_time TAG
device_runtime_count_month/year.device_runtime_count每设备每月/年统计查询对象同上;查询 record_time 使用月首 yyyyMM01、年首 yyyy0101
device_runtime_count_day_shadow.device_runtime_count重构时的日统计影子对象同上;已配置且实测存在
device_runtime.device_runtime同库额外超级表ts,data_key,mac,cpu,end_time,device_duration,record_time TAG;当前明细 DO 不映射它,生产/保留用途待确认

统计 DO 的子表名为 device_runtime_count_{record_time},data_key 为 MAC+CPU;tableName 标记 exist=false。不能把实体旧注释“包名+record_time”解释为统计按应用分表。

源码存在重构任务与主/影子 Mapper 路由:日影子 Mapper 有有效 @DS,月、年影子 Mapper 的 @DS 已注释,提供的配置也未列出月、年影子别名。本次仅证明日影子库存在,未执行重构任务,不能声称整套影子切换可用。源码还区分分页按日/月/年选 Mapper 与部分辅助方法固定日 Mapper,调用范围应以方法本身为准。

物理字典:明细库、日统计、月统计、年统计、日影子。

MySQL 统计结果:业务口径比字段名称更重要​

nebula_ids.device_model_activity_detail 按 base_day/source_type/device_model 描述型号活跃及新激活、死亡设备计数。source_type 的 0–14 代表 UOTA01/UOTA02 的并集、差集,再叠加巴伦/非巴伦筛选,不能与活跃接口 uotaType=1..4 共用一个枚举解释。

ik_yudao_device.device_month_activity_stat 是按基准月和对比月保存的报表结果。MonthActivityStatJob 从月度活跃集合和设备激活信息计算后入库,管理端读取结果。data_source=0 表示 UOTA、1 表示域名分发,与前面的 uotaType 编号再次不同。实库在 (data_source,bench_month) 上只有普通索引,没有按“来源+基准月+对比月”定义唯一约束。

字段组业务含义
bench_month/cmp_offset/cmp_month本次分析从哪个月出发、观察之后第几个月
bench_active_num/cmp_active_num两个月分别出现过活动的设备数
bench_new_act_num/cmp_new_act_num对应月份首次激活数,不等于新增活跃数
new_active_num对比月活跃而基准月不活跃,包含历史设备回归
bench_resurrect_num/bench_loss_num基准月设备在之后至对比月期间是否曾再次活跃,不只看对比月
loss_reactive_num基准月活跃,中间月均未活跃,对比月回归
both_active_num/new_act_both_active_num两月都活跃,以及基准月新激活设备在对比月的留存
cum_new_act_num/cum_loss_num/cum_new_active_num区间累计首次激活、累计流失、累计去重活跃

Mermaid Diagram Code:

flowchart LR
  Activity[周期活跃设备集合] --> Stat[月活对比计算]
  Registry[设备档案 activation_time] --> Stat
  Stat --> Result[device_month_activity_stat]
  Runtime[上报运行区间] --> Detail[运行明细]
  Runtime --> Day[运行日统计]

图中关联为应用计算,没有跨库物理 FK。本次不重新计算结果,因此“字段结构已核验”不等于“统计数值和源集合已核对”。

源码证据​

证据位置
来源枚举与字段D/dal/dataobject/deviceActivityDetail/DeviceActivityDetailDO.java:27
活跃去重、来源路由D/service/deviceActivityDetail/DeviceActivityDetailServiceImpl.java:224,288,485
活跃日期、子表名、业务键D/service/deviceActivityDetail/bo/DeviceActivityDetailBO.java:78,96,118
运行明细消费和写入D/kafka/consumer/DeviceRuntimeConsumer.java:46,73,163
时长子表名与字段D/dal/dataobject/deviceRuntime/DeviceRuntimeDetailDO.java:76;D/dal/dataobject/deviceRuntime/DeviceRuntimeCountDO.java:77
统计分页与影子路由D/service/deviceRuntime/DeviceRuntimeCountServiceImpl.java:69;D/service/deviceRuntime/DeviceRuntimeCountMapperRouter.java:53
型号口径、月活口径与计算D/dal/dataobject/modelactivitydetail/DeviceModelActivityDetailDO.java:24;D/dal/dataobject/monthactivitystat/DeviceMonthActivityStatDO.java:28;D/job/activity/month/MonthActivityStatJob.java:86,872
用户文档
AI 助手
Agent 列表
请选择一个 Agent 开始对话
AI 问答