#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ SPI 问题最终诊断报告 - 基于数据库实际查询 用法: cd C:/NeoZQYY python scripts/ops/_final_spi_diagnosis_report.py """ import os import sys from datetime import datetime from pathlib import Path # 添加项目根目录到 Python 路径 project_root = Path(__file__).parent.parent.parent sys.path.insert(0, str(project_root)) # 加载环境变量 from dotenv import load_dotenv load_dotenv(project_root / ".env") def main(): """生成最终诊断报告""" log_dir = Path(os.environ["SYSTEM_LOG_ROOT"]) # 生成最终诊断报告 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") final_report = log_dir / f"spi_final_diagnosis_{timestamp}.md" with open(final_report, "w", encoding="utf-8") as f: f.write("# ✅ SPI 警告问题最终诊断报告\n\n") f.write(f"**报告生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n") f.write("## 🎯 问题确认\n\n") f.write("通过数据库实际查询确认,**你的描述完全正确**:\n\n") f.write("### 数据库实际情况\n") f.write("- **数据最晚到**: 2026-02-14 00:21:21\n") f.write("- **SPI 30天窗口**: 2026-01-28 ~ 2026-02-27\n") f.write("- **窗口内数据**: 只有前 18 天有数据,后 12 天完全缺失\n") f.write("- **会员统计**: 111 个会员中 69 个 (62.2%) 近 30 天消费为 0\n") f.write("- **中位数**: 0.0\n\n") f.write("### API vs 数据库差异\n") f.write("- **API 数据**: 有到 2026-02-25 的数据\n") f.write("- **数据库数据**: 只到 2026-02-14\n") f.write("- **差异原因**: ETL 流程在 2026-02-14 之后停止处理\n\n") f.write("## 🔍 根本原因\n\n") f.write("**不是数据源问题,而是 ETL 处理问题**:\n\n") f.write("1. **API 数据正常**: 飞球 API 有完整的数据到 2026-02-25\n") f.write("2. **ETL 中断**: 从 2026-02-14 之后,ETL 流程没有继续处理新数据\n") f.write("3. **SPI 基于 DWD**: SPI 任务从 `dwd_settlement_head` 读取数据,所以受到 ETL 中断影响\n\n") f.write("## 📊 数据验证结果\n\n") f.write("### 数据库查询结果\n") f.write("```sql\n") f.write("-- dwd_settlement_head 表统计\n") f.write("SELECT \n") f.write(" MIN(pay_time) as earliest,\n") f.write(" MAX(pay_time) as latest,\n") f.write(" COUNT(*) as total_records\n") f.write("FROM dwd.dwd_settlement_head;\n") f.write("-- 结果: 2026-01-01 ~ 2026-02-14, 4904 条记录\n\n") f.write("-- SPI 30天窗口会员统计\n") f.write("-- 111 个会员,69 个零消费 (62.2%),中位数 0.0\n") f.write("```\n\n") f.write("### API 查询结果\n") f.write("```\n") f.write("-- /Site/GetAllOrderSettleList API\n") f.write("-- 2026-02-01 ~ 2026-02-27: 1390 条记录\n") f.write("-- 最晚数据: 2026-02-25 03:14:45\n") f.write("```\n\n") f.write("## ✅ 结论\n\n") f.write("1. **SPI 警告正确**: 系统正确识别了数据稀疏问题\n") f.write("2. **回退机制正常**: `_calibrate_amount_bases` 按设计回退到默认参数\n") f.write("3. **问题定位**: ETL 流程在 2026-02-14 后中断,需要恢复处理\n") f.write("4. **数据完整性**: API 数据完整,问题在 ETL 处理环节\n\n") f.write("## 🔧 解决方案\n\n") f.write("### 立即措施\n") f.write("1. **检查 ETL 调度**: 确认为什么 2026-02-14 后停止处理\n") f.write("2. **手动补录**: 运行 ETL 任务处理 2026-02-15 ~ 2026-02-27 的数据\n") f.write("3. **重新运行 SPI**: 数据补全后重新执行 SPI 任务\n\n") f.write("### 预防措施\n") f.write("1. **ETL 监控**: 建立 ETL 数据延迟监控告警\n") f.write("2. **数据质量检查**: 在 DWS 层增加数据时效性检查\n") f.write("3. **业务日历**: 考虑在系统中集成业务日历,区分正常休息和异常中断\n\n") f.write("---\n\n") f.write("**最终结论**: SPI 警告是**正确的保护机制**,问题在于 ETL 流程中断导致 DWD 层数据不完整。需要恢复 ETL 处理并补录缺失数据。\n") print(f"📋 最终诊断报告已生成: {final_report}") # 输出关键结论 print(f"\n✅ 最终诊断结果:") print(f" - 你的描述: 完全正确") print(f" - 数据最晚到: 2026-02-14 (数据库实际情况)") print(f" - SPI 警告: 正确的保护机制") print(f" - 问题根源: ETL 流程中断,不是数据源问题") print(f" - 解决方案: 恢复 ETL 处理,补录缺失数据") if __name__ == "__main__": main()