7.2 KiB
7.2 KiB
name, description
| name | description |
|---|---|
| sql-context-builder | 当需要组装 SQL 生成器与评审器共同消费的、唯一可信的 SQL Context 时使用。触发词包括"build SQL context"、"固化 join key"、"table aliases"、"列出来自哪张表"、"准备写 SQL"、"context 已经齐了"。消费已校验的 Logic Plan 与 Field Mapping,产出带有稳定 alias、固化 join key、显式 fact/dimension 标记的标准化 SQL Context。SQL 生成器**不得**再重新推导其中任何一项。 |
SQL Context Builder(SQL 上下文构建器)
概述(Overview)
把 SQL 生成器本来要重复发明的所有决策一次性固化下来:alias、join key、字段来源、类型、角色标签(fact / dimension / filter)、时间列,都在这里只此一次地钉死。输出是 sql-review 及任何 SQL 输出步骤的唯一可信输入。
核心原则:任何不在 SQL Context 中的字段,下游 skill 视同不存在。 如果下游 skill 还需要新内容,请求必须先回退到 metadata-validator 和 logic-planner。
何时使用(When to Use)
使用场景:
logic-planner返回状态PLANNED- 用户即将写 Spark SQL,需要一份规范化的 context(alias、join key、字段来源)
- 同一份逻辑要产出多版 SQL 草稿 — context 保证它们保持一致
不要使用场景:
logic-plan.status为NEED_USER_CONFIRMATION— 回到logic-planner- SQL 极简单(单表无 join) — 仍然建议构建 context,除非用户明确跳过
- 任务是把 plan 翻译成 SQL — 那是另一回事,不是本 skill 的职责
输入(Inputs)
- 来自
logic-planner的logic_plan(状态PLANNED) - 来自
metadata-validator的field_mapping(状态VALIDATED) - 原始
validation_result(用于表级元数据:类型、来源)
工作流(Workflow)
digraph sql_context_builder {
"读取 logic_plan + field_mapping + validation_result" [shape=box];
"为每张表分配稳定 alias" [shape=box];
"固化 join key(left_alias.field = right_alias.field)" [shape=box];
"把每个字段解析为 (alias, column, type, source_file)" [shape=box];
"为每个字段打标签:dimension | metric | filter | time | join_key" [shape=box];
"标记事实表 / 维度表" [shape=box];
"校验 Logic Plan 的字段在 context 中全部存在" [shape=box];
"所有必需字段都齐全?" [shape=diamond];
"输出 SQL Context" [shape=box];
"输出 SQL Context + missing_fields" [shape=box];
"读取 logic_plan + field_mapping + validation_result" -> "为每张表分配稳定 alias";
"为每张表分配稳定 alias" -> "固化 join key(left_alias.field = right_alias.field)";
"固化 join key(left_alias.field = right_alias.field)" -> "把每个字段解析为 (alias, column, type, source_file)";
"把每个字段解析为 (alias, column, type, source_file)" -> "为每个字段打标签:dimension | metric | filter | time | join_key";
"为每个字段打标签:dimension | metric | filter | time | join_key" -> "标记事实表 / 维度表";
"标记事实表 / 维度表" -> "校验 Logic Plan 的字段在 context 中全部存在";
"校验 Logic Plan 的字段在 context 中全部存在" -> "所有必需字段都齐全?";
"所有必需字段都齐全?" -> "输出 SQL Context" [label="yes"];
"所有必需字段都齐全?" -> "输出 SQL Context + missing_fields" [label="no"];
}
规则(Rules)
Alias 分配
- 一张表一个 alias,绝不重用
- 事实表(承载主指标的表)优先拿到短 alias(
o、f、t1) - 维度表用有意义的 alias(
c代表 customer,p代表 product,ch代表 channel) - alias 在此处固化,SQL 生成器与评审器不得再发明新 alias
Join Key 固化
- 对每条
logic_plan.steps[kind=join],固化精确的谓词:left_alias.col1 = right_alias.col2
- 包含 join 类型(inner / left / right / full / semi / anti)
- 沿用 Logic Plan 中的 cardinality 假设
- 如果两张表有多种可能的 join key,在此处固化为所选的那一个,其他候选不再纳入 SQL 范畴
字段解析(Field Resolution)
对 Logic Plan 用到的每个字段,记录:
alias(字段所在表)column(物理列名)type(取自validation_result)source_file(元数据文件来源 — 用于追溯)role:取自dimension|metric|filter|time|join_key|derived之一
一个字段可以有多个 role(例如 customer_id 同时是 join_key 和 dimension),全部列出。
Fact vs Dimension 标记
- 承载主要事件/度量的表为
fact - 起丰富作用的表(customer、product、channel、city)为
dimension - 一条 query 只能有一个 fact。如果 Logic Plan 隐含多张事实表,作为
pending_question抛出 — 那是规划问题,不是 context 问题
覆盖度校验
logic_plan.steps中的每一步引用的字段都必须存在于本 context- 每条
field_mapping都必须出现在本 context - 每个
group_by、order_by字段都必须有标签 aggregate中的每个指标都必须有metric标签filter中的每条谓词都必须引用filter或time标签的字段
输出契约(Output Contract)
sql_context:
aliases:
- alias: o
table: loan_order
role: fact
source_file: metadata/loan_order.json
- alias: c
table: customer_info
role: dimension
source_file: metadata/customer_info.md
joins:
- left: { alias: o, column: customer_id }
right: { alias: c, column: customer_id }
type: left
cardinality_assumption: 1:N
fields:
- alias: o
column: customer_id
type: string
role: [join_key]
source_file: metadata/loan_order.json
- alias: o
column: loan_amount
type: decimal(18,2)
role: [metric]
source_file: metadata/loan_order.json
- alias: o
column: apply_time
type: timestamp
role: [time, filter]
source_file: metadata/loan_order.json
- alias: c
column: city
type: string
role: [dimension]
source_file: metadata/customer_info.md
metrics:
- alias: total_loan
expr: "SUM(o.loan_amount)"
agg: sum
- alias: customer_cnt
expr: "COUNT(DISTINCT o.customer_id)"
agg: count_distinct
dimensions: ["c.city"]
time_grain:
column: o.apply_time
granularity: day
filters:
- "o.status = 'SUCCESS'"
missing_fields: []
status: <READY | NEED_USER_CONFIRMATION>
禁止行为(Forbidden Behaviors)
| 自我说服 | 现实 |
|---|---|
| "alias 让 SQL 生成器自己选" | alias 就在此处固化。下游重新起 alias 会破坏 sql-review。 |
| "join key 太显然,跳过固化" | 整个 skill 的意义就在于此 — 把 join key 钉死。 |
| "字段类型无所谓,SQL 里都是字符串" | 类型决定了聚合、cast、分区裁剪的策略。 |
| "派生列到 SQL 阶段再发明就行" | 每个派生列都必须在 Logic Plan 里就出现。 |
| "多张事实表?全 join 上就行" | 多事实是 Logic Plan 的问题,要暴露并停止。 |
完成判定(Completion Criteria)
仅当以下全部成立时,status: READY:
- Logic Plan 的每一步在本 context 中都有对应条目
missing_fields为空- 每个指标都有
agg和expr - 每个 join 都有固化的 key 和 type
- 时间粒度已设定