Files
CN_Tool/docs/superpowers/specs/2026-04-28-add-data-flicker-batch-design.md

14 KiB
Raw Blame History

电能质量 13 张表批量补数设计说明

1. 背景

tools/add-data 当前只有模块骨架和历史 SQL 文件 DATA_FLICKER.sql,尚未提供真实业务接口。

本次需求是在 add-data 模块中补齐一套“按时间区间批量生成电能质量数据并写入数据库”的能力,满足以下业务目标:

  • 支持按时间区间补数,例如一天、一月。
  • 支持时间戳步长选择:13510 分钟。
  • 支持单监测点和多监测点,前端可选择监测点 ID默认单监测点。
  • 支持批量写入,优先保证大区间补数时的效率。
  • 同一主键数据已存在时跳过,不覆盖、不删除。
  • 同步提供前端页面交互方案与参数展示规则。

2. 范围确认

根据当前 DATA_FLICKER.sql 内容,本次补数范围按 13 张表处理,而不是 14 张表:

  1. data_flicker
  2. data_fluc
  3. data_harmphasic_i
  4. data_harmphasic_v
  5. data_harmpower_p
  6. data_harmpower_q
  7. data_harmpower_s
  8. data_harmrate_i
  9. data_harmrate_v
  10. data_i
  11. data_inharm_i
  12. data_plt
  13. data_v

3. 已确认需求

本次设计基于以下已确认结论:

  • 写入方式是“按时间戳步长生成整段数据”,不是定时常驻写库。
  • 重复补数时采用“跳过已存在数据”策略。
  • 前端方案需要和后端接口一起设计。
  • 展示字段需要覆盖:
    • 电能质量参数名称
    • 相别
    • 是否合格
    • 最大值
    • 最小值
    • 平均值
    • 95%概率大值
    • 数据展示(保留小数)
  • 数值展示默认保留 2 位小数。
  • 相别参照用户提供图片中的“相别”列。

4. 关键约束

4.1 主键约束

13 张表均以 LINEID + TIMEID + PHASIC_TYPE 作为主键,重复写入时必须避免主键冲突导致整批失败。

4.2 相别字段长度约束

PHASIC_TYPE 字段长度为 varchar(2)。因此前端展示中的相别值和数据库实际落库值不能简单等同:

  • 页面展示可使用 TABCAB/BC/CA
  • 落库时必须拆分为真实可存储的 PHASIC_TYPE

4.3 数据量约束

当时间区间为“一月”、步长为“1 分钟”、监测点为“多选”时,补数规模会非常大,不能采用单条插入或一次性全量加载入内存的方式。

4.4 现有仓库约束

  • 当前仓库是后端工程,没有现成前端代码,本次只输出前端交互方案和接口契约。
  • 默认不执行 mvn 编译、打包、测试。
  • 修改范围应尽量收敛在 tools/add-data 模块内。

5. 方案选择

本次比较三种实现路径:

方案 A同步接口直接写库

特点:

  • 控制器接收参数后直接在请求线程中完成全部写库。
  • 实现最简单。

问题:

  • 大区间、多监测点时容易超时。
  • 任务执行中断后难以定位进度。
  • 前端体验差,无法明确看到当前执行状态。

结论:

不采用。

方案 B异步任务 + JDBC 批量写入

特点:

  • 请求只负责创建任务,后台异步执行。
  • 任务状态可轮询。
  • 批量写入时可按表、按批次提交。

优势:

  • 更适合月级、多监测点补数。
  • 可以精细控制批次大小。
  • 当前数据源连接串已开启 rewriteBatchedStatements=true,适合批处理。

结论:

采用该方案。

方案 C只生成 SQL 文件,人工执行

特点:

  • 后端只生成 SQL 脚本,不直接写库。

问题:

  • 需要人工执行,流程割裂。
  • 不符合“前端选择后直接补数”的目标。

结论:

不采用。

6. 总体设计

6.1 设计目标

tools/add-data 中新增一套“批量补数任务”能力,支持:

  • 前端提交补数参数
  • 后端预估本次写入规模
  • 后端异步生成数据并按表批量写入
  • 前端轮询任务状态
  • 前端获取参数展示规则

6.2 模块边界

本次能力只落在 tools/add-data,不向 systemuserdetection 扩散业务逻辑。

如需监测点列表,首版不假设存在基础监测点表,也不新增点位管理能力,直接由前端传入选中的 lineIds

6.3 接口拆分

建议把“任务管理”和“参数模板展示”分成两类接口:

  • 补数任务接口:负责预估、创建、状态查询
  • 模板展示接口:负责返回图片对应的参数展示规则

7. 数据模型与相别规则

7.1 展示相别与落库相别分离

前端展示相别来自用户图片中的“相别”列,但落库时需要展开成真正的 PHASIC_TYPE 值。

建议在模板中同时维护:

  • phaseDisplay:前端展示值
  • phaseCodes:落库使用的真实相别集合

7.2 相别展开规则

建议默认规则如下:

  • T -> ["T"]
  • ABC -> ["A", "B", "C"]
  • AB/BC/CA -> ["AB", "BC", "CA"]

