150 lines
4.8 KiB
Markdown
150 lines
4.8 KiB
Markdown
---
|
||
name: logic-planner
|
||
description: 当需求和元数据都已经确认,需要把业务逻辑拆成 SQL 生成前的确定性执行步骤时使用。它只规划 source、filter、join、dedupe、transform、window、aggregate、output,不写 SQL,不调用 MCP。
|
||
---
|
||
|
||
# Logic Planner(逻辑规划)
|
||
|
||
## 目标
|
||
|
||
把已确认的 DRD 和元数据拆成可执行计算步骤,让后续 SQL 只是翻译计划,而不是重新猜业务逻辑。
|
||
|
||
## 输入
|
||
|
||
```yaml
|
||
requirements_output:
|
||
status: READY_FOR_METADATA
|
||
validation_result:
|
||
status: VALIDATED
|
||
field_mapping: {}
|
||
joins: []
|
||
```
|
||
|
||
如果元数据没有 `VALIDATED`,停止并回到 `metadata-validator`。
|
||
|
||
## 步骤类型
|
||
|
||
只允许使用这些 `kind`:
|
||
|
||
- `source`:读取哪张表、哪些字段。
|
||
- `filter`:时间、分区、状态、业务条件过滤。
|
||
- `join`:多表关联。
|
||
- `dedupe`:去重,通常在 join 或 aggregate 前。
|
||
- `transform`:派生字段、分类、类型转换、标志位。
|
||
- `window`:首笔、末笔、排名、累计、lag/lead。
|
||
- `aggregate`:分组和指标计算。
|
||
- `output`:最终列、排序、limit 或写入意图。
|
||
|
||
## 工作顺序
|
||
|
||
1. 定义输出粒度:一行代表什么。
|
||
2. 选事实表:承载核心事件或分母人群的表。
|
||
3. 列出 source:每张表只取必要字段。
|
||
4. 尽早放 filter:尤其是时间、分区和状态条件。
|
||
5. 固定时间窗口边界:下界包含、上界排除。
|
||
6. 规划 join:顺序、key、类型、基数假设。
|
||
7. 判断是否需要 dedupe/window:首登、首次注册、首笔成功事件等。
|
||
8. 规划 transform:标志位、事件顺序、空值处理。
|
||
9. 规划 aggregate:group by、指标公式、别名。
|
||
10. 规划 output:输出字段、排序、写入模式。
|
||
|
||
## 时间窗口硬规则
|
||
|
||
当需求为“近 N 天按 T-1 完整日”时,必须规划为:
|
||
|
||
```yaml
|
||
time_window:
|
||
lower_bound_sql: date_sub(current_date(), N)
|
||
upper_bound_sql: current_date()
|
||
boundary: left_closed_right_open
|
||
predicate_sql: event_time >= date_sub(current_date(), N) AND event_time < current_date()
|
||
```
|
||
|
||
禁止规划为 `BETWEEN ... AND date_add(current_date(), -1)`,尤其是 timestamp 字段。
|
||
|
||
## 转化/漏斗硬规则
|
||
|
||
转化类需求必须维护事件顺序。对“注册后成功付费”,推荐计划:
|
||
|
||
1. `first_login`:取窗口内每个用户的首次登录,形成分母。
|
||
2. `registered`:取用户注册事件,必要时去重到一个注册时间。
|
||
3. `qualified_payment`:在关联注册事件后筛选 `pay_status = 'SUCCESS' AND pay_time >= register_time`。
|
||
4. `final_agg`:按维度计算分母、分子和转化率。
|
||
|
||
不要先对全量 `pay_order` 按用户取 `MIN(pay_time)` 再与 `register_time` 比较;这可能漏掉“历史早付费但注册后也付费”的用户。
|
||
|
||
## 必须显式写出的风险
|
||
|
||
- 1:N 或 N:N join 是否会放大事实行。
|
||
- 去重发生在 join 前还是 join 后。
|
||
- 指标是否需要 `count_distinct` 而不是 `count`。
|
||
- 时间过滤是否能命中分区字段。
|
||
- left join 后维度缺失如何处理。
|
||
- 转化事件是否严格满足前后顺序。
|
||
- 分母为 0 时比率如何处理。
|
||
|
||
## 输出格式
|
||
|
||
```yaml
|
||
logic_plan:
|
||
status: PLANNED | NEED_USER_CONFIRMATION
|
||
grain: "结果一行代表什么"
|
||
fact_table: "事实表"
|
||
dimension_tables: []
|
||
time_window:
|
||
lower_bound_sql: "date_sub(current_date(), N)"
|
||
upper_bound_sql: "current_date()"
|
||
predicate_sql: "event_time >= date_sub(current_date(), N) AND event_time < current_date()"
|
||
boundary: left_closed_right_open
|
||
steps:
|
||
- id: S1
|
||
kind: source
|
||
name: first_login
|
||
table: "表名"
|
||
columns: ["字段"]
|
||
reason: "为什么需要"
|
||
- id: S2
|
||
kind: filter
|
||
target: "表名或中间结果"
|
||
predicates: ["业务过滤条件"]
|
||
partition_pruning: true
|
||
- id: S3
|
||
kind: join
|
||
left: "左表或CTE"
|
||
right: "右表或CTE"
|
||
keys: ["左字段 = 右字段"]
|
||
type: left
|
||
cardinality: "1:1 | 1:N | N:1 | N:N | unknown"
|
||
row_growth_risk: low | medium | high
|
||
- id: S4
|
||
kind: aggregate
|
||
group_by: ["维度字段"]
|
||
metrics:
|
||
- name: "指标名"
|
||
agg: count_distinct | sum | avg | min | max | ratio
|
||
expression: "业务表达式"
|
||
alias: "指标别名"
|
||
- id: S5
|
||
kind: output
|
||
columns: ["输出列"]
|
||
order_by: []
|
||
write_intent: query_only | insert_into | insert_overwrite
|
||
assumptions: []
|
||
risks: []
|
||
pending_questions: []
|
||
```
|
||
|
||
## 用户可见摘要
|
||
|
||
除了 YAML,必须输出这张表:
|
||
|
||
```markdown
|
||
## 逻辑计划
|
||
| 步骤 | 中间结果 | 类型 | 说明 | 关键条件 |
|
||
|---|---|---|---|---|
|
||
```
|
||
|
||
## 停止条件
|
||
|
||
如果粒度、指标公式、join 基数、去重策略、空值策略、时间归属或写入模式不明确,输出 `NEED_USER_CONFIRMATION`。
|