跳到主要内容

安装应用快照与检索设计

具体索引选择、单月查询、JSON 包名详情、分区及排序边界见 大数据查询指南。

安装应用业务回答“某设备在某月最近一次上报时安装了哪些应用”,以及“某应用版本覆盖多少设备”。它不等同于 task 服务的应用投放执行结果:收到安装清单可以说明清单内容,不能自动证明某次下发任务执行成功。当前消费者中曾经关联任务安装结果的旧代码已经注释。

从设备上报到管理端查询​

AppInstallListConsumer 接收安装列表事件,按服务接收时间确定 yyyyMM。开启入库开关后,确保当月表存在,把整份安装列表序列化为 apps,写入 app_install_device{yyyyMM}。Mapper 使用 ON DUPLICATE KEY UPDATE 语义维护设备当月快照;数据变更消息再由 AppInstallDeviceMysqlToEsConsumer 投影到同月份 ES 索引。管理端可按月、设备及应用内容查询,导出通过 task 导出 API 编排。

Mermaid Diagram Code:

flowchart LR
  Event[设备安装列表事件] --> Consumer[AppInstallListConsumer]
  Consumer --> Snapshot[MySQL 月表: 设备安装快照]
  Snapshot --> CDC[数据库变更消息]
  CDC --> ES[ES 月索引: 应用内容检索]
  Snapshot --> Expand[设备快照展开任务]
  Expand --> Package[按包名明细月表]
  Package --> Job[安装统计任务]
  Job --> Count[按月份与应用版本统计]
  Query[管理端查询与导出] --> Snapshot
  Query --> ES
对象业务粒度关键字段及原因
ik_app_install.app_install_device{yyyyMM}每月每设备快照mac/cpu_id 标识设备,apps 保留完整列表 JSON 字符串,app_count 便于筛选,last_undate_Time 保留上报时间,partition_index 配合分区访问
ik_app_install.app_install_count_package应用、版本、月份的统计结果package_name/version_code/version_name/month/device_count 表示覆盖情况;不是一台设备一条记录
源码 app_install_package{yyyyMM}按应用展开的设备安装明细package_name、MAC/CPU、版本、系统应用标识等;本次实际库未发现该系列,不能作为已部署对象陈述
nebula_ids.sys_app_package_name包名说明和别名customize_app_name/describe/status/del_flag 用于维护展示含义,不承担安装明细统计
ES app_install_device{yyyyMM}每月设备快照的检索投影apps 支持全文检索,MAC 有分词/精确子字段;文档 _id 映射实体 id

分表、分区与索引​

源码 MyBatis 动态表名拦截器将指定表名追加年月后缀;AppInstallUtil.getTableSuffix、服务的 setTableSuffix/clearTableSuffix 负责传递月份。真实名字为 app_install_device202609,中间没有下划线。本次库内存在 202606、202607、202608、202609 四个月表和一张 count 表。

AppInstallUtil 使用 MAC+CPU 哈希计算 1–150 的 partition_index。实测月表主键为 (id,partition_index),唯一键为 (mac,cpu_id,partition_index),因此只凭实体的单个 id 注解不能完整表达数据库唯一性。补采确认 202606–202609 四张月表均为 LIST(partition_index)、每表 150 个分区。查询应先限定业务月份,再由同一算法计算分区号;源码是否传入条件及边界见查询指南。

包名明细工具仍保留按月建表及包名分区能力(特殊包单独编号,其余 59 桶),但当前安装列表消费者直接写设备快照,并未逐应用写包名明细。源码的 appInstallDeviceToPackage 定时任务负责将快照展开为按包名明细,appinstallCountByPackageName 再从包名明细分区统计并写入 count 表;两步是否在测试环境调度运行未核验。AppInstallPackageMapper 仍有查询和维护逻辑;“实库缺少”属于当前代码与部署结构的差异,不能直接判为线上必定报错或应删表。

设备安装详情也可以直接由 Mapper 的 JSON_TABLE(t.apps, '$[*]') 展开,并不依赖每次都先生成包名明细表;这是整份快照和行式明细并存的原因。AppInstallCountPackageMapper.xml 还使用完整库名同时查询 ik_app_install.app_install_count_package 和 nebula_ids.sys_app_package_name,形成显式跨库依赖。将来迁库仅修改 appInstall 数据源别名不足以解除这一依赖。

当前演进差异​

MySQL 字段历史拼写 last_undate_Time 与 Java lastUndateTime、ES last_undate_time 均保留。“undate”“isSysteApp”不能为了文档美观悄悄改成另一个字段名。MySQL 列名大小写差异本身不代表缺列。

ES 实测有 app_install_device202503 至 202609 共 19 个月索引,另有无后缀索引和 app_install_device_s0。这大于当前 MySQL 月表范围,反映两端保留对象范围不同;没有扫描记录,不能认定数据完全同步或已经归档。

  • 2025 月索引的 cpu_id 为 keyword、时间字段为 date。
  • 202601 除下划线字段外,还并存 appCount/cpuId/createTime/lastUndateTime/updateTime 等驼峰字段,其中时间为 text。
  • 202602–202609 的 cpu_id、三个时间字段为 text,与实体的精确标识/日期语义和早期 mapping 不一致;跨月筛选、排序、聚合需按实际 mapping 评估。
  • 无后缀及 _s0 索引的确存在,但当前按月服务调用不能证明它们仍被写入;保留为待确认对象。

详见 安装 MySQL 字典、当月 ES 字典、过渡月份 ES 字典。

源码证据​

证据位置
上报接收、入库开关、旧任务回写已注释D/kafka/consumer/AppInstallListConsumer.java:35,38,47
动态月表写入和查询D/service/appinstalldevice/AppInstallDeviceServiceImpl.java:65,107,152
数据源绑定D/dal/mysql/appinstalldevice/AppInstallDeviceMapper.java:29;D/dal/mysql/appinstallpackage/AppInstallPackageMapper.java:31
建表及分区算法D/utils/AppInstallUtil.java:34,59,64,124,353
展开与汇总任务D/job/AppInstallListJob.java:72,118,250
JSON 展开与跨库查询R/mapper/appinstalldevice/AppInstallDeviceMapper.xml:12;R/mapper/appinstallpackage/AppInstallCountPackageMapper.xml:19,23
ES 同步和按月索引D/kafka/consumer/AppInstallDeviceMysqlToEsConsumer.java:36;D/service/appinstalldevice/AppInstallDeviceEsServiceServiceImpl.java:32
动态表名拦截器F/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java:60

以上描述当前源代码,不表示本次执行了建表、消费、同步或统计任务。

用户文档
AI 助手
Agent 列表
请选择一个 Agent 开始对话
AI 问答