这套规则同时用于:

  • 决定每个参数需要展开多少条写库数据
  • 决定前端参数表如何显示相别列

7.3 参数模板职责

参数模板不直接等于数据库表结构,而是承担以下职责:

  • 描述前端展示行
  • 绑定该参数对应的数据表
  • 描述展示相别和落库相别
  • 约定是否展示“是否合格”
  • 约定最大值、最小值、平均值、95%概率大值的展示逻辑
  • 约定保留小数位数,默认 2

8. 后端接口设计

8.1 预估接口

接口:

  • POST /addData/task/preview

作用:

  • 根据 lineIds、时间区间、时间戳步长,返回本次补数的预估规模

入参:

  • lineIds:监测点 ID 列表
  • startTime:开始时间
  • endTime:结束时间
  • intervalMinutes13510

返回内容:

  • 时间点数量
  • 监测点数量
  • 每张表预估写入条数
  • 总预估条数

8.2 创建任务接口

接口:

  • POST /addData/task/create

作用:

  • 创建一个批量补数任务,并立即进入后台执行

入参:

  • lineIds
  • startTime
  • endTime
  • intervalMinutes

返回内容:

  • taskId
  • 初始状态

说明:

  • 前端默认提交单个 lineId
  • 多监测点时前端直接提交多个 lineIds
  • 不单独拆分“单点接口”和“多点接口”

8.3 任务状态接口

接口:

  • GET /addData/task/status/{taskId}

作用:

  • 供前端轮询当前任务执行状态

返回内容:

  • 任务状态:WAITINGRUNNINGSUCCESSFAILED
  • 当前执行表名
  • 当前批次信息
  • 已写入条数
  • 已跳过条数
  • 失败条数
  • 失败原因
  • 开始时间、结束时间

8.4 参数模板接口

接口:

  • GET /addData/template/list

作用:

  • 返回前端页面参数规则表所需的静态配置

返回内容:

  • 电能质量参数名称
  • 相别展示值
  • 是否展示“是否合格”
  • 最大值规则
  • 最小值规则
  • 平均值规则
  • 95%概率大值规则
  • 保留小数位数

9. 后端分层设计

9.1 Controller 层

建议新增两个控制器:

  • AddDataTaskController
    • 补数任务相关接口
  • AddDataTemplateController
    • 参数模板查询接口

9.2 Service 层

建议拆分为:

  • AddDataTaskService
    • 创建任务
    • 状态查询
    • 预估规模
  • AddDataTemplateService
    • 返回前端参数模板

9.3 Component 层

建议新增以下组件:

  • AddDataTaskExecutor
    • 负责异步执行任务
  • AddDataBatchWriter
    • 负责按表批量写入
  • AddDataValueGenerator
    • 负责根据模板生成每条记录的值
  • AddDataTaskStatusHolder
    • 首版用内存保存任务状态
  • AddDataTemplateRegistry
    • 持有参数模板与相别映射

9.4 数据访问层

本次不建议为 13 张表分别创建超长 MyBatis XML 批量插入语句。

原因如下:

  • 宽表字段极多XML 可维护性差。
  • 13 张表结构差异大,重复代码很多。
  • 本次更偏工具型批处理写数,不适合以业务实体方式逐表建模。

建议采用:

  • JdbcTemplate
  • PreparedStatement
  • batchUpdate

在写入 SQL 上统一使用:

  • INSERT IGNORE

以满足“跳过已存在数据”的业务要求。

10. 批量写入策略

10.1 总体原则

批量写入必须满足以下原则:

  • 不先查存在再插入
  • 不整段数据一次性全部放入内存
  • 按表、按批次逐步提交
  • 主键冲突自动跳过

10.2 跳过已存在数据

采用 INSERT IGNORE 而不是以下策略:

  • 不采用“先查后写”,避免额外查询放大数据库压力
  • 不采用“覆盖更新”,与已确认需求不符
  • 不采用“先删后写”,避免误删

10.3 流式生成

建议按如下顺序流式生成:

  1. 先遍历时间点
  2. 再遍历监测点
  3. 再按模板展开相别
  4. 最后路由到对应表的批缓存

达到批次阈值后立即落库并清空当前缓存。

10.4 分批阈值

建议根据表宽度分层设置批次大小:

  • 窄表:500 ~ 1000 行/批
  • 宽表:100 ~ 200 行/批

其中以下表建议视为宽表:

  • data_harmphasic_i
  • data_harmphasic_v
  • data_harmpower_p
  • data_harmpower_q
  • data_harmpower_s
  • data_harmrate_i
  • data_harmrate_v
  • data_i
  • data_inharm_i
  • data_v

10.5 任务统计

任务执行过程中需累计以下统计值:

  • insertedCount
  • skippedCount
  • failedCount

其中:

  • insertedCount 表示本次真正插入成功的行数
  • skippedCount 表示因主键重复被忽略的行数
  • failedCount 表示非主键冲突导致的失败数量

11. 数据生成策略

11.1 首版原则

首版不引入复杂公式配置,不让前端传计算表达式。数据生成规则由后端内置。

11.2 生成方式

