tools: add add-data batch design spec
This commit is contained in:
@@ -0,0 +1,603 @@
|
||||
# 电能质量 13 张表批量补数设计说明
|
||||
|
||||
## 1. 背景
|
||||
|
||||
`tools/add-data` 当前只有模块骨架和历史 SQL 文件 [DATA_FLICKER.sql](D:/Work/SourceCode/CN_Tool/tools/add-data/DATA_FLICKER.sql),尚未提供真实业务接口。
|
||||
|
||||
本次需求是在 `add-data` 模块中补齐一套“按时间区间批量生成电能质量数据并写入数据库”的能力,满足以下业务目标:
|
||||
|
||||
- 支持按时间区间补数,例如一天、一月。
|
||||
- 支持时间戳步长选择:`1`、`3`、`5`、`10` 分钟。
|
||||
- 支持单监测点和多监测点,前端可选择监测点 ID,默认单监测点。
|
||||
- 支持批量写入,优先保证大区间补数时的效率。
|
||||
- 同一主键数据已存在时跳过,不覆盖、不删除。
|
||||
- 同步提供前端页面交互方案与参数展示规则。
|
||||
|
||||
## 2. 范围确认
|
||||
|
||||
根据当前 [DATA_FLICKER.sql](D:/Work/SourceCode/CN_Tool/tools/add-data/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)`。因此前端展示中的相别值和数据库实际落库值不能简单等同:
|
||||
|
||||
- 页面展示可使用 `T`、`ABC`、`AB/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`,不向 `system`、`user`、`detection` 扩散业务逻辑。
|
||||
|
||||
如需监测点列表,首版不假设存在基础监测点表,也不新增点位管理能力,直接由前端传入选中的 `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`:结束时间
|
||||
- `intervalMinutes`:`1`、`3`、`5`、`10`
|
||||
|
||||
返回内容:
|
||||
|
||||
- 时间点数量
|
||||
- 监测点数量
|
||||
- 每张表预估写入条数
|
||||
- 总预估条数
|
||||
|
||||
### 8.2 创建任务接口
|
||||
|
||||
接口:
|
||||
|
||||
- `POST /addData/task/create`
|
||||
|
||||
作用:
|
||||
|
||||
- 创建一个批量补数任务,并立即进入后台执行
|
||||
|
||||
入参:
|
||||
|
||||
- `lineIds`
|
||||
- `startTime`
|
||||
- `endTime`
|
||||
- `intervalMinutes`
|
||||
|
||||
返回内容:
|
||||
|
||||
- `taskId`
|
||||
- 初始状态
|
||||
|
||||
说明:
|
||||
|
||||
- 前端默认提交单个 `lineId`
|
||||
- 多监测点时前端直接提交多个 `lineIds`
|
||||
- 不单独拆分“单点接口”和“多点接口”
|
||||
|
||||
### 8.3 任务状态接口
|
||||
|
||||
接口:
|
||||
|
||||
- `GET /addData/task/status/{taskId}`
|
||||
|
||||
作用:
|
||||
|
||||
- 供前端轮询当前任务执行状态
|
||||
|
||||
返回内容:
|
||||
|
||||
- 任务状态:`WAITING`、`RUNNING`、`SUCCESS`、`FAILED`
|
||||
- 当前执行表名
|
||||
- 当前批次信息
|
||||
- 已写入条数
|
||||
- 已跳过条数
|
||||
- 失败条数
|
||||
- 失败原因
|
||||
- 开始时间、结束时间
|
||||
|
||||
### 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 选择框
|
||||
- 开始时间
|
||||
- 结束时间
|
||||
- 时间戳步长:`1`、`3`、`5`、`10` 分钟
|
||||
- 预计写入量按钮
|
||||
- 开始补数按钮
|
||||
|
||||
交互说明:
|
||||
|
||||
- 默认单监测点
|
||||
- 多监测点时切换为多选
|
||||
- 前端先调用预估接口,展示预计写入规模
|
||||
- 用户确认后再调用创建任务接口
|
||||
|
||||
### 12.3 任务状态展示
|
||||
|
||||
前端创建任务后轮询状态接口,建议展示:
|
||||
|
||||
- 当前状态
|
||||
- 当前表名
|
||||
- 已写入数量
|
||||
- 已跳过数量
|
||||
- 失败数量
|
||||
- 失败原因
|
||||
- 开始时间
|
||||
- 结束时间
|
||||
|
||||
### 12.4 参数规则展示区
|
||||
|
||||
参数规则表按用户提供图片组织,至少展示以下列:
|
||||
|
||||
- `电能质量参数名称`
|
||||
- `相别`
|
||||
- `显示`
|
||||
- `最大值`
|
||||
- `最小值`
|
||||
- `平均值`
|
||||
- `95%概率大值`
|
||||
- `是否合格`
|
||||
- `数据展示(保留小数)`
|
||||
|
||||
其中:
|
||||
|
||||
- 相别列使用 `phaseDisplay`
|
||||
- 所有数值默认保留 `2` 位小数
|
||||
- 该表展示的是模板规则,不是实时数据库统计结果
|
||||
|
||||
## 13. 文件结构建议
|
||||
|
||||
建议在 `tools/add-data` 下按现有仓库风格扩展:
|
||||
|
||||
```text
|
||||
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. 非目标
|
||||
|
||||
本次不包含以下内容:
|
||||
|
||||
- 不新增监测点基础信息管理能力
|
||||
- 不新增监测点字典表
|
||||
- 不新增数据库迁移框架
|
||||
- 不在 `system` 或 `user` 模块中扩展通用任务中心
|
||||
- 不实现真实前端页面代码
|
||||
- 不做覆盖更新或先删后写逻辑
|
||||
|
||||
## 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 分钟时间戳步长
|
||||
- 支持重复补数时跳过已存在数据
|
||||
- 支持前端按图片规则展示参数和相别
|
||||
- 在当前仓库约束下把改动范围控制在最小必要集合
|
||||
Reference in New Issue
Block a user