---
name: guanbi-etl-rewrite
description: 当用户要把观远 BI 里已有 SmartETL / 数据集链路完整重写成仅含 SQL 节点的新链路，并要求在看板副本上替换新数据源、逐卡对比、定位差异层级、处理空快照阻塞时，使用这个 skill。它强调“全链路追到原始源”，不接受只重写最终 ADS。
---

# guanbi-etl-rewrite

## 何时使用

- 用户明确要求把既有 SmartETL “完整”改写成 SQL 版 SmartETL。
- 目标不仅是重建数据集，还包括页面副本替换和卡片级验收。
- 需要把旧 ETL 当作只读参考，重新梳理页面、数据集、ETL DAG、源数据。
- 需要判断差异到底来自页面配置、执行快照时点、还是某一层数据链。
- 需要处理“上游空快照，但链路定义仍要重写完”的场景。

如果用户只是在观远里新建一个 SQL 节点数据集，不涉及旧链迁移、页面替换和链路审计，不用这个 skill，优先用 `guanbi-skill` 或 `guandata-smartetl-sql`。

## 目标定义

交付不是“SQL 能跑”这么简单，而是同时满足下面 4 件事：

1. 旧链所有参与本次范围的 ETL 加工都被新 SQL 链替代。
2. 新链只依赖原始表/表单/文件/系统内置表或本轮新 SQL 中间层，不再依赖旧 ETL 数据集。
3. 新数据集能挂到页面副本上，且卡片结果可与原页比对。
4. 对无法验收的部分，必须把阻塞点上推到真正的空源或权限/平台问题，不能含糊写成“已完成”。

## 硬规则

- 全链路重写。不能只改最终 ADS，必须继续上追，直到原始源。
- 旧资产只读。旧文档、旧 ETL、旧数据集只作为参考，不作为本轮交付对象。
- 新结果放新目录。用子目录隔离新旧对象，正式对象名保持业务原名。
- 新 SmartETL 只允许 SQL 节点。不要混回可视化清洗节点。
- SQL 输入只引用已连接输入，如 `input1`、`input2`，不要赌平台按对象名解析。
- 验收分两层：
  - 结构验收：字段、行列规模、依赖关系、是否 `FINISHED`
  - 数值验收：与原数据集或页面卡片对齐
- 空快照不是“完成”。如果原始源为空，只能写成“新链已重写完成，但数值验收硬阻塞”。
- 页面验收只看副本页，不直接改原页。

## 标准工作流

### 1. 先锁定范围和命名

- 明确正式页面、正式数据集、排除范围。
- 明确本轮新 ETL 目录和新数据集目录。
- 建 ExecPlan，写清：
  - 正式范围
  - 只读历史
  - 命名规则
  - 暂停条件
  - 验收标准

### 2. 从页面往下重新拉血缘

- 从页面卡片清单重新盘点：
  - 卡片绑定的数据集
  - selector / 参数卡
  - 页面默认筛选器
  - 页面运行时 payload
- 对每个正式数据集，拉数据集详情和 ETL DAG。
- 标注哪些输入是：
  - 原始源
  - 旧 ETL 数据集
  - 系统表
  - 当前页面不在范围内的旁路输入

### 3. 先判断“是否已经到原始源”

判断口径很严格：

- 如果输入是表单、Excel、ADLS、数据库物理表、系统内置时间表，可以视为源。
- 如果输入是 `DATAFLOW` 且背后还有 ETL，就还没到底，必须继续追。
- 不要因为名字叫 `清洗_*`、`ods_*`、`report_*` 就误判成源。

### 4. 重建顺序

按“最上游老 ETL 先重写，再往下游收口”的顺序推进。

推荐顺序：

1. 先重写被多个下游复用的清洗层 / 中间层。
2. 再重写共享中间 ADS。
3. 最后重跑最终消费 ADS。
4. 最后再做页面副本切换。

这样能避免反复改下游输入。

### 5. 每个对象的重建模板

对每个待重建对象，至少固定这些信息：

- 原 ETL 定义文件
- 目标输出 selector
- 目标输出名称
- 结构对齐所参考的 schema 数据集
- 需要替换成“本轮新数据集”的输入 override