建议采用“基准值 + 受控扰动 + 派生字段回填”的方式生成数据:

  • 主值字段按基准值和随机扰动生成
  • 最大值字段不小于平均值
  • 最小值字段不大于平均值
  • 95%概率大值 对应 CP95 字段
  • 宽表中的谐波分量和派生列按统一规则回填

11.3 质量标识

QUALITYFLAG 首版建议统一使用固定有效值,例如 1

前端“是否合格”不直接读取数据库 QUALITYFLAG 的原始含义,而是走模板展示规则,避免把数据生成逻辑和展示文案硬耦合。

12. 前端页面交互方案

12.1 页面结构

建议页面分为两个区域:

  1. 补数任务区
  2. 参数规则展示区

12.2 补数任务区

表单项建议如下:

  • 监测点选择模式:单点 / 多点
  • 监测点 ID 选择框
  • 开始时间
  • 结束时间
  • 时间戳步长:13510 分钟
  • 预计写入量按钮
  • 开始补数按钮

交互说明:

  • 默认单监测点
  • 多监测点时切换为多选
  • 前端先调用预估接口,展示预计写入规模
  • 用户确认后再调用创建任务接口

12.3 任务状态展示

前端创建任务后轮询状态接口,建议展示:

  • 当前状态
  • 当前表名
  • 已写入数量
  • 已跳过数量
  • 失败数量
  • 失败原因
  • 开始时间
  • 结束时间

12.4 参数规则展示区

参数规则表按用户提供图片组织,至少展示以下列:

  • 电能质量参数名称
  • 相别
  • 显示
  • 最大值
  • 最小值
  • 平均值
  • 95%概率大值
  • 是否合格
  • 数据展示(保留小数)

其中:

  • 相别列使用 phaseDisplay
  • 所有数值默认保留 2 位小数
  • 该表展示的是模板规则,不是实时数据库统计结果

13. 文件结构建议

建议在 tools/add-data 下按现有仓库风格扩展:

tools/add-data/src/main/java/com/njcn/gather/tool/adddata/
├── controller
│   ├── AddDataTaskController.java
│   └── AddDataTemplateController.java
├── service
│   ├── AddDataTaskService.java
│   ├── AddDataTemplateService.java
│   └── impl
│       ├── AddDataTaskServiceImpl.java
│       └── AddDataTemplateServiceImpl.java
├── component
│   ├── AddDataTaskExecutor.java
│   ├── AddDataBatchWriter.java
│   ├── AddDataValueGenerator.java
│   ├── AddDataTaskStatusHolder.java
│   └── AddDataTemplateRegistry.java
└── pojo
    ├── param
    └── vo

如参数模板需落成资源文件,建议放在:

  • tools/add-data/src/main/resources/template/add-data-parameter-template.json

14. 非目标

本次不包含以下内容:

  • 不新增监测点基础信息管理能力
  • 不新增监测点字典表
  • 不新增数据库迁移框架
  • 不在 systemuser 模块中扩展通用任务中心
  • 不实现真实前端页面代码
  • 不做覆盖更新或先删后写逻辑

15. 风险与取舍

15.1 内存态任务状态的风险

首版如果使用内存保存任务状态:

  • 服务重启后任务状态会丢失
  • 适合当前工具型场景
  • 不适合后续演进为长期审计能力

当前取舍:

  • 首版接受该限制
  • 如果后续需要审计与追踪,再补任务表

15.2 模板与真实表字段映射的风险

用户图片中的参数项比“13 张表名”更偏业务视角,实际落库需要一层参数模板到表结构的映射。

当前取舍:

  • 首版把模板规则集中维护在 AddDataTemplateRegistry
  • 不在前端直接拼接数据库字段名

15.3 大批量写入的数据库压力

多监测点、长区间、1 分钟步长时数据库压力会很大。

当前取舍:

  • 采用预估接口提前提示规模
  • 控制批次大小
  • 使用异步执行与 INSERT IGNORE

16. 验证方式

本次设计和后续实现默认不执行 mvn,验证方式以静态检查和链路闭合检查为主。

16.1 设计验证

确认以下设计点闭合:

  • 13 张表范围明确
  • 相别展示与落库规则明确
  • 重复数据处理策略明确
  • 前后端接口契约明确
  • 批量写入策略明确

16.2 实现后验证

后续实现时重点检查:

  • 入参校验是否覆盖时间区间、步长、监测点 ID 列表
  • 预估条数计算是否正确
  • SQL 是否统一使用 INSERT IGNORE
  • 批次是否按宽表和窄表区分
  • 重复补数时是否正确累加 skippedCount
  • 参数模板返回是否与图片字段一致

17. 结论

本次采用“异步任务 + JDBC 批量写入 + 参数模板展示接口”的实现方案,在 tools/add-data 模块内完成电能质量 13 张表的批量补数能力。

该方案兼顾以下目标:

  • 支持单监测点和多监测点
  • 支持日级、月级区间
  • 支持 1/3/5/10 分钟时间戳步长
  • 支持重复补数时跳过已存在数据
  • 支持前端按图片规则展示参数和相别
  • 在当前仓库约束下把改动范围控制在最小必要集合