# 历史数据回溯 — 变更检测功能开发工作日志 ## 项目概述 项目路径:`e:\workfile\JAVA\AI-Python\AI-Python` 这是一个 Django + React 前后端分离项目,核心功能是从第三方 API(驿达商业平台)拉取数据并存储到本地数据库(达梦/Oracle)。项目包含: - **数据更新定时任务**(`SCHEDULED_UPDATE_TASK` + `DATA_UPDATE_CONFIG`):按配置自动从第三方 API 拉取数据并 upsert 到本地表 - **历史数据回溯**(`HISTORY_BACKFILL_CONFIG`):定期回溯检查历史月份数据是否有变动,按需同步 - **动态查询 API**(`API_CONFIG`):根据配置动态生成本地数据查询接口 ## 本次会话完成的工作 ### 1. 修复本地数据获取 endpoint 错误 ✅ **问题**:`_fetch_local_check_data` 使用 `DATA_UPDATE_CONFIG.NAME`(中文描述名如"更新python语义营收")构造 URL,导致 404。 **修复**: - 修改 [history_backfill_service.py](file:///e:/workfile/JAVA/AI-Python/AI-Python/api/history_backfill_service.py) 的 `_get_data_update_config()` 方法,增加子查询 JOIN `API_CONFIG`,通过 `TARGET_TABLE = TABLE_NAME` 获取正确的 `local_endpoint` - 修改 `_check_month_changed()` 使用 `duc_config['local_endpoint']` 替代 `duc_config['name']` - 同步修复 [history_backfill_views.py](file:///e:/workfile/JAVA/AI-Python/AI-Python/api/history_backfill_views.py) 的 `BackfillCheckPreviewView` ### 2. 清理 DEBUG 日志 ✅ 删除 [dynamic_query_service.py](file:///e:/workfile/JAVA/AI-Python/AI-Python/api/dynamic_query_service.py) 中所有 `[DEBUG]` 级别的 print 语句(约 30 处),包括:SQL 参数、字段匹配、汇总包裹、模糊查询等 ### 3. 改进变更检测日志输出 ✅ 修改 `_check_month_changed()` 的对比逻辑,无论字段匹配与否都输出日志: ``` [DETECT] 202501 | 对客销售 = 一致 | 本地=12345 | 远端=12345 [DETECT] 202501 | 年度累计 ≠ 不同 | 本地=99999 | 远端=88888 [DETECT] 202501 结论: 发现差异,需要全量同步 ``` ### 4. 调整超时时间 ✅ 变更检测的 API 调用超时从 30 秒调整为 120 秒(与全量同步一致)。 ### 5. MonthINCAnalysisProxyView 修改 ✅ 将 `/api/revenue/month-inc-analysis/` 接口的 `ServerpartId` 从必填改为可选。 ### 6. 修复 NEWGETSUMMARYREVENUEMONTH 展平问题(部分完成) 在 [data_processing_utils.py](file:///e:/workfile/JAVA/AI-Python/AI-Python/api/data_processing_utils.py) 的 `process_downloaded_data` 中,对 `NEWGETSUMMARYREVENUE` 和 `NEWGETSUMMARYREVENUEMONTH` 表跳过 `extract_serverpart_data` 步骤。 --- ## 🚨 当前待解决问题 ### 问题:变更检测与全量同步的数据粒度不匹配 **现象**:回溯执行"更新驿达看板首页数据缓存"(NEWGETSUMMARYREVENUEMONTH 表)时,变更检测判定"有差异"后触发全量同步,但全量同步结果全部是"跳过"(数据一致),没有任何实际更新。 **根因分析**: | 阶段 | 调用方式 | 数据粒度 | |---|---|---| | 变更检测(本地) | `GET /api/dynamic/ahydDIBData/?StatisticsStartMonth=202501&StatisticsEndMonth=202501`(不传 ServerpartId) | **省级汇总**(123 条聚合成 1 条) | | 变更检测(远端) | `GET GetSummaryRevenueMonth?pushProvinceCode=340000&StatisticsMonth=202501`(不传 ServerpartId) | **省级汇总**(需确认返回结构) | | 全量同步 | `execute_update_internal` → 按 133 个 ServerpartId 逐个调用第三方 API | **服务区级**(每次 1 条) | **变更检测的两个子问题**: 1. **远端值为 None**:之前字段路径配置错误(用 `CashPay` 而非 `MonthRevenueModel.CashPay`),用户已手动修正为嵌套路径 2. **数据口径不一致**:本地汇总是 dynamic API 的聚合计算结果,远端是第三方 API 不传 ServerpartId 时的返回值,两者可能不是同一个统计口径 **全量同步"跳过123"**: - `execute_update_internal` 调用 `process_downloaded_data` 处理数据 - upsert 按 `STATISTICS_MONTH + SERVERPART_ID` 匹配后,逐字段比对发现数据与数据库完全一致 - 这说明数据确实没变化,跳过是正确行为 - 但如果变更检测一直误判为"有差异",就会每次执行无效的全量同步(浪费资源) --- ## 关键文件说明 | 文件 | 用途 | |---|---| | `api/history_backfill_service.py` | 回溯服务核心:调度、变更检测、执行全量同步 | | `api/history_backfill_views.py` | 回溯 API 视图(CRUD、手动触发、检测预览) | | `api/data_update_internal.py` | 定时任务内部执行函数(被回溯服务调用) | | `api/data_update_views.py` | 数据更新视图(手动执行入口,有完整的行内特殊处理) | | `api/data_processing_utils.py` | 数据处理工具(展平、提取、upsert) | | `api/dynamic_query_service.py` | 动态查询服务(本地数据 API) | | `api/revenue_proxy_views.py` | 第三方 API 代理视图 | | `frontend/src/components/BackfillConfigPage.tsx` | 回溯配置前端页面 | ## 数据库表关系 ``` SCHEDULED_UPDATE_TASK (定时任务) ├── CONFIG_ID → DATA_UPDATE_CONFIG (数据源配置:API URL、目标表、参数映射) └── HISTORY_BACKFILL_CONFIG (回溯配置:TASK_ID → 关联任务) DATA_UPDATE_CONFIG.TARGET_TABLE = API_CONFIG.TABLE_NAME (1:1 或 1:N 映射) API_CONFIG.ENDPOINT → 动态查询 API 的 endpoint 名 ``` ## 后续建议 1. **修正变更检测逻辑**:要么让变更检测也按服务区级别对比(但太慢),要么确认不传 ServerpartId 时第三方 API 返回的省级汇总字段路径完全正确 2. **考虑方案 B**:变更检测直接查数据库比对,绕过 HTTP 调用,避免数据结构适配问题 3. **注意 `data_update_views.py` vs `process_downloaded_data` 的差异**:前者有更完善的行内特殊处理(字段优先级保护、智能唯一键补充),后者是简化版。当前回溯使用后者