Files
planet/docs/collected-data-column-removal-plan.md
2026-03-25 17:19:10 +08:00

5.1 KiB
Raw Blame History

collected_data 强耦合列拆除计划

背景

当前 collected_data 同时承担了两类职责:

  1. 通用采集事实表
  2. 少数数据源的宽表字段承载

典型强耦合列包括:

  • country
  • city
  • latitude
  • longitude
  • value
  • unit

以及 API 层临时平铺出来的:

  • cores
  • rmax
  • rpeak
  • power

这些字段并不适合作为统一事实表的长期 schema。
推荐方向是:

  • 表内保留通用稳定字段
  • 业务差异字段全部归入 metadata
  • API 和前端动态读取 metadata

拆除目标

最终希望 collected_data 只保留:

  • id
  • snapshot_id
  • task_id
  • source
  • source_id
  • entity_key
  • data_type
  • name
  • title
  • description
  • metadata
  • collected_at
  • reference_date
  • is_valid
  • is_current
  • previous_record_id
  • change_type
  • change_summary
  • deleted_at

计划阶段

Phase 1读取层去依赖

目标:

  • API / 可视化 / 前端不再优先依赖宽列表字段
  • 所有动态字段优先从 metadata

当前已完成:

  • 新写入数据时,将 country/city/latitude/longitude/value/unit 自动镜像到 metadata
  • /api/v1/collected 优先从 metadata 取动态字段
  • visualization 接口优先从 metadata 取动态字段
  • 国家筛选已改成只走 metadata->>'country'
  • CollectedData.to_dict() 已切到 metadata-first
  • 变更比较逻辑已切到 metadata-first
  • 已新增历史回填脚本: scripts/backfill_collected_data_metadata.py
  • 已新增删列脚本: scripts/drop_collected_data_legacy_columns.py

涉及文件:

Phase 2写入层去依赖

目标:

  • 采集器内部不再把这些字段当作数据库一级列来理解
  • 统一只写:
    • 通用主字段
    • metadata

建议动作:

  1. Collector 内部仍可使用 country/city/value 这种临时字段作为采集过程变量
  2. 进入 BaseCollector._save_data() 后统一归档到 metadata
  3. CollectedData 模型中的强耦合列已从 ORM 移除,写入统一归档到 metadata

Phase 3数据库删列

目标:

  • collected_data 真正移除以下列:
    • country
    • city
    • latitude
    • longitude
    • value
    • unit

注意:

  • cores / rmax / rpeak / power 当前本来就在 metadata 里,不是表列
  • 这四个主要是 API 平铺字段,不需要数据库删列

当前阻塞点

在正式删列前,还需要确认这些地方已经完全不再直接依赖数据库列:

1. CollectedData.to_dict()

文件:

状态:

  • 已完成

2. 差异计算逻辑

文件:

状态:

  • 已完成
  • 当前已改成比较归一化后的 metadata-first payload

3. 历史数据回填

问题:

  • 老数据可能只有列值,没有对应 metadata

当前方案:

4. 导出格式兼容

文件:

现状:

  • CSV/JSON 导出已基本切成 metadata-first

建议:

  • 删列前再回归检查一次导出字段是否一致

推荐执行顺序

  1. 保持新数据写入时 metadata 完整
  2. 把模型和 diff 逻辑完全切成 metadata-first
  3. 写一条历史回填脚本
  4. 回填后观察一轮
  5. 正式执行删列迁移

推荐迁移 SQL

仅在确认全部读取链路已去依赖后执行:

ALTER TABLE collected_data
DROP COLUMN IF EXISTS country,
DROP COLUMN IF EXISTS city,
DROP COLUMN IF EXISTS latitude,
DROP COLUMN IF EXISTS longitude,
DROP COLUMN IF EXISTS value,
DROP COLUMN IF EXISTS unit;

风险提示

  1. 地图类接口对经纬度最敏感 必须确保所有地图需要的记录,其 metadata.latitude/longitude 已回填完整。

  2. 历史老数据如果没有回填,删列后会直接丢失这些信息。

  3. 某些 collector 可能仍隐式依赖这些宽字段做差异比较,删列前必须做一次全量回归。

当前判断

当前项目已经完成“代码去依赖 + 历史回填 + readiness 检查”。
下一步执行顺序建议固定为:

  1. 先部署当前代码版本并重启后端
  2. 再做一轮功能回归
  3. 最后执行: uv run python scripts/drop_collected_data_legacy_columns.py