后端修改
This commit is contained in:
parent
c78e3be982
commit
3d4a65a157
@ -127,7 +127,12 @@ public class DeviceInferService {
|
||||
List<String> requiredFeatures = new ArrayList<>();
|
||||
if (model.getFeatureMapSnapshot() != null && !model.getFeatureMapSnapshot().isBlank()) {
|
||||
try {
|
||||
// 由于数据库里存的可能是转义的 JSON 字符串,我们需要多次解析直到它变成真正的 Object
|
||||
JsonNode fNode = objectMapper.readTree(model.getFeatureMapSnapshot());
|
||||
if (fNode.isTextual()) {
|
||||
fNode = objectMapper.readTree(fNode.asText());
|
||||
}
|
||||
|
||||
if (fNode.isArray()) {
|
||||
for (JsonNode node : fNode) requiredFeatures.add(node.asText());
|
||||
} else if (fNode.has("input_cols") && fNode.get("input_cols").isArray()) {
|
||||
@ -136,9 +141,12 @@ public class DeviceInferService {
|
||||
// 兼容旧版本
|
||||
for (JsonNode node : fNode.get("features")) requiredFeatures.add(node.asText());
|
||||
}
|
||||
log.info("Parsed requiredFeatures from feature_map_snapshot: {}", requiredFeatures);
|
||||
} catch (Exception e) {
|
||||
log.warn("解析特征映射快照失败: {}", e.getMessage());
|
||||
}
|
||||
} else {
|
||||
log.warn("模型 feature_map_snapshot 为空,将不进行特征过滤");
|
||||
}
|
||||
|
||||
// 将相对路径转换为绝对路径
|
||||
@ -206,11 +214,18 @@ public class DeviceInferService {
|
||||
if (requiredFeatures != null && !requiredFeatures.isEmpty()) {
|
||||
for (String featureName : requiredFeatures) {
|
||||
// 如果设备属性中包含模型需要的特征,则提取;否则填 0 或抛出异常(这里选择填 0.0,具体看业务要求)
|
||||
filteredProps.put(featureName, allProps.getOrDefault(featureName, 0.0));
|
||||
Object value = allProps.get(featureName);
|
||||
if (value == null) {
|
||||
log.warn("设备 {} 缺少必需的特征: {},默认填充 0.0", device.getDeviceId(), featureName);
|
||||
value = 0.0;
|
||||
}
|
||||
filteredProps.put(featureName, value);
|
||||
}
|
||||
log.info("设备 {} 的过滤后特征: {}", device.getDeviceId(), filteredProps);
|
||||
} else {
|
||||
// 如果模型没有保存特征快照,退退回发送全部属性
|
||||
filteredProps.putAll(allProps);
|
||||
log.warn("没有 requiredFeatures,发送全部属性: {}", filteredProps);
|
||||
}
|
||||
|
||||
deviceData.put("features", filteredProps);
|
||||
|
||||
24
data.txt
Normal file
24
data.txt
Normal file
@ -0,0 +1,24 @@
|
||||
batch=[Sample(meta={'deviceType': 'AnnularTank', 'step': 0, 'time': 0, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 1, 'time': 1, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 2,
|
||||
'time': 2, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 3, 'time': 3, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 4, 'time': 4, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 5, 'time': 5, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 6, 'time': 6, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 7, 'time': 7, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 8, 'time': 8, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 9, 'time': 9, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0}),
|
||||
Sample(meta={'deviceType': 'AnnularTank', 'step': 10, 'time': 10, 'deviceId': '786a9f85-2fd4-4b56-b5f6-4afb1cf33d32'},
|
||||
features={'diameter': 100.0, 'concentration': 0.0, 'concentration*ratio': 0.0, 'height': 150.0, 'ratio': 0.0, 'diameter*height': 0.0})]
|
||||
model_dir=None modelDir='D:\\keff_dataSpace\\models\\MLP\\AnnularTank\\Pu\\V2.0\\pipeline.pkl' algorithm_type=None device_type='AnnularTank' deviceType=None material_type=None materialType=None
|
||||
4
scripts/mvn17.cmd
Normal file
4
scripts/mvn17.cmd
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot"
|
||||
set "PATH=%JAVA_HOME%\bin;%PATH%"
|
||||
mvn %*
|
||||
46
变更实现方案.md
Normal file
46
变更实现方案.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 变更实现方案
|
||||
|
||||
本方案旨在响应《变更需求.md》中提出的四项核心改进需求,涵盖前端展示、后端逻辑、数据库设计及与 Python 算法服务的交互。
|
||||
|
||||
## 1. 需求一:情景表添加 Keff 阈值设置字段
|
||||
|
||||
### 1.1 需求描述
|
||||
在情景配置中新增 `keff` 阈值参数,并在仿真结果中对超过阈值的 `keff` 值进行红字高亮预警。
|
||||
|
||||
### 1.2 数据库变更
|
||||
在 `scenario` 表中增加字段:
|
||||
```sql
|
||||
ALTER TABLE scenario ADD COLUMN keff_threshold decimal(8,6) COMMENT 'Keff预警阈值';
|
||||
```
|
||||
|
||||
### 1.3 后端实现
|
||||
1. **实体类更新**:在 `Scenario.java` 中添加 `BigDecimal keffThreshold` 字段。
|
||||
2. **接口调整**:`ScenarioController` 的新增/修改接口自动支持该字段(基于 MyBatis-Plus)。
|
||||
3. **结果返回**:`SimController` 返回仿真结果时,可以顺便在元数据中返回该阈值,或者前端单独查询情景详情获取。
|
||||
|
||||
|
||||
|
||||
## 2. 需求二:情景表支持按设备设置算法类型
|
||||
|
||||
### 2.1 需求描述
|
||||
打破原有的“一情景一算法”限制,支持针对不同设备配置不同的算法模型(例如:圆柱槽使用 GPR,环形槽使用 MLP)。
|
||||
|
||||
### 2.2 数据库变更
|
||||
在 `scenario` 表中增加字段,存储设备级算法配置(JSON 格式):
|
||||
```sql
|
||||
ALTER TABLE scenario ADD COLUMN device_algo_config JSON COMMENT '设备算法配置映射,格式:{"deviceId1":"GPR", "deviceId2":"MLP"}';
|
||||
```
|
||||
|
||||
### 2.3 后端实现
|
||||
1. **实体类更新**:`Scenario.java` 添加 `String deviceAlgoConfig` 字段。
|
||||
2. **推理服务重构 (`DeviceInferService`)**:
|
||||
* **当前逻辑**:按 `deviceType` 分组 -> 获取全局 `algorithmType` -> 加载模型 -> 批量推理。
|
||||
* **新逻辑**:
|
||||
1. 解析 `deviceAlgoConfig` JSON。
|
||||
2. 遍历所有设备,确定每个设备的算法类型(优先取设备配置,无配置则取情景默认)。
|
||||
3. **重分组**:将设备按 `(deviceType, algorithmType)` 组合进行分组。例如:`{ "CylindricalTank_GPR": [dev1, dev2], "CylindricalTank_MLP": [dev3] }`。
|
||||
4. **分批推理**:遍历新的分组,分别加载对应的模型路径进行推理调用。
|
||||
|
||||
|
||||
---
|
||||
|
||||
35
变更需求.md
Normal file
35
变更需求.md
Normal file
@ -0,0 +1,35 @@
|
||||
1.情景表添加keff阈值设置字段:在情景配置中新增keff阈值参数,当模拟过程中keff值达到或超过设定阈值时,系统对keff值进行红色高亮显示,用于风险预警。
|
||||
2.情景表,有算法类型字段,现在要求支持按设备设置所使用的算法类型,以满足不同设备在同一情景下采用差异化算法模型的需求。
|
||||
3.始发事件配置增强:多时间点、多数值的配置方式,支持通过excel模板批量导入。
|
||||
4.开放模型训练面板
|
||||
新增模型训练模块,主要包括:
|
||||
选择算法类型、设备类型、选择样本数据集、支持模型参数配置,进行模型训练,展示模型训练指标(误差),支持模型文件保存。
|
||||
初步计划模型训练面板设计:
|
||||
设备类型:(下拉选择)
|
||||
算法类型:(下拉选择)
|
||||
样本数据集:根据时间范围选自临界数据库,或者上传的excel文件。
|
||||
模型参数配置:(文本框输入)
|
||||
训练按钮:(点击触发训练)
|
||||
训练指标展示:(实时显示训练误差等指标)
|
||||
模型文件保存:(保存训练好的模型文件)
|
||||
训练完成后,需要在模型表里面加一条记录。
|
||||
|
||||
|
||||
当前已有模型表:CREATE TABLE `algorithm_model` (
|
||||
`algorithm_model_id` char(36) COLLATE utf8mb4_general_ci NOT NULL COMMENT '模型版本唯一ID',
|
||||
`algorithm_type` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '算法类型(如GPR/MLP/FastRBF)',
|
||||
`device_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '设备类型(如CylindricalTank/AnnularTank)',
|
||||
`version_tag` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '版本标识(如v1或时间戳)',
|
||||
`model_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '模型文件路径(pipeline.pkl)',
|
||||
`feature_map_snapshot` json NOT NULL COMMENT '特征映射快照(Java属性→Python特征键)',
|
||||
`metrics` json DEFAULT NULL COMMENT '训练评估指标(rmse/mae/r2/maxe)',
|
||||
`metrics_image_path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '误差散点图路径',
|
||||
`trained_at` datetime DEFAULT NULL COMMENT '训练完成时间',
|
||||
`is_current` tinyint NOT NULL DEFAULT '0' COMMENT '是否当前激活版本(1是,0否)',
|
||||
`created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`modifier` varchar(40) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后修改人',
|
||||
PRIMARY KEY (`algorithm_model_id`),
|
||||
UNIQUE KEY `uk_algo_dev_ver` (`algorithm_type`,`device_type`,`version_tag`) COMMENT '同算法+设备类型的版本唯一',
|
||||
KEY `idx_current` (`algorithm_type`,`device_type`,`is_current`) COMMENT '当前版本查询索引'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
73
增加材料类型的支持.md
Normal file
73
增加材料类型的支持.md
Normal file
@ -0,0 +1,73 @@
|
||||
# 增加材料类型(material_type)支持的详细实施方案
|
||||
|
||||
根据现有的系统架构和需求,为算法模型增加“材料类型(material_type)”维度的支持,需要从数据库、实体类、核心业务逻辑(特别是路径解析与模型发布)以及状态控制等方面进行细化和落地。以下是详细的分析与实施细则:
|
||||
|
||||
## 1. 数据库层面修改 (Database)
|
||||
- **目标表**: `algorithm_model`
|
||||
- **操作**: 增加 `material_type` 字段,用于区分该模型适用的材料(如 `Pu` 等)。
|
||||
- **SQL 参考**:
|
||||
```sql
|
||||
ALTER TABLE algorithm_model
|
||||
ADD COLUMN material_type VARCHAR(50) DEFAULT NULL COMMENT '材料类型' AFTER device_type;
|
||||
```
|
||||
|
||||
## 2. 实体类及映射修改 (Domain)
|
||||
- **目标文件**: `AlgorithmModel.java`
|
||||
- **操作**: 增加对应的 Java 属性,并使用 MyBatis-Plus 的 `@TableField` 进行映射。
|
||||
- **代码参考**:
|
||||
```java
|
||||
/**
|
||||
* 材料类型 (例如: Pu)
|
||||
*/
|
||||
@TableField("material_type")
|
||||
private String materialType;
|
||||
```
|
||||
|
||||
## 3. 核心业务逻辑修改 (Service)
|
||||
|
||||
### 3.1 提取材料类型 (Path Parsing)
|
||||
- **目标文件**: `ModelTrainServiceImpl.java` -> `publishModel` 方法。
|
||||
- **逻辑细化**: `ModelTrainTask` 中保存的相对路径(如 `runs/GPR/AnnularTank/Pu/edb0e340-51e6-46bb-9c08-5ba38762089e/pipeline.pkl`)包含了材料信息。
|
||||
- **解析规则**:
|
||||
需要对 `task.getModelOutputPath()` 或 `task.getModelRelativePath()` 进行字符串分割(兼容 `/` 和 `\`)。
|
||||
标准的目录层级为:`runs` / `{算法类型}` / `{设备类型}` / `{材料类型}` / `{TaskID}` / `{文件名}`。
|
||||
- 第 0 层: `runs`
|
||||
- 第 1 层: `algorithm_type` (如 `GPR`)
|
||||
- 第 2 层: `device_type` (如 `AnnularTank`)
|
||||
- **第 3 层**: `material_type` (如 `Pu`) <- **需要提取的字段**
|
||||
- 第 4 层: `task_id`
|
||||
|
||||
### 3.2 更新模型发布路径 (Publish Path Assembly)
|
||||
- **目标文件**: `ModelTrainServiceImpl.java` -> `publishModel` 方法。
|
||||
- **旧路径结构**: `{modelRoot}/{algorithmType}/{deviceType}/{versionTag}/`
|
||||
- **新路径结构**: 将提取出的 `materialType` 拼接到发布路径中,使发布目录也具备材料维度。
|
||||
**新结构**: `{modelRoot}/{algorithmType}/{deviceType}/{materialType}/{versionTag}/`
|
||||
- **持久化**:
|
||||
在构建要插入到 `algorithm_model` 表的记录时,不仅要保存新拼接出的模型绝对/相对路径,还要将解析出的 `materialType` 赋值给 `AlgorithmModel` 对象。
|
||||
|
||||
### 3.3 激活模型的唯一性约束控制 (Active Model Logic)
|
||||
- **业务规则**: “每种设备 + 每种算法类型 + 每种材料类型” 只能由一个激活(`is_active = 1` 或者对应状态码)的算法。
|
||||
- **目标文件**: 处理模型发布或激活的 Service 方法(如 `AlgorithmModelServiceImpl` 中如果存在独立激活方法,或直接在 `publishModel` 之后的操作)。
|
||||
- **逻辑细化**: 在将某模型记录标记为激活前,需要执行排他更新:
|
||||
```java
|
||||
UpdateWrapper<AlgorithmModel> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("device_type", model.getDeviceType())
|
||||
.eq("algorithm_type", model.getAlgorithmType())
|
||||
.eq("material_type", model.getMaterialType()) // 新增材料类型维度限制
|
||||
.set("is_active", 0); // 假设 0 为未激活,1 为激活
|
||||
algorithmModelMapper.update(null, updateWrapper);
|
||||
```
|
||||
|
||||
## 4. API 接口层面 (Controller)
|
||||
- **目标文件**: `ModelTrainController.java`
|
||||
- **接口定义**:
|
||||
```java
|
||||
@PostMapping("/publish")
|
||||
public ResponseResult publish(@RequestBody Map<String, String> body) {
|
||||
String taskId = body.get("taskId");
|
||||
String versionTag = body.get("versionTag");
|
||||
boolean success = modelTrainService.publishModel(taskId, versionTag);
|
||||
return success ? ResponseResult.success() : ResponseResult.error("发布失败");
|
||||
}
|
||||
```
|
||||
- **结论**: 接口的入参定义**无需修改**。材料类型信息属于内部推导数据,完全可以由 Service 层通过 `taskId` 找到对应的 Task 数据,再解析路径得到 `material_type`,对前端调用保持透明。
|
||||
49
异步推理并保存结果.md
Normal file
49
异步推理并保存结果.md
Normal file
@ -0,0 +1,49 @@
|
||||
# 异步推理并保存结果 (SimInferService 流程解析)
|
||||
|
||||
在仿真计算完成后,系统需要将每一步的计算结果发送给 Python 推理服务,以预测关键指标(如 Keff)。这个过程由 `SimInferService` 和 `DeviceInferService` 协同完成。
|
||||
|
||||
## 1. 推理数据不是一次性全部发送
|
||||
|
||||
**核心结论:** 并不是把所有结果封装为一个大 Request 调用一次推理接口,而是**进行了精细的多级分组后,分别调用推理接口**。
|
||||
|
||||
因为不同的设备、不同的材料、以及用户为设备配置的不同算法,都对应着不同的**模型文件(Pipeline/Model)**。一次推理请求只能加载一个模型文件,所以必须将必须使用同一模型的数据分在同一批次发送。
|
||||
|
||||
## 2. 数据转换与分组流程
|
||||
|
||||
整个流程分为两部分:在 `SimInferService` 中进行一级分组,然后在 `DeviceInferService` 中进行二级和三级分组。
|
||||
|
||||
### 2.1 第一级分组:按设备类型 (DeviceType) 分组
|
||||
**位置:** `SimInferService.asyncInferAndSave`
|
||||
|
||||
1. **展平时间轴 (Flatten Timeline)**:仿真引擎返回的 `SimContext` 是按时间步(Step)组织的。代码首先遍历每个时间步,将散落的属性(如液位、浓度)按 `unitId` 聚合。
|
||||
2. **注入元数据**:通过 `SimUnit`,将静态属性(如设备固有的直径、高度)以及新加入的 `materialType`(如 U, Pu)合并到设备的属性集合中,生成 `DeviceStepInfo` 对象。
|
||||
3. **一级分组**:将所有时间步的 `DeviceStepInfo` 根据 **设备类型 (`deviceType`)** 放入 `Map<String, List<DeviceStepInfo>> groupedDevices` 中。
|
||||
- *例如:所有的 CylindricalTank 数据在一组,AnnularTank 在另一组。*
|
||||
|
||||
### 2.2 第二级分组:按算法类型 (AlgorithmType) 分组
|
||||
**位置:** `DeviceInferService.processDeviceInference`
|
||||
|
||||
1. **读取配置**:获取全局配置的算法(如 GPR),以及针对特定设备独立配置的算法(`deviceAlgoConfig`)。
|
||||
2. **二级分组**:在某一个设备类型(如 CylindricalTank)的数据列表中,进一步按 **算法类型 (`algoType`)** 分组。
|
||||
- *例如:CylindricalTank 组被拆分为 -> 使用 GPR 算法的批次、使用 MLP 算法的批次。*
|
||||
|
||||
### 2.3 第三级分组:按材料类型 (MaterialType) 分组
|
||||
**位置:** `DeviceInferService.processDeviceInference`
|
||||
|
||||
1. **三级分组**:在特定的算法批次中,进一步按 **材料类型 (`materialType`)** 分组。
|
||||
- *例如:使用 GPR 的 CylindricalTank 批次被拆分为 -> 材料为 U 的批次、材料为 Pu 的批次。*
|
||||
|
||||
## 3. 发起推理请求
|
||||
|
||||
经过上述三级分组后,我们得到了一个**高度同质化**的数据批次。对于每一个这样的最终批次:
|
||||
|
||||
1. **查询模型**:调用 `algorithmModelService.getCurrentModelPath(algoType, deviceType, materialType)`。因为这三个维度相同,所以它们一定使用同一个物理模型文件(`.pkl`)。
|
||||
2. **构建 Request**:将这批数据(包含所有相关设备在所有时间步的状态)组装成一个 `InferRequest`。
|
||||
3. **发起调用**:向 Python 服务发送 HTTP POST 请求 `/v1/infer`。
|
||||
4. **入库保存**:Python 返回每个设备在每个时间步的预测结果(如 `keff`),Java 端解析这些结果并批量保存到 `scenario_result` 表中。
|
||||
|
||||
## 4. 异常与状态管理
|
||||
|
||||
- 整个过程是加上了 `@Async` 异步执行的,不会阻塞前端获取基础仿真数据。
|
||||
- 如果某一个批次因为找不到模型(例如上述终端日志中 `GPR + CylindricalTank + U` 的模型未配置),代码会记录错误并标记 `hasAnyError = true`,然后跳过该批次(`continue`)。
|
||||
- **兜底机制**:如果所有的批次都失败或找不到模型(`!hasAnySuccess && hasAnyError`),会抛出 `RuntimeException`。这会被外层 `SimInferService` 捕获,并将该情景的状态更新为 **"3" (失败)**。
|
||||
112
推理接口对材料类型的支持.md
Normal file
112
推理接口对材料类型的支持.md
Normal file
@ -0,0 +1,112 @@
|
||||
# 推理接口对材料类型的支持分析与实施方案
|
||||
|
||||
根据最新的需求,`algorithm_model` 表已支持 `material_type` 字段,用于区分不同材料(如 `Pu`、`U` 等)的专用模型。为了在仿真推理阶段能够正确加载对应的模型,需要对现有的推理数据流进行改造,确保“材料类型”这一关键上下文能够从仿真计算传递到推理服务。
|
||||
|
||||
## 1. 现状分析 (As-Is)
|
||||
|
||||
### 1.1 数据流现状
|
||||
|
||||
1. **SimController**: 调用 `simBuilder.buildUnits` 构建仿真单元。
|
||||
2. **SimBuilder**: 从 `Topology` 和 `MaterialService` 读取数据,构建 `SimUnit`。
|
||||
- *当前缺失*: `SimUnit` 仅包含 `materialId`,**未包含** `materialType`。
|
||||
- *当前缺失*: `Material` 实体类中也未明确发现 `materialType` 字段(仅有 `name`, `concentrations` 等)。
|
||||
3. **SimInferService**: 将 `SimContext` 转换为 `DeviceStepInfo`,并按 `deviceType` 分组。
|
||||
- *当前缺失*: 分组逻辑未考虑材料类型。
|
||||
4. **DeviceInferService**: 接收分组数据,再次按 `algorithmType` 分组,然后调用 `algorithmModelService.getCurrentModelPath(algo, device)`。
|
||||
- *当前缺失*: 调用获取模型路径接口时,缺少 `materialType` 参数,导致无法精确定位到特定材料的模型(可能默认返回第一个或报错)。
|
||||
|
||||
### 1.2 关键断点
|
||||
|
||||
- **源头缺失**: 仿真单元(SimUnit)不知道自己处理的是什么类型的材料。
|
||||
- **传递中断**: 推理服务(InferService)无法获取材料类型信息。
|
||||
- **查询不足**: 模型匹配逻辑未利用材料类型进行过滤。
|
||||
|
||||
## 2. 实施方案 (To-Be)
|
||||
|
||||
### 2.1 第一步:完善领域模型 (Domain & Model)
|
||||
|
||||
#### 1. 不修改 `Material` 实体
|
||||
|
||||
需要根据材料表获取的是U浓度值或者Pu浓度值,决定Material\_type = U 或者Pu
|
||||
|
||||
这个主要是模型根据材料类型训练来的,所以只能把数据也做了材料分类。
|
||||
|
||||
#### 2. 修改 `SimUnit` Record
|
||||
|
||||
在 `SimUnit` 中增加 `materialType` 字段,用于在内存中流转该信息。
|
||||
|
||||
```java
|
||||
public record SimUnit(
|
||||
String unitId,
|
||||
String deviceId,
|
||||
String materialId,
|
||||
String deviceType,
|
||||
String materialType, // 新增
|
||||
Map<String, Double> staticProperties
|
||||
) {}
|
||||
```
|
||||
|
||||
#### 3. 修改 `DeviceStepInfo`
|
||||
|
||||
在 `DeviceStepInfo` 中增加 `materialType` 字段,确保分组时能携带此信息。
|
||||
|
||||
```java
|
||||
public class DeviceStepInfo {
|
||||
// ... 原有字段
|
||||
private String materialType; // 新增
|
||||
|
||||
// getter/setter ...
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 第二步:更新构建逻辑 (SimBuilder)
|
||||
|
||||
在 `SimBuilder.buildUnits` 方法中:
|
||||
|
||||
1. 在查询 `Material` 信息时,根据材料属性(U浓度/Pu浓度等)推导 `materialType`。
|
||||
- 规则示例:若 `pu_concentration > 0` 则为 `Pu`,否则若 `u_concentration > 0` 则为 `U`,否则为 `unknown`。
|
||||
2. 在构造 `SimUnit` 时,将 `material_type` 注入。
|
||||
|
||||
### 2.3 第三步:更新推理准备逻辑 (SimInferService)
|
||||
|
||||
在 `SimInferService.asyncInferAndSave` 方法中:
|
||||
|
||||
1. 在将 `SimContext` 转换为 `DeviceStepInfo` 时,从对应的 `SimUnit` 中提取 `materialType` 并赋值给 `DeviceStepInfo`。
|
||||
2. **分组策略变更**:
|
||||
- 原: `Map<String, List<DeviceStepInfo>>` (Key: DeviceType)
|
||||
- 新: 保持外层按 `DeviceType` 分组不变,利用 `DeviceStepInfo` 内部携带的 `materialType` 在下一步进行细分。
|
||||
|
||||
### 2.4 第四步:更新推理执行逻辑 (DeviceInferService)
|
||||
|
||||
在 `DeviceInferService.processDeviceInference` 方法中:
|
||||
|
||||
1. 接收到的数据是按 `DeviceType` 分组的。
|
||||
2. **三级分组**: 遍历设备列表,进一步按 `AlgorithmType` **AND** `MaterialType` 进行分组。
|
||||
- 构造复合键或嵌套 Map: `Map<String, Map<String, List<DeviceStepInfo>>>` (AlgoType -> MaterialType -> List)。
|
||||
3. **模型匹配**:
|
||||
```java
|
||||
String modelPath = algorithmModelService.getCurrentModelPath(currentAlgoType, deviceType, currentMaterialType);
|
||||
```
|
||||
4. **请求构建**: 确保找到的模型是与当前批次数据的材料类型匹配的。
|
||||
|
||||
### 2.5 第五步:更新模型查询接口 (AlgorithmModelService)
|
||||
|
||||
完善 `getCurrentModelPath` 方法,增加 `materialType` 参数,并更新 MyBatis-Plus 查询条件。
|
||||
|
||||
```java
|
||||
String getCurrentModelPath(String algorithmType, String deviceType, String materialType);
|
||||
```
|
||||
|
||||
## 3. 任务清单 (Action Items)
|
||||
|
||||
1. **Domain & Model**:
|
||||
- [ ] 更新 `SimUnit.java` 增加 `materialType`。
|
||||
- [ ] 更新 `DeviceStepInfo.java` 增加 `materialType`。
|
||||
2. **Builder**:
|
||||
- [ ] 修改 `SimBuilder.java`,实现材料类型推导逻辑并填充 `SimUnit`。
|
||||
3. **Service**:
|
||||
- [ ] 修改 `SimInferService.java`,在转换时将 `materialType` 传递给 `DeviceStepInfo`。
|
||||
- [ ] 修改 `DeviceInferService.java`,实现 (Algo + Material) 的组合分组与模型匹配调用。
|
||||
- [ ] 修改 `AlgorithmModelService.java` 及实现类,增加带 `materialType` 的路径查询方法。
|
||||
4. **Controller**:
|
||||
- [ ] `SimController` 无需修改代码,验证端到端流程。
|
||||
2
推理数据封装问题定位.md
Normal file
2
推理数据封装问题定位.md
Normal file
@ -0,0 +1,2 @@
|
||||
# 推理数据:
|
||||
|
||||
114
日志记录及日志文件.md
Normal file
114
日志记录及日志文件.md
Normal file
@ -0,0 +1,114 @@
|
||||
# 日志记录及日志文件分析与建议
|
||||
|
||||
在目前的 `framework` 框架和 `business-css` 业务模块中,日志系统已经基于 **Logback** 和 **Spring AOP** 搭建了良好的基础。为了在 `business-css` 模块中更好地使用日志并规范输出,以下是综合分析与具体建议:
|
||||
|
||||
## 1. 当前日志架构分析
|
||||
|
||||
### 1.1 日志框架与配置
|
||||
- **底层框架**: 使用的是 Spring Boot 默认的 Logback。
|
||||
- **配置文件**: 位于 `framework/src/main/resources/logback-spring.xml`。
|
||||
- **输出策略**:
|
||||
- **控制台 (CONSOLE)**: 强制使用 UTF-8 编码,包含时间、线程、级别、类名和消息。
|
||||
- **文件 (FILE)**: 采用按天滚动的策略 (`TimeBasedRollingPolicy`),最多保留 30 天的历史日志。
|
||||
- **配置文件覆盖**: 在 `business-css/src/main/resources/application-business.yml` 中,通过 `logging.file.name: logs/business-css.log` 重写了日志文件的路径和名称。这意味着启动 `business-css` 模块时,日志会自动写入该文件。
|
||||
|
||||
### 1.2 业务操作日志 (AOP 切面)
|
||||
- **注解支持**: `framework` 中提供了自定义注解 `@com.yfd.platform.annotation.Log(value="操作描述", module="所属模块")`。
|
||||
- **切面拦截**: `LogAspect.java` 会拦截带有该注解的方法,自动提取请求信息(IP、浏览器、操作人等)以及方法执行的耗时和结果,并调用 `ISysLogService` 将这些操作日志**持久化到数据库**中。
|
||||
|
||||
---
|
||||
|
||||
## 2. 针对 business-css 模块的实施建议
|
||||
|
||||
为了在 `business-css` 模块中实现规范、高效的日志记录,建议从以下两个维度(**系统运行日志** 和 **用户操作日志**)入手:
|
||||
|
||||
### 2.1 用户操作日志 (入库) —— 针对 Controller 层
|
||||
对于需要审计、追踪用户行为的核心业务接口(如增删改操作),应直接复用框架提供的 `@Log` 注解。
|
||||
|
||||
**实施方法:**
|
||||
在 `business-css` 的 `Controller` 层方法上添加 `@Log` 注解。
|
||||
|
||||
**代码示例:**
|
||||
```java
|
||||
import com.yfd.platform.annotation.Log;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/project")
|
||||
public class ProjectController {
|
||||
|
||||
@Log(value = "新增仿真项目", module = "项目管理")
|
||||
@PostMapping
|
||||
public ResponseResult addProject(@RequestBody Project project) {
|
||||
// 业务逻辑...
|
||||
return ResponseResult.success();
|
||||
}
|
||||
}
|
||||
```
|
||||
**效果**:用户的操作会被自动拦截并写入数据库的系统日志表中,方便后台管理界面的“日志管理”模块进行展示和审计。
|
||||
|
||||
### 2.2 系统运行与调试日志 (写文件) —— 针对 Service / 核心逻辑层
|
||||
对于系统内部的运行状态、复杂计算过程(如仿真计算、模型推理等)以及异常捕获,应该使用标准的日志框架(SLF4J)打印日志,以便于排查 Bug。
|
||||
|
||||
**实施方法:**
|
||||
在需要打印日志的类上使用 Lombok 的 `@Slf4j` 注解,然后使用 `log.info()`, `log.error()` 等方法。
|
||||
|
||||
**代码示例:**
|
||||
```java
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SimInferServiceImpl implements SimInferService {
|
||||
|
||||
public void asyncInferAndSave(...) {
|
||||
log.info("开始执行异步推理任务, scenarioId: {}", scenarioId);
|
||||
try {
|
||||
// 复杂的推理逻辑...
|
||||
log.debug("中间计算状态: {}", someState);
|
||||
} catch (Exception e) {
|
||||
// 记录异常堆栈,这会被输出到 logs/business-css.log 中
|
||||
log.error("异步推理失败, scenarioId: {}, 原因: {}", scenarioId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 异常日志的统一处理
|
||||
目前的 `GlobalExceptionHandler` 已经能够拦截未处理的异常并使用 `log.error()` 打印。
|
||||
**建议**:在 `business-css` 模块抛出自定义业务异常(如 `BizException`)时,确保全局异常处理器能合理地记录(通常业务异常记为 `WARN` 即可,系统级异常记为 `ERROR`)。目前 `GlobalExceptionHandler` 统一按 `ERROR` 记录了所有 `Throwable`,这会导致日志文件中充斥着正常的业务校验阻断信息,建议后续对异常进行分类处理。
|
||||
|
||||
---
|
||||
|
||||
## 3. 日志文件输出管理建议
|
||||
|
||||
目前 `business-css` 的 `application-business.yml` 中配置了:
|
||||
```yaml
|
||||
logging:
|
||||
file:
|
||||
name: logs/business-css.log
|
||||
```
|
||||
这会导致 Spring Boot 覆盖 `logback-spring.xml` 中定义的 `<file>` 标签,但在某些 Spring Boot 版本中,如果不完全结合 `logback-spring.xml`,可能导致滚动策略失效。
|
||||
|
||||
**最佳实践建议:**
|
||||
1. **统一由 Logback 接管**:建议删除 `application-business.yml` 中的 `logging.file.name` 配置。
|
||||
2. **通过变量传递**:在 `application-business.yml` 中定义自定义属性,或者直接利用 `spring.application.name`。然后在 `logback-spring.xml` 中通过 `<springProperty>` 读取该值,动态决定日志文件名。
|
||||
|
||||
**修改示例 (logback-spring.xml 改造建议):**
|
||||
```xml
|
||||
<configuration>
|
||||
<!-- 从 yml 读取应用名称,默认为 platform -->
|
||||
<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="platform"/>
|
||||
<property name="LOG_PATH" value="logs"/>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 这样启动 business-css 时,日志就会是 logs/business-css.log -->
|
||||
<file>${LOG_PATH}/${APP_NAME}.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
</configuration>
|
||||
```
|
||||
这样做能确保日志的按天滚动、文件大小限制等策略完美生效,且不同微服务/模块只要定义好 `spring.application.name`,就能自动隔离日志文件。
|
||||
146
模型训练任务.md
Normal file
146
模型训练任务.md
Normal file
@ -0,0 +1,146 @@
|
||||
# 模型训练任务界面设计方案
|
||||
|
||||
本方案基于原有需求,对“模型训练面板”的功能模块、交互流程及字段定义进行了全面细化与完善,确保用户体验流畅且功能完整。
|
||||
|
||||
## 1. 任务列表 (Task List)
|
||||
|
||||
### 1.1 查询栏
|
||||
* **任务名称**:文本输入框(支持模糊搜索)。
|
||||
* **算法类型**:下拉选择框(如 GPR, MLP, FastRBF, ...)。
|
||||
* **设备类型**:下拉选择框(如 CylindricalTank, AnnularTank, ...)。
|
||||
* **状态**:下拉选择框(全部, Pending, Training, Success, Failed)。
|
||||
* **操作按钮**:[查询] [重置] [新建训练任务]
|
||||
|
||||
### 1.2 数据表格
|
||||
| 列名 | 数据类型 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| **任务名称** | String | 点击名称可直接跳转详情页 |
|
||||
| **算法类型** | String | GPR / MLP 等 |
|
||||
| **设备类型** | String | CylindricalTank 等 |
|
||||
| **训练集来源** | String | 显示文件名或数据源类型(如 "Upload: dataset.csv") |
|
||||
| **核心指标** | String | 成功时显示关键指标(如 RMSE: 0.02, R2: 0.98),失败/进行中显示 "-" |
|
||||
| **状态** | Status | 使用 Tag 区分颜色:<br>🔵 Pending (等待中)<br>🟡 Training (训练中)<br>🟢 Success (成功)<br>🔴 Failed (失败) |
|
||||
| **创建时间** | DateTime | yyyy-MM-dd HH:mm:ss |
|
||||
| **操作** | ButtonGroup | [查看详情] [发布模型] [删除] |
|
||||
|
||||
* **分页控件**:位于表格底部,支持调整每页显示条数。
|
||||
|
||||
### 1.3 操作说明
|
||||
* **查看详情**:任何状态下均可点击,跳转至详情页。
|
||||
* **发布模型**:仅当状态为 **Success** 时可用(否则禁用)。点击弹出发布确认框。
|
||||
* **删除**:仅当状态为 **Success** 或 **Failed** 时可用(Training 中不可删除)。点击需二次确认,删除后不可恢复。
|
||||
|
||||
---
|
||||
|
||||
## 2. 新建训练任务 (Create Task)
|
||||
|
||||
采用分步向导或单页表单形式,推荐单页表单。
|
||||
|
||||
### 2.1 基础配置
|
||||
* **任务名称** (必填):文本框,建议自动生成默认名(如 "Train_GPR_20240311_001")。
|
||||
* **设备类型** (必填):下拉选择。
|
||||
* **算法类型** (必填):下拉选择。选择后,下方的“参数配置”应动态加载该算法的默认参数。
|
||||
|
||||
### 2.2 数据准备
|
||||
* **数据源类型** (必填):单选框 [文件上传] / [临界库数据]。
|
||||
* **选中“文件上传”**:
|
||||
* 显示文件上传组件(支持 .csv, .xlsx)。
|
||||
* 上传后需显示文件名及大小,并提供“重新上传”按钮。
|
||||
* **选中“临界库数据”**(二期功能):
|
||||
* 显示时间范围选择器(开始时间 - 结束时间)。
|
||||
* 显示“预览数据量”按钮(如:查询到 5000 条记录)。
|
||||
|
||||
### 2.3 参数配置
|
||||
* **训练超参数**:
|
||||
* 提供“加载默认值”按钮。
|
||||
* 使用 **JSON 编辑器** 或 **Key-Value 列表** 展示参数(如 `epochs`, `learning_rate`, `kernel` 等)。
|
||||
* 相比单纯文本框,JSON 编辑器能提供格式校验,避免输入错误。
|
||||
|
||||
### 2.4 底部按钮
|
||||
* [提交训练]:点击后校验表单,成功则跳转回列表页并自动刷新。
|
||||
* [取消]:返回列表页。
|
||||
|
||||
---
|
||||
|
||||
## 3. 查看详情 (Task Details)
|
||||
|
||||
详情页分为三个主要区域:基础信息、训练监控/结果、日志。
|
||||
|
||||
### 3.1 基础信息卡片
|
||||
展示任务的静态配置信息:
|
||||
* 任务名称、ID
|
||||
* 算法类型、设备类型
|
||||
* 数据源路径
|
||||
* 训练参数(JSON 格式化展示,只读)
|
||||
* 创建时间、更新时间
|
||||
|
||||
### 3.2 训练监控/结果区
|
||||
根据状态不同,展示不同内容:
|
||||
|
||||
* **Training (训练中)**:
|
||||
* **进度条**:显示当前 Epoch/Total Epochs。
|
||||
* **实时指标图**:折线图展示 Loss (损失函数) 随迭代次数的变化。前端定时轮询或通过 WebSocket 获取最新数据。
|
||||
* **当前指标**:实时显示当前的 RMSE, Accuracy 等。
|
||||
|
||||
* **Success (成功)**:
|
||||
* **最终指标卡片**:RMSE, MAE, R2, MaxError 等关键评估指标。
|
||||
* **误差散点图**:展示 `metrics_image_path` 对应的图片(预测值 vs 真实值)。
|
||||
* **特征重要性**(可选):如果算法支持,展示特征权重图。
|
||||
|
||||
* **Failed (失败)**:
|
||||
* 显示醒目的红色错误提示。
|
||||
|
||||
### 3.3 错误日志区
|
||||
* 仅在 **Failed** 状态或 **Training** 状态下显示。
|
||||
* 展示后端或 Python 服务返回的详细异常堆栈或 Print 输出,便于排查问题。
|
||||
|
||||
### 3.4 顶部/底部操作栏
|
||||
* [发布模型](仅 Success 状态可见)
|
||||
* [返回列表]
|
||||
|
||||
---
|
||||
|
||||
## 4. 模型发布 (Publish Model)
|
||||
|
||||
将临时训练任务产出的模型正式注册到系统模型库中。
|
||||
|
||||
### 4.1 交互流程
|
||||
1. 在列表页点击“发布模型”,或在详情页点击“发布模型”。
|
||||
2. 弹出模态框(Modal)。
|
||||
|
||||
### 4.2 弹窗内容
|
||||
* **任务名称**:(只读回显)
|
||||
* **算法/设备**:(只读回显)
|
||||
* **版本号 (Version Tag)** (必填):文本框。
|
||||
* 提示用户输入版本标识,如 `v1.0`, `20240311-release`。
|
||||
* 后端需校验该算法+设备下版本号的唯一性。
|
||||
* **备注描述**:多行文本框(可选),用于记录模型特性或变更点。
|
||||
|
||||
### 4.3 确认操作
|
||||
* [确认发布]:
|
||||
* 后端将临时模型文件移动到正式目录。
|
||||
* 在 `algorithm_model` 表中创建新记录。
|
||||
* 发布成功后,提示用户“发布成功,请前往模型管理页激活使用”。
|
||||
* 关闭弹窗,刷新列表(建议在列表中增加“已发布”标记或状态)。
|
||||
* [取消]:关闭弹窗。
|
||||
|
||||
|
||||
### 4.4 模型路径规划
|
||||
|
||||
模型路径规划建议(推荐目录结构) 以你现有的配置 file-space.model-path 为根(例如 E:/python_coding/keffCenter/models/ ),建议分两棵树:
|
||||
|
||||
- 训练产物(可清理)
|
||||
|
||||
- {modelRoot}/runs/{algorithmType}/{deviceType}/{taskId}/
|
||||
- 里面放: pipeline.pkl 、 metrics.json 、 feature_map.json 、 metrics.png 、 train_params.json 等
|
||||
- 优点:用 taskId 保证唯一、不覆盖
|
||||
- 发布模型(长期保留、可回滚)
|
||||
|
||||
- {modelRoot}/published/{algorithmType}/{deviceType}/{versionTag}/
|
||||
- 里面放: pipeline.pkl (或带 hash 的文件名)、配套文件、manifest(可选)
|
||||
- algorithm_model.model_path 指向这里
|
||||
另外建议:
|
||||
|
||||
- 路径里尽量只用 algorithmType/deviceType/versionTag/taskId 这种稳定字段,避免包含中文/空格
|
||||
- versionTag 建议由用户输入但要校验(只允许 [a-zA-Z0-9._-] ),避免路径注入
|
||||
- 如果担心文件重复,可在发布时生成 artifactId (hash)并写入模型表,便于去重/校验一致性
|
||||
192
模型训练面板实现过程.md
Normal file
192
模型训练面板实现过程.md
Normal file
@ -0,0 +1,192 @@
|
||||
# 模型训练面板实现过程
|
||||
|
||||
根据《变更需求.md》中的第四点,我们需要为系统新增一个“模型训练面板”。该面板旨在支持用户通过简单的交互界面,上传数据、配置参数并启动模型训练,最终将训练好的模型发布到系统中。
|
||||
|
||||
## 1. 核心流程分析
|
||||
|
||||
1. **数据准备**:用户上传训练数据集(Excel/CSV),或从系统历史数据中选择(后续扩展)。
|
||||
2. **任务配置**:选择目标设备类型、算法类型,并输入模型超参数。
|
||||
3. **任务提交**:后端接收请求,创建训练任务记录,并异步调用 Python 算法服务。
|
||||
4. **过程监控**:前端轮询任务状态,展示实时训练进度和评估指标(如 Loss, Accuracy)。
|
||||
5. **模型入库**:训练成功后,自动解析模型元数据(特征映射、评估指标图表),并将其注册到 `algorithm_model` 表中。
|
||||
|
||||
## 2. 详细实现步骤
|
||||
|
||||
### 2.1 数据库设计
|
||||
|
||||
虽然已有 `algorithm_model` 表用于存储正式模型,但训练过程是一个长耗时且可能失败的操作,直接写入正式表会导致垃圾数据。因此,建议新增一张 **训练任务表 (`model_train_task`)** 来管理训练生命周期。
|
||||
|
||||
```sql
|
||||
CREATE TABLE model_train_task (
|
||||
task_id VARCHAR(32) PRIMARY KEY COMMENT '任务ID',
|
||||
task_name VARCHAR(100) COMMENT '任务名称',
|
||||
algorithm_type VARCHAR(50) COMMENT '算法类型 (GPR, MLP...)',
|
||||
device_type VARCHAR(50) COMMENT '设备类型 (CylindricalTank...)',
|
||||
dataset_path VARCHAR(255) COMMENT '数据集文件路径',
|
||||
train_params JSON COMMENT '训练超参数 ({"epochs": 100, "lr": 0.01...})',
|
||||
status VARCHAR(20) COMMENT '状态 (PENDING, TRAINING, SUCCESS, FAILED)',
|
||||
metrics JSON COMMENT '训练指标 ({"rmse": 0.002, "r2": 0.98})',
|
||||
model_output_path VARCHAR(255) COMMENT '训练生成的临时模型路径',
|
||||
feature_map_snapshot JSON COMMENT '特征映射快照',
|
||||
metrics_image_path VARCHAR(255) COMMENT '误差散点图路径',
|
||||
error_log TEXT COMMENT '错误日志',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 2.2 后端接口设计 (`ModelTrainController`)
|
||||
|
||||
| 接口路径 | 方法 | 描述 | 参数示例 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `/train/upload` | POST | 上传训练数据集 | File |
|
||||
| `/train/submit` | POST | 提交训练任务 | `{name, algoType, deviceType, datasetPath, params}` |
|
||||
| `/train/status/{taskId}` | GET | 查询训练状态与指标 | - |
|
||||
| `/train/publish/{taskId}` | POST | 发布模型(入库) | `{versionTag, description}` |
|
||||
| `/train/list` | GET | 查询历史训练任务 | `page, size` |
|
||||
|
||||
### 2.3 业务逻辑实现 (`ModelTrainService`)
|
||||
|
||||
1. **数据上传 (`uploadDataset`)**:
|
||||
* 接收 Excel/CSV 文件。
|
||||
* 校验文件格式(必需列:`input_features`, `target_label`)。
|
||||
* 保存到服务器临时目录 `/data/uploads/{date}/{uuid}.csv`。
|
||||
|
||||
2. **任务提交 (`createTask`)**:
|
||||
* 创建 `model_train_task` 记录,状态设为 `PENDING`。
|
||||
* 构建请求参数,异步调用 Python 服务的 `/v1/train` 接口。
|
||||
* 若调用成功,更新状态为 `TRAINING`;否则标记为 `FAILED`。
|
||||
|
||||
3. **状态同步 (`syncTaskStatus`)**:
|
||||
* 定时任务或前端轮询触发:调用 Python 服务的 `/v1/train/status/{taskId}` 接口。
|
||||
* 更新数据库中的 `metrics` 和 `status`。
|
||||
* 如果状态为 `SUCCESS`,记录 `model_output_path`, `feature_map_snapshot`, `metrics_image_path`。
|
||||
|
||||
4. **模型发布 (`publishModel`)**:
|
||||
* 校验任务状态是否为 `SUCCESS`。
|
||||
* 将模型文件从临时目录移动到正式模型目录 `/models/{algo}/{device}/`。
|
||||
* 在 `algorithm_model` 表中插入新记录:
|
||||
* `algorithm_model_id`: 生成 UUID
|
||||
* `version_tag`: 用户输入(如 v1.2)
|
||||
* `feature_map_snapshot`: 从任务表复制
|
||||
* `metrics`: 从任务表复制
|
||||
* `metrics_image_path`: 从任务表复制
|
||||
* `is_current`: 默认为 0(需人工激活)
|
||||
|
||||
### 2.4 Python 算法服务扩展
|
||||
|
||||
需要在 Python 服务中新增以下 API:
|
||||
|
||||
* `POST /v1/train`:
|
||||
* 接收:`dataset_path`, `algorithm_type`, `device_type`, `hyperparameters`。
|
||||
* 动作:启动后台线程/进程进行训练。
|
||||
* 返回:`task_id`。
|
||||
* `GET /v1/train/status/{task_id}`:
|
||||
* 返回:`status` (TRAINING/SUCCESS/FAILED), `progress` (0-100%), `metrics`, `model_path`, `feature_map`, `metrics_image`。
|
||||
|
||||
### 2.5 前端界面开发
|
||||
|
||||
1. **新建训练任务向导**:
|
||||
* **Step 1: 基础配置**
|
||||
* 任务名称:文本框。
|
||||
* 设备类型:下拉框(从字典加载)。
|
||||
* 算法类型:下拉框(GPR, MLP...)。
|
||||
* **Step 2: 数据准备**
|
||||
* 数据源选择:[上传文件] / [选择历史数据]。
|
||||
* 上传组件:支持 .csv, .xlsx。
|
||||
* **Step 3: 参数配置**
|
||||
* 文本框输入 JSON 或 Key-Value 对。
|
||||
* 提供“加载默认参数”按钮。
|
||||
|
||||
2. **训练监控面板**:
|
||||
* 展示任务列表。
|
||||
* 点击“查看详情”进入监控页。
|
||||
* **实时图表**:展示 Loss 曲线。
|
||||
* **评估结果**:展示 RMSE, R2 指标及误差散点图(`metrics_image_path`)。
|
||||
|
||||
3. **模型发布弹窗**:
|
||||
* 输入版本号。
|
||||
* 点击确认后,将训练好的模型正式注册到系统中。
|
||||
|
||||
## 3. 关键问题与解决方案
|
||||
|
||||
1. **训练耗时问题**:
|
||||
* **方案**:后端采用异步调用,前端使用轮询(每 3-5 秒)。Python 端必须使用非阻塞方式执行训练(如 `threading` 或 `Celery`)。
|
||||
|
||||
2. **数据格式校验**:
|
||||
* **方案**:后端在上传阶段需解析 Excel 表头,确保包含必要的特征列。若缺失关键列,直接拒绝上传。
|
||||
|
||||
3. **模型文件管理**:
|
||||
* **方案**:区分“临时模型”和“正式模型”。训练生成的模型先放在临时目录,只有用户确认发布后才移动到正式目录,避免无效模型占用空间。
|
||||
|
||||
4. **特征映射一致性**:
|
||||
* **方案**:训练时必须生成 `feature_map_snapshot`(记录输入特征与 Java 实体属性的对应关系),并将其保存到 `algorithm_model` 表中。推理服务加载模型时,必须读取该快照以正确组装输入数据。
|
||||
|
||||
|
||||
|
||||
## 4. 接口改进
|
||||
1. list接口加上查询条件:
|
||||
* `algoType`: 算法类型(GPR, MLP...)。
|
||||
* `deviceType`: 设备类型(CPU, GPU...)。
|
||||
* `status`: 任务状态(PENDING, TRAINING, SUCCESS, FAILED)。
|
||||
* `name`: 任务名称(模糊查询)。
|
||||
* `page`: 分页页码。
|
||||
* `size`: 每页数量(默认 10)。
|
||||
2. submit 接口加上MultipartFile file 非必须参数
|
||||
* `datasetPath`: 数据集路径(上传时返回的路径)。--这个需要根据是否上传文件来判断是否需要
|
||||
、
|
||||
3.超参数面板
|
||||
GPR根据类型获取超参数面板。
|
||||
[
|
||||
{
|
||||
"name": "RBF 平滑尺度",
|
||||
"key": "rbf_length_scale",
|
||||
"description": "控制模型整体平滑程度。值越小模型越敏感,值越大预测曲线越平滑。",
|
||||
"default": 1.0,
|
||||
"range": [0.01, 100],
|
||||
"category": "基础参数"
|
||||
},
|
||||
{
|
||||
"name": "RQ 平滑尺度",
|
||||
"key": "rq_length_scale",
|
||||
"description": "控制多尺度变化的平滑程度,用于描述局部变化特征。",
|
||||
"default": 1.0,
|
||||
"range": [0.01, 100],
|
||||
"category": "基础参数"
|
||||
},
|
||||
{
|
||||
"name": "RQ 多尺度系数",
|
||||
"key": "rq_alpha",
|
||||
"description": "控制多尺度变化强度。值越小多尺度变化越明显,值越大模型趋近于RBF。",
|
||||
"default": 1.0,
|
||||
"range": [0.1, 10]
|
||||
},
|
||||
{
|
||||
"name": "噪声水平",
|
||||
"key": "noise_level",
|
||||
"description": "数据观测噪声大小,用于提升模型鲁棒性。",
|
||||
"default": 1e-5,
|
||||
"range": [1e-8, 1e-1],
|
||||
"category": "基础参数"
|
||||
},
|
||||
{
|
||||
"name": "优化重启次数",
|
||||
"key": "optimizer_restarts",
|
||||
"description": "模型超参数优化时的随机重启次数,用于避免陷入局部最优。",
|
||||
"default": 5,
|
||||
"range": [0, 20],
|
||||
"category": "训练参数"
|
||||
}
|
||||
]
|
||||
|
||||
生成这样的数据:{
|
||||
"rbf_length_scale": 2.0,
|
||||
"rq_length_scale": 1.5,
|
||||
"rq_alpha": 0.8,
|
||||
"noise_level": 1e-4,
|
||||
"optimizer_restarts": 10
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
134
模型训练面板编码实现规划.md
Normal file
134
模型训练面板编码实现规划.md
Normal file
@ -0,0 +1,134 @@
|
||||
# 模型训练面板编码实现规划
|
||||
|
||||
本规划基于《模型训练面板实现过程.md》,旨在提供具体的编码指导。**核心原则:简化开发,直接使用 Domain 实体,避免繁琐的 DTO 转换。**
|
||||
|
||||
## 1. 数据库与实体层
|
||||
|
||||
### 1.1 数据库表 (`model_train_task`)
|
||||
请确保数据库已执行以下 SQL:
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS `model_train_task` (
|
||||
`task_id` char(36) NOT NULL COMMENT '任务ID',
|
||||
`task_name` varchar(100) DEFAULT NULL COMMENT '任务名称',
|
||||
`algorithm_type` varchar(50) DEFAULT NULL COMMENT '算法类型',
|
||||
`device_type` varchar(50) DEFAULT NULL COMMENT '设备类型',
|
||||
`dataset_path` varchar(255) DEFAULT NULL COMMENT '数据集路径',
|
||||
`train_params` json DEFAULT NULL COMMENT '训练参数',
|
||||
`status` varchar(20) DEFAULT 'PENDING' COMMENT '状态',
|
||||
`metrics` json DEFAULT NULL COMMENT '训练指标',
|
||||
`model_output_path` varchar(255) DEFAULT NULL COMMENT '临时模型路径',
|
||||
`feature_map_snapshot` json DEFAULT NULL COMMENT '特征映射',
|
||||
`metrics_image_path` varchar(255) DEFAULT NULL COMMENT '指标图路径',
|
||||
`error_log` text DEFAULT NULL COMMENT '错误日志',
|
||||
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`task_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
```
|
||||
|
||||
### 1.2 Domain 实体 (`ModelTrainTask.java`)
|
||||
* **位置**: `com.yfd.business.css.domain`
|
||||
* **注解**: `@TableName("model_train_task")`, `@TableId(type = IdType.ASSIGN_UUID)`
|
||||
* **JSON 字段处理**: 使用 MyBatis-Plus 的 `@TableField(typeHandler = JacksonTypeHandler.class)` 处理 `trainParams`, `metrics`, `featureMapSnapshot` 等 JSON 字段。建议直接映射为 `Map<String, Object>` 或 `JsonNode`,或者简单的 `String`(前端解析)。为了简化,使用 `String` 存储 JSON 字符串。
|
||||
|
||||
```java
|
||||
@Data
|
||||
@TableName(value = "model_train_task", autoResultMap = true)
|
||||
public class ModelTrainTask implements Serializable {
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String taskId;
|
||||
private String taskName;
|
||||
private String algorithmType;
|
||||
private String deviceType;
|
||||
private String datasetPath;
|
||||
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Object> trainParams; // 或 String
|
||||
|
||||
private String status; // PENDING, TRAINING, SUCCESS, FAILED
|
||||
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Object> metrics;
|
||||
|
||||
private String modelOutputPath;
|
||||
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Object> featureMapSnapshot;
|
||||
|
||||
private String metricsImagePath;
|
||||
private String errorLog;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Mapper 层 (`ModelTrainTaskMapper.java`)
|
||||
* **位置**: `com.yfd.business.css.mapper`
|
||||
* **继承**: `BaseMapper<ModelTrainTask>`
|
||||
|
||||
## 3. Service 层
|
||||
|
||||
### 3.1 接口 (`ModelTrainService.java`)
|
||||
* **位置**: `com.yfd.business.css.service`
|
||||
* **继承**: `IService<ModelTrainTask>`
|
||||
* **核心方法**:
|
||||
* `String uploadDataset(MultipartFile file)`: 上传文件,返回路径。
|
||||
* `String submitTask(ModelTrainTask task)`: 提交任务(接收前端传来的实体,补充初始状态后保存,并异步调用 Python)。
|
||||
* `ModelTrainTask syncTaskStatus(String taskId)`: 同步并返回最新状态。
|
||||
* `boolean publishModel(String taskId, String versionTag, String description)`: 发布模型。
|
||||
|
||||
### 3.2 实现 (`ModelTrainServiceImpl.java`)
|
||||
* **位置**: `com.yfd.business.css.service.impl`
|
||||
* **依赖**: `ModelTrainTaskMapper`, `RestTemplate` (调用 Python), `AlgorithmModelService` (发布模型)。
|
||||
|
||||
## 4. Controller 层 (`ModelTrainController.java`)
|
||||
|
||||
* **位置**: `com.yfd.business.css.controller`
|
||||
* **原则**: 直接接收和返回 `ModelTrainTask` 实体或 `Map`。
|
||||
|
||||
### 4.1 接口定义
|
||||
|
||||
1. **上传数据集**
|
||||
* `POST /train/upload`
|
||||
* 参数: `@RequestParam("file") MultipartFile file`
|
||||
* 返回: `Result<String>` (文件路径)
|
||||
|
||||
2. **提交任务**
|
||||
* `POST /train/submit`
|
||||
* 参数: `@RequestBody ModelTrainTask task`
|
||||
* 逻辑: 前端构建好 `task` 对象(包含 name, algoType, deviceType, datasetPath, trainParams),传给后端。后端设置 status=PENDING, save, async call python。
|
||||
|
||||
3. **查询任务列表**
|
||||
* `GET /train/list`
|
||||
* 参数: `PageQuery`, `ModelTrainTask query` (查询条件)
|
||||
* 返回: `Result<Page<ModelTrainTask>>`
|
||||
|
||||
4. **查询任务详情/状态**
|
||||
* `GET /train/status/{taskId}`
|
||||
* 逻辑: 调用 Service 的 `syncTaskStatus`,触发一次 Python 状态查询,更新数据库,然后返回最新实体。
|
||||
|
||||
5. **发布模型**
|
||||
* `POST /train/publish`
|
||||
* 参数: `Map<String, String> body` (包含 taskId, versionTag, description)
|
||||
* 逻辑: 检查状态 -> 移动文件 -> 插入 `algorithm_model` 表。
|
||||
|
||||
## 5. Python 服务交互
|
||||
* **调用方式**: `RestTemplate`
|
||||
* **API 对应**:
|
||||
* Java `submitTask` -> Python `POST /v1/train`
|
||||
* Java `syncTaskStatus` -> Python `GET /v1/train/status/{taskId}`
|
||||
|
||||
## 6. 开发步骤建议
|
||||
|
||||
1. **创建表**:执行 SQL。
|
||||
2. **生成代码**:创建 Domain, Mapper, Service, Controller。
|
||||
3. **实现上传接口**:确保文件能保存到指定目录(如 `data/upload/`)。
|
||||
4. **实现提交接口**:
|
||||
* 先实现保存到数据库。
|
||||
* 再实现 `RestTemplate` 调用 Python(Mock 阶段可先跳过 Python 调用,直接设为 SUCCESS)。
|
||||
5. **实现状态查询**:对接 Python 查询接口。
|
||||
6. **实现发布接口**:操作 `algorithm_model` 表。
|
||||
17
算法描述及原理.md
Normal file
17
算法描述及原理.md
Normal file
@ -0,0 +1,17 @@
|
||||
# 算法描述及原理一句话总结
|
||||
|
||||
**1. 高斯过程回归 (GPR)**
|
||||
* **算法描述**:一种基于概率的非参数回归方法,不仅能预测目标值,还能给出预测的不确定性(置信区间)。
|
||||
* **算法原理**:假设所有观测数据服从一个联合高斯分布,通过核函数衡量样本间的相似性,利用贝叶斯推断由先验分布和观测数据计算出后验分布进行预测。
|
||||
|
||||
**2. 多层感知机 (MLP)**
|
||||
* **算法描述**:一种经典的前馈人工神经网络,通过多层结构学习输入到输出的复杂非线性映射关系。
|
||||
* **算法原理**:由输入层、隐藏层和输出层组成,通过神经元间的权重连接和非线性激活函数传递信号,利用反向传播算法和梯度下降不断调整权重以最小化预测误差。
|
||||
|
||||
**3. 多维线性插值 (N-dimensional Linear Interpolation)**
|
||||
* **算法描述**:一种在多维网格数据中,基于已知离散数据点估算网格内任意点数值的确定性插值方法。
|
||||
* **算法原理**:在目标点所在的多维超立方体网格内,沿各个维度依次进行一维线性插值(即基于距离的加权平均),最终得出该点的平滑过渡值。
|
||||
|
||||
**4. 快速径向基函数网络 (FastRBF)**
|
||||
* **算法描述**:一种改进的径向基函数神经网络,专为处理大规模散乱数据的高效插值和拟合而设计。
|
||||
* **算法原理**:以样本点到中心的欧氏距离为自变量的非线性函数(径向基)为基底,结合快速多极子方法(FMM)或贪心算法来加速求解庞大的线性方程组,实现对高维复杂曲面的快速逼近。
|
||||
@ -3,18 +3,20 @@
|
||||
## 1. 目标与原则
|
||||
|
||||
### 1.1 业务目标
|
||||
|
||||
- framework 模块:沉淀系统级通用能力(安全、认证、权限、日志、任务调度、文件、缓存、监控、通用工具等),**不依赖任何业务代码**,可被 N 个业务模块复用
|
||||
- business-css 模块:仅聚焦“临界事故情景分析”业务,**零系统代码**,所有共性能力通过 framework 提供
|
||||
|
||||
### 1.2 设计原则
|
||||
|
||||
| 原则 | 落地要求 |
|
||||
|----|----|
|
||||
| ---------- | ------------------------------------ |
|
||||
| **高内聚低耦合** | 业务模块只依赖 framework,framework 绝不反向依赖业务 |
|
||||
| **DRY** | 同一能力只在一个地方实现(framework),禁止业务模块重复造轮子 |
|
||||
| **可演进** | 后续新增业务模块(business-xxx)零改动即可接入现有能力 |
|
||||
| **可维护** | 通过 Maven 多模块 + 分层分包,让“修改点”收敛到最小范围 |
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 2. 多模块 Maven 结构(聚合工程)
|
||||
|
||||
@ -31,13 +33,14 @@ d:\JavaProjectSpace (root pom, packaging=pom)
|
||||
└── pom.xml ← modules 声明
|
||||
```
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 3. framework 模块职责与目录
|
||||
|
||||
### 3.1 职责矩阵
|
||||
|
||||
| 能力域 | 是否包含 | 说明 |
|
||||
|----|----|----|
|
||||
| ------- | ---- | ------------------------------------------------- |
|
||||
| 统一配置 | ✅ | 数据源、Redis、Jackson、MyBatis-Plus、Swagger、监控、日志、加解密等 |
|
||||
| 安全 & 认证 | ✅ | Spring Security + JWT 过滤器、权限注解、匿名访问标记 |
|
||||
| 系统级 API | ✅ | 用户/角色/菜单/部门/字典/日志/文件/消息/定时任务等 |
|
||||
@ -46,6 +49,7 @@ d:\JavaProjectSpace (root pom, packaging=pom)
|
||||
| 业务代码 | ❌ | 禁止出现任何与“临界事故”相关的类、表、API |
|
||||
|
||||
### 3.2 代码分层
|
||||
|
||||
```
|
||||
src/main/java/com/yfd/platform
|
||||
├── config # 自动配置类(DataSource、Security、Async、Redis、MyBatisPlus...)
|
||||
@ -67,6 +71,7 @@ src/main/java/com/yfd/platform
|
||||
```
|
||||
|
||||
### 3.3 资源目录
|
||||
|
||||
```
|
||||
src/main/resources
|
||||
├── mapper/system/*.xml # 仅系统表 SQL 映射
|
||||
@ -77,19 +82,21 @@ src/main/resources
|
||||
|
||||
> **注意**:framework 绝不放业务 SQL、业务静态页面;业务资源全部下沉到业务模块。
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 4. business-css 模块职责与目录
|
||||
|
||||
### 4.1 职责矩阵
|
||||
|
||||
| 能力域 | 是否包含 | 说明 |
|
||||
|----|----|----|
|
||||
| ------- | ---- | ---------------------------- |
|
||||
| 业务领域代码 | ✅ | 临界事故实体、服务、控制器、DTO、Mapper XML |
|
||||
| 业务静态页面 | ✅ | 仅与“临界事故”相关的页面、图片、图标 |
|
||||
| 系统能力 | ❌ | 通过依赖 framework 获得,禁止复制粘贴 |
|
||||
| 系统表 SQL | ❌ | 系统表由 framework 提供,业务模块只写业务表 |
|
||||
|
||||
### 4.2 代码分层
|
||||
|
||||
```
|
||||
src/main/java/com/yfd/business/css
|
||||
├── model # 业务实体 / DTO / VO(仅业务表)
|
||||
@ -100,6 +107,7 @@ src/main/java/com/yfd/business/css
|
||||
```
|
||||
|
||||
### 4.3 资源目录
|
||||
|
||||
```
|
||||
src/main/resources
|
||||
├── mapper/css/*.xml # 仅业务表 SQL 映射
|
||||
@ -107,57 +115,58 @@ src/main/resources
|
||||
└── application.yml # 业务个性化配置(端口、数据源 URL、业务开关)
|
||||
```
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 5. 依赖关系与 Maven 坐标
|
||||
|
||||
| 模块 | 坐标 | 依赖 |
|
||||
|----|----|----|
|
||||
| ------------ | --------------------------------- | ------------------------------------------------------ |
|
||||
| framework | com.yfd:platform:1.0 | 无业务依赖,仅技术栈(Spring Boot、MyBatis-Plus、Security、Redis...) |
|
||||
| business-css | com.yfd:business-css:1.0-SNAPSHOT | com.yfd:platform:1.0(plain classifier) |
|
||||
|
||||
> **plain classifier**:framework 通过 `maven-jar-plugin` 额外生成 `platform-1.0-plain.jar`,仅含 classes & resources,不含 Spring-Boot 启动器,避免业务模块引入重复主类。
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 6. 配置隔离策略
|
||||
|
||||
| 配置项 | 放在哪里 | 示例 |
|
||||
|----|----|----|
|
||||
| --------------------------- | ------------ | ------------------------------------------------- |
|
||||
| 数据源、Redis、MyBatis、线程池、监控、日志 | framework | `framework/src/main/resources/application.yml` |
|
||||
| 业务开关、业务参数、端口、上下文 | business-css | `business-css/src/main/resources/application.yml` |
|
||||
| 环境差异化(dev/prod) | 各自模块 | `application-dev.yml`、`application-prod.yml` |
|
||||
|
||||
> **启动顺序**:业务模块的 `application.yml` 会覆盖 framework 的同名 key,实现“共性 + 个性”组合。
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 7. 静态资源隔离策略
|
||||
|
||||
| 资源类型 | 放在哪里 | 访问路径 | 说明 |
|
||||
|----|----|----|----|
|
||||
| ---------------------------- | ------------ | --------------------------- | ---------- |
|
||||
| 全局通用(swagger、error、login 背景) | framework | `/error`、`/swagger-ui.html` | 所有业务模块共用 |
|
||||
| 业务页面(*.html、*.js、*.png) | business-css | `/css/index.html` | 仅当前业务使用 |
|
||||
| 业务页面(*.html、*.js、\*.png) | business-css | `/css/index.html` | 仅当前业务使用 |
|
||||
| 业务接口 | business-css | `/api/simulation/*` | REST 无静态冲突 |
|
||||
|
||||
> **最佳实践**:业务静态统一放在 `/static/{业务简称}/` 目录,避免文件名冲突。
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 8. 数据库隔离策略
|
||||
|
||||
| 表归属 | 模块 | 说明 |
|
||||
|----|----|----|
|
||||
| 系统表(sys_user、sys_role、sys_menu...) | framework | 由 framework 提供 Mapper & XML,业务模块只读/调用 Service |
|
||||
| 业务表(css_simulation、css_record...) | business-css | 由业务模块自行创建 Mapper & XML,禁止写入系统表 SQL |
|
||||
| ------------------------------------- | ------------ | --------------------------------------------- |
|
||||
| 系统表(sys\_user、sys\_role、sys\_menu...) | framework | 由 framework 提供 Mapper & XML,业务模块只读/调用 Service |
|
||||
| 业务表(css\_simulation、css\_record...) | business-css | 由业务模块自行创建 Mapper & XML,禁止写入系统表 SQL |
|
||||
|
||||
> **多业务共享同一库**:系统表前缀 `sys_`,业务表前缀 `css_`、`xxx_`,物理共存但逻辑隔离。
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 9. 启动与部署
|
||||
|
||||
### 9.1 开发阶段
|
||||
|
||||
```bash
|
||||
# 1. 安装 framework 到本地仓库
|
||||
mvn -DskipTests clean install -pl framework
|
||||
@ -170,6 +179,7 @@ mvn -DskipTests spring-boot:run -pl business-css
|
||||
```
|
||||
|
||||
### 9.2 交付阶段
|
||||
|
||||
```bash
|
||||
# 一次性打包所有模块
|
||||
mvn -DskipTests clean package
|
||||
@ -180,10 +190,11 @@ business-css/target/business-css-1.0-SNAPSHOT.jar # 业务服务(含内嵌 To
|
||||
```
|
||||
|
||||
> **部署方式**:
|
||||
>
|
||||
> - 轻量场景:只部署 `business-css-1.0-SNAPSHOT.jar`,内嵌 framework 能力
|
||||
> - 分离场景:独立部署 `platform-1.0.jar`(提供统一后台),再部署多个业务 jar,网关统一路由
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 10. 横向扩展:新增业务模块(business-xxx)
|
||||
|
||||
@ -197,46 +208,56 @@ business-css/target/business-css-1.0-SNAPSHOT.jar # 业务服务(含内嵌 To
|
||||
|
||||
**零改动接入**:无需复制任何系统代码,仅需以上 7 步即可拥有完整的用户/权限/日志/文件/任务能力。
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 11. 常见误区与禁止项
|
||||
|
||||
| 误区 | 正确做法 |
|
||||
|----|----|
|
||||
| -------------------------------- | -------------------------------------- |
|
||||
| 把系统表 SQL 写在业务模块 | 系统 SQL 只能放在 framework/mapper/system |
|
||||
| 把系统静态页面(login、404)复制到业务模块 | 全局静态统一收敛到 framework/static |
|
||||
| 业务模块直接依赖 `platform-1.0.jar`(可执行) | 使用 `platform-1.0-plain.jar`(仅 classes) |
|
||||
| framework 里出现“css”字样 | framework 必须业务无关,出现业务代码即重构 |
|
||||
| 多个业务模块端口重复 | 每个业务模块独立端口(8082、8083...) |
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
## 12. 演进路线
|
||||
|
||||
| 阶段 | 动作 |
|
||||
|----|----|
|
||||
| ------- | ------------------------------------------------------------- |
|
||||
| **当前** | 单库多模块,Maven 聚合,静态/配置/表逻辑隔离 |
|
||||
| **下一步** | 引入 Spring Cloud Gateway,统一路由 & 鉴权,业务模块只关注领域逻辑 |
|
||||
| **未来** | 业务模块拆分为独立微服务(docker-compose/k8s),framework 作为共享 lib 或 sidecar |
|
||||
|
||||
---
|
||||
***
|
||||
|
||||
> **一句话总结**:framework 做“平台”,business-css 做“产品”;平台沉淀,产品迭代,互不污染,横向复制。
|
||||
|
||||
## 快速稳定方案(作用:脚本先设置 JAVA_HOME 与 PATH 指向 17,再调用 Maven,确保所有构建/运行都用 JDK 17,不受工具自带 JDK 8 影响。)
|
||||
## 快速稳定方案(作用:脚本先设置 JAVA\_HOME 与 PATH 指向 17,再调用 Maven,确保所有构建/运行都用 JDK 17,不受工具自带 JDK 8 影响。)
|
||||
|
||||
使用项目内脚本强制 JDK 17(已为你添加):
|
||||
scripts\mvn17.cmd -s mvn-settings.xml -DskipTests -pl framework -am install
|
||||
|
||||
scripts\mvn17.cmd -s mvn-settings.xml -DskipTests -f business-css\pom.xml spring-boot:run -Dspring-boot.run.profiles=business
|
||||
## 后端启动方法
|
||||
|
||||
- debug方式启动
|
||||
scripts\mvn17-debug.cmd -s mvn-settings.xml -DskipTests -f business-css\pom.xml spring-boot:run -Dspring-boot.run.profiles=business
|
||||
scripts\mvn17.cmd -DskipTests -f business-css\pom.xml spring-boot:run "-Dspring-boot.run.profiles=business"
|
||||
|
||||
参数说明:
|
||||
|
||||
- -f business-css\pom.xml :指定要运行的模块 POM 文件。
|
||||
- -DskipTests :跳过单元测试,加快启动速度。
|
||||
- spring-boot:run :运行 Spring Boot 应用。
|
||||
- -Dspring-boot.run.profiles=business :激活 business 配置文件(对应 application-business.yml ),加载业务专用配置。
|
||||
- 调试模式启动
|
||||
scripts\mvn17-debug.cmd -DskipTests -f business-css\pom.xml spring-boot:run "-Dspring-boot.run.profiles=business"
|
||||
|
||||
## 在工具内终端验证并调整到 17:
|
||||
|
||||
- 验证: mvn -version 、 where java 、 where mvn
|
||||
- 临时修正当前终端(一次性手动):
|
||||
- set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot"
|
||||
- set "PATH=%JAVA_HOME%\bin;%PATH%"
|
||||
- set "JAVA\_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot"
|
||||
- set "PATH=%JAVA\_HOME%\bin;%PATH%"
|
||||
- 再 mvn -version 应为 17
|
||||
|
||||
## 开发模式
|
||||
@ -244,7 +265,6 @@ scripts\mvn17-debug.cmd -s mvn-settings.xml -DskipTests -f business-css\pom.xml
|
||||
- 进入前端目录: business-css/frontend
|
||||
- 安装依赖: npm install
|
||||
- 启动开发服务器: npm run dev
|
||||
- 访问: http://localhost:3000/
|
||||
- 访问: <http://localhost:3000/>
|
||||
|
||||
set "PATH=d:/Program Files/nodejs;%PATH%"
|
||||
|
||||
|
||||
65
训练任务数据.md
Normal file
65
训练任务数据.md
Normal file
@ -0,0 +1,65 @@
|
||||
# 训练任务回填数据
|
||||
|
||||
根据现有的 `algorithm_model` 数据,生成了对应的 `model_train_task` 回填 SQL 语句。这些数据代表了系统中已存在的模型训练记录。
|
||||
|
||||
## 映射规则说明
|
||||
* **Task ID**:复用 `algorithm_model_id`,以保持与模型表的关联(实际场景中可能通过此 ID 关联,或视作一次性导入)。
|
||||
* **Task Name**:自动生成格式 `Import_{Algorithm}_{Device}_{Version}`。
|
||||
* **Status**:统一设为 `SUCCESS`,因为这些模型已经发布。
|
||||
* **Dataset Path / Train Params**:由于原表无此信息,设为默认占位符。
|
||||
* **Metrics / Feature Map**:直接从原表复制。
|
||||
|
||||
## SQL 插入语句
|
||||
|
||||
请在数据库中执行以下 SQL 语句以完成数据回填:
|
||||
|
||||
```sql
|
||||
INSERT INTO `model_train_task` (
|
||||
`task_id`,
|
||||
`task_name`,
|
||||
`algorithm_type`,
|
||||
`device_type`,
|
||||
`dataset_path`,
|
||||
`train_params`,
|
||||
`status`,
|
||||
`metrics`,
|
||||
`model_output_path`,
|
||||
`feature_map_snapshot`,
|
||||
`metrics_image_path`,
|
||||
`error_log`,
|
||||
`created_at`,
|
||||
`updated_at`
|
||||
) VALUES
|
||||
(
|
||||
'a3c3b6b0-6c2f-4f9c-9b77-2b9d3c8a1f02',
|
||||
'Import_GPR_AnnularTank_V1',
|
||||
'GPR',
|
||||
'AnnularTank',
|
||||
'Unknown (Historical Import)',
|
||||
'{}',
|
||||
'SUCCESS',
|
||||
'{\"r2\": 0.991, \"mae\": 0.007, \"maxe\": 0.034, \"rmse\": 0.012}',
|
||||
'E:/python_coding/keffCenter/models/GPR/AnnularTank/V1/pipeline.pkl',
|
||||
'{\"直径\": \"diameter\", \"高度\": \"height\", \"钚浓度\": \"fissile_concentration\", \"pu_isotope\": \"isotopic_abundance\", \"pu_concentration\": \"fissile_concentration\", \"钚同位素比例\": \"isotopic_abundance\"}',
|
||||
'GPR/AnnularTank/V1/error.png',
|
||||
NULL,
|
||||
'2025-12-26 07:53:27',
|
||||
'2026-01-20 07:25:28'
|
||||
),
|
||||
(
|
||||
'a3c3b6b0-6c2f-4f9c-9b77-2b9d3c8a1f01',
|
||||
'Import_GPR_CylindricalTank_v1',
|
||||
'GPR',
|
||||
'CylindricalTank',
|
||||
'Unknown (Historical Import)',
|
||||
'{}',
|
||||
'SUCCESS',
|
||||
'{\"r2\": 0.991, \"mae\": 0.007, \"maxe\": 0.034, \"rmse\": 0.012}',
|
||||
'E:/python_coding/keffCenter/models/GPR/CylindricalTank/v1/pipeline.pkl',
|
||||
'{\"直径\": \"diameter\", \"高度\": \"height\", \"铀浓度\": \"fissile_concentration\", \"u_enrichment\": \"isotopic_abundance\", \"铀富集度\": \"isotopic_abundance\", \"u_concentration\": \"fissile_concentration\"}',
|
||||
'GPR/CylindricalTank/V1/error.png',
|
||||
NULL,
|
||||
'2025-12-26 07:34:05',
|
||||
'2026-01-20 07:25:22'
|
||||
);
|
||||
```
|
||||
55
设备size处理.md
Normal file
55
设备size处理.md
Normal file
@ -0,0 +1,55 @@
|
||||
1.设备有多种类型,为了方便提取尺寸,
|
||||
扁平槽:FlatTank,形状参数(尺寸)json表达:{
|
||||
"length": 100,
|
||||
"width": 40,
|
||||
"height": 15
|
||||
}
|
||||
圆柱槽:CylindricalTank ,形状参数(尺寸)json表达:{
|
||||
"diameter": 200,
|
||||
"height":120
|
||||
}
|
||||
环形槽:AnnularTank,形状参数(尺寸)json表达: {
|
||||
"outer_diameter": 100,
|
||||
"height": 150
|
||||
}
|
||||
管束槽:TubeBundleTank,形状参数(尺寸)json表达:{
|
||||
"outer_diameter":120,
|
||||
"height": 200
|
||||
}
|
||||
萃取柱:ExtractionColumn,形状参数(尺寸)json表达: {
|
||||
"upper_expanded": {
|
||||
"diameter": 40,
|
||||
"height": 150
|
||||
},
|
||||
"tray_section": {
|
||||
"diameter": 100,
|
||||
"height":800
|
||||
},
|
||||
"lower_expanded": {
|
||||
"diameter": 30,
|
||||
"height": 50
|
||||
}
|
||||
}
|
||||
流化床:FluidizedBed,形状参数(尺寸)json表达: {
|
||||
"expanded_section": {
|
||||
"diameter": 120,
|
||||
"height":40
|
||||
},
|
||||
"transition_section": {
|
||||
"height": 60
|
||||
},
|
||||
"reaction_section": {
|
||||
"diameter": 60,
|
||||
"height": 400
|
||||
}
|
||||
}
|
||||
锥底环形槽:ACFTank,形状参数(尺寸)json表达:{
|
||||
"annular_cylinder": {
|
||||
"outer_diameter": 70,
|
||||
"height": 300
|
||||
},
|
||||
"frustum_bottom": {
|
||||
"bottom_diameter": 20,
|
||||
"height": 30
|
||||
}
|
||||
}
|
||||
0
设备类型支持v2.0.txt
Normal file
0
设备类型支持v2.0.txt
Normal file
Loading…
Reference in New Issue
Block a user