ShopTRAINING/xz数据库2025_07_24.md

56 lines
5.0 KiB
Markdown
Raw Normal View History

# 数据库设计方案 (最终版)
本文档定义了项目重构后的核心数据库结构旨在实现对机器学习模型和预测历史的统一、高效管理。该设计方案结合了业务需求、前端UI逻辑、后端代码实现以及现有数据库结构并经过了多次迭代确认。
## 设计原则
- **模型集中化**: 所有模型的元数据统一存储,摆脱对文件系统的依赖。
- **数据一致性**: 通过逻辑外键确保预测记录与模型版本精确关联。
- **查询高性能**: 通过冗余关键字段,避免在查询列表时进行不必要的`JOIN`操作。
- **可扩展性**: 使用JSON字段存储灵活、复杂的范围定义和文件路径适应未来业务变化。
- **结构清晰**: 物理文件(模型、日志、预测结果)与数据库记录分离,数据库只存元数据和路径,保持自身轻量。
---
第一阶段:初步重构与标准化 起点: 最初的系统功能基本,但代码存在重复,缺乏统一标准。我们从修复一个 xgboost_trainer.py 中的 NameError 开始。 核心工作: 统一工件保存: 将所有模型训练脚本 (xgboost, kan, tcn 等) 中保存模型和图表的逻辑进行了重构,提取到 server/utils/visualization.py 和 server/utils/model_manager.py 中,确保了所有训练器都遵循统一、健壮的模式。 修复绘图Bug: 修正了 visualization.py 中损失曲线图文件名生成不正确的bug,并更新了所有训练脚本以适应新的、更通用的 plot_loss_curve 函数。 第二阶段:数据库与API的现代化改造 问题: 原有的数据库设计过于简单,依赖文件名或复合键来识别模型,非常脆弱且难以扩展。 核心工作: 数据库重新设计: 在 server/api.py 中,我对数据库进行了彻底的重新设计。 废弃了旧的 model_versions 表,引入了新的 models 表,为每个模型实例分配一个唯一的 model_uid。此表现在存储了模型的全方位元数据,如类型、训练范围、参数、性能指标和工件路径。 重构了 prediction_history 表,使其通过 model_uid 与 models 表关联,并使用灵活的 JSON 字段(如 prediction_scope)来存储预测范围,以优雅地支持“按产品”、“按店铺”和“全局”等不同模式。 API大规模重构: 数据库的变更引发了对后端API的全面重构。 /api/models: 完全重写,以从新的 models 表中查询数据。 /api/prediction: 接口被简化,现在只接受一个核心参数 model_uid,而不是之前的一系列零散参数。 /api/prediction/history: 同样被重写以适应新的表结构。 第三阶段:前后端联调与Bug修复周期 问题: 后端的重大重构导致了前端功能失效,暴露出前后端接口定义不匹配的问题。 核心工作: 修复模型列表显示: 解决了因后端 /api/models 返回的JSON键与前端期望(product_name, store_name)不符,而导致的“药品名称”和“店铺名称”列为空的问题。 修复预测功能: 解决了因前端向 /api/prediction 发送旧格式的请求体而导致的“预测失败”问题。我修改了所有三个预测视图(ProductPredictionView.vue, StorePredictionView.vue, GlobalPredictionView.vue),使其发送后端现在需要的 model_uid。 修复UI视觉问题: 修复了预测按钮上的加载动画(spinner)失效的问题。原因是前端脚本逻辑中的键已更新为 model_uid,但模板中的 :loading 绑定仍错误地指向了旧的 model_id。 第四阶段:历史记录页面的最终完善 问题: 历史记录页面存在多个深层bug,包括列表为空、数据显示不正确以及筛选功能失效。 核心工作: 修复空列表: 解决了因后端 get_prediction_history 函数查询了不存在的数据库列而导致历史记录为空的问题。修复方案是改用 json_extract 函数来正确查询嵌套在JSON字段中的 product_id。 修正产品名称显示: 解决了列表中产品名称显示为内部标识符的bug。根据您的要求,我在不修改数据库记录的前提下,通过在后端读取数据时动态查询产品名并修正返回给前端的数据,解决了这个问题。 实现动态筛选下拉框: 解决了产品筛选下拉框为空的问题。根据您的最终指示,我修改了 HistoryView.vue,使其从返回的历史记录数据中动态提取唯一的产品列表来填充下拉框,移除了原有的独立API调用,使筛选功能更加智能和高效。
2025-07-24 18:37:58 +08:00
## 预测结果JSON保存到saved_predictions
## 表结构定义
### 表1`models`
这张表是模型管理的核心,负责存储所有模型版本的全生命周期信息。
| 字段名 | 类型 | 确认理由与说明 |
| :--- | :--- | :--- |
| `id` | INTEGER | 主键,系统内部使用。 |
| `model_uid` | TEXT | **[关键]** 用户可见的唯一ID由后端生成用于API调用和逻辑关联。 |
| `display_name` | TEXT | **[建议新增]** 用户可自定义的别名,如“夏季促销模型”,提升易用性。 |
| `model_type` | TEXT | **已确认.** 核心参数,如 `mlstm`, `kan`。 |
| `training_mode` | TEXT | **已确认.** 模型的训练范围: `product`, `store`, `global`。 |
| `training_scope` | TEXT (JSON) | **[最终版]** **精确描述训练范围,并包含中文名。**<br/>- **按药品训练**: `{"product": {"id": "P001", "name": "阿莫西林"}, "stores": "all"}``{"product": {"id": "P001", "name": "阿莫西林"}, "stores": [{"id": "S001", "name": "城西店"}]}`<br/>- **按店铺训练**: `{"store": {"id": "S001", "name": "城西店"}, "products": "all"}``{"store": {"id": "S001", "name": "城西店"}, "products": [{"id": "P001", "name": "阿莫西林"}, {"id": "P002", "name": "布洛芬"}]}`<br/>- **全局训练**: `{"stores": "all", "products": "all"}``{"stores": [{"id": "S001", "name": "城西店"}], "products": [{"id": "P001", "name": "阿莫西林"}]}` |
| `parent_model_id` | INTEGER | **已确认.** 外键,指向自身 `id`,用于实现“继续训练”功能,形成版本链。 |
| `version` | TEXT | **已确认.** 模型版本号,如 `v1`, `v2`。 |
| `status` | TEXT | **已确认.** 模型状态,如 `active`, `archived`,用于控制模型是否可用。 |
| `training_params` | TEXT (JSON) | **已确认.** 存储训练时的超参数,如 `{"epochs": 50, "aggregation_method": "sum"}`。 |
| `performance_metrics` | TEXT (JSON) | **已确认.** 存储性能指标,如 `{"R2": 0.85, "RMSE": ...}`。 |
| `artifacts` | TEXT (JSON) | **[采纳建议]** **存储与模型相关的所有文件路径。** 所有文件均采用**扁平化结构**存放在 `saved_models/` 目录下。示例:<br/>`{"best_model": "saved_models/product_P001_mlstm_best.pth", "versioned_model": "saved_models/product_P001_mlstm_v1.pth", "loss_curve_plot": "saved_models/product_P001_mlstm_v1_loss.png", "loss_curve_data": "saved_models/product_P001_mlstm_v1_history.json"}` |
| `created_at` | DATETIME | **已确认.** 模型的创建时间。 |
---
### 表2`prediction_history`
这张表用于记录每一次预测任务的结果,其结构在现有基础上进行了优化,以实现高效查询和完整追溯。
| 字段名 | 类型 | 确认理由与说明 |
| :--- | :--- | :--- |
| `id` | INTEGER | **已确认.** 主键,自增。 |
| `prediction_uid` | TEXT | **已确认.** 唯一的预测ID (UUID)用于API调用。 |
| `model_id` | TEXT | **[核心变更]** **使用的模型的唯一标识符。** 在重构后,此字段的值应该与 `models` 表中的某条记录的 `model_uid` 相对应,从而建立起逻辑关联。 |
| `model_type` | TEXT | **已确认 (冗余).** 冗余存储模型类型(如 `mlstm`),用于在不关联查询的情况下快速筛选历史记录。 |
| `product_name` | TEXT | **已确认 (冗余).** **冗余存储产品/店铺的中文名**,用于在列表页快速展示,极大提升查询性能。 |
| `prediction_scope` | TEXT (JSON) | **[新增]** 描述本次预测的范围,与 `models` 表的 `training_scope` 结构类似,指明是为哪个产品/店铺做的预测。 |
| `prediction_params` | TEXT (JSON) | **已确认.** 存储预测参数,如 `{"start_date": "...", "future_days": 7}`。 |
| `metrics` | TEXT (JSON) | **已确认 (冗余).** 缓存的性能指标,用于列表展示和排序。 |
| `result_file_path` | TEXT | **[已采纳您的规范]** 指向预测结果JSON文件的**相对路径**。文件存储在 `saved_predictions/` 目录下,并根据模型名和时间戳命名,例如:`saved_predictions/cnn_bilstm_attention_global_sum_v6_pred_20250724111600.json`。 |
| `created_at` | DATETIME | **已确认.** 记录的创建时间。 |