如果是自动从 ETL JSON 编译 SQL，要特别小心：

- `split(col, ']')[1]` 这类数组下标不能误识别成字段引用
- 分组维度重名时要去重
- 空公式列表不能生成非法 `select`
- 列名里如果带换行或特殊字符，最终 SQL 拼接不能破坏原标识符

## 数据集验收方法

每新建一层，至少检查：

- 新 ETL 是否 `FINISHED`
- 新数据集是否真实物化，不是只保存了草稿 ETL
- 行数、列数是否与旧对象一致
- 关键字段名是否一致
- 如果结构不一致，先修这一层，不要急着看页面

如果结构一致但页面不一致，优先检查：

- 上下游执行时点
- 页面筛选是否真正作用到卡片
- selector 是否还绑定旧 ds

## 页面副本验收方法

### 1. 只替换副本页

- 原页保持不动。
- 副本页先替换图表卡，再检查 selector 卡。

### 2. 不要默认相信页面首屏渲染

副本页经常出现两类假差异：

- selector 还挂旧数据集
- 页面默认时间筛选器没有真正传到卡片

因此页面默认渲染不能直接作为最终结论。

### 3. 推荐卡片级验收法

- 先抓原页运行时 payload。
- 把副本卡切到新数据集。
- 用原页真实 payload 去重放副本卡片。
- 这样可以把“页面联动问题”和“数据链问题”拆开。

### 4. 剩余差异的定位顺序

如果某张卡还有差异，按这个顺序查：

1. 先确认卡片和 selector 是否都换到了新 ds。
2. 看时间筛选、参数筛选是否生效。
3. 对比新旧最终 ADS。
4. 找首个不一致层。
5. 再看该层与上游的执行时间。

很多“SQL 错了”的假象，实际是因为新链吃到了更早的快照。

## 差异追踪的实战做法

当页面只剩 1 到 2 张卡不一致时，不要盲改 SQL，按下面顺序压缩范围：

1. 先对比新旧最终数据集的键集合。
2. 再对比有差异的字段，不要一次看全表。
3. 把差异收缩到少量记录。
4. 沿链路往上追，看差异最早出现在哪一层。
5. 对该层再看：
   - SQL 定义是否不同
   - 执行时间是否落后于上游
6. 如果定义相同但时点落后，先补跑最近一层上游，再补跑下游。

经验上，很多残差来自“执行顺序不对”，不是“重写逻辑错了”。

## 空快照处理

如果上游是空的，按下面处理：

1. 继续把链路定义完整重写到源头。
2. 如平台允许，物化出新的空数据集。
3. 在文档里明确写：
   - 根阻塞源是谁
   - 当前行列规模是多少
   - 哪些下游因此为空
4. 结论只能写成：
   - “全链路 SQL 重写完成”
   - “数值验收硬阻塞”

不能写成“已完成对齐”。

## 推荐交付物

至少保留下面这些材料：

- ExecPlan
- `modeling.md`
- `evidence.md`
- 每个对象的完整 SQL
- ETL 保存前定义
- 执行结果
- 数据集搜索/定位结果
- 页面运行时 payload
- 卡片对比结果

目录建议：

```text
output/<restart_tag>/
  modeling.md
  evidence.md
  sql/<object_name>/
  raw/
```

## 常见坑

- 把旧 `DATAFLOW` 当成源头，导致只重写了半条链。
- 只保存 ETL 没执行，却误以为已经有新数据集。
- 页面图表卡换了新 ds，但 selector 还在用旧 ds。
- 时间筛选器没有真正生效，就直接拿页面数字做结论。
- 看到少量差异就修改 SQL，没有先检查上下游执行时点。
- 上游空快照时，为了让页面“有东西看”而接受降级结果。

## 完成标准

只有同时满足下面条件，才能说“替换成功”：

- 新链已追到原始源，不再依赖旧 ETL 数据集。
- 新 SmartETL 全部是 SQL 节点。
- 目标数据集已真实物化并运行成功。
- 页面副本已切到新数据集。
- 非阻塞范围内，卡片级结果与原页一致。
- 阻塞范围内，根因已被定位到真实空源或平台限制，并明确留证。

