微信小程序页面迁移校验之前 P5任务处理之前
This commit is contained in:
112
scripts/ops/_final_spi_diagnosis_report.py
Normal file
112
scripts/ops/_final_spi_diagnosis_report.py
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user