跳转至

列级数据血缘

Provisa以静态方式追踪列级数据血缘——根据SQL定义和命令合约计算得出,无需执行。系统提供两种视图:单条语句的DAG,以及涵盖所有已注册视图和物化视图(MV)的联邦级溯源图。

血缘浏览器

在界面中导航至Lineage/lineage)。粘贴一条SQL语句并点击Build statement graph,即可查看其列级DAG。点击Federation graph,可加载涵盖注册表中每个MV的溯源图。[tool-verified: LineagePage.tsx:28-119]

语句级DAG(REQ-1160

SQL中每个具名输出列都会成为一个节点。构建器会沿着每个CTE、子查询、join及内联命令调用向上回溯,直至其来源列,从而构建出由来源输入到最终输出的有向图。

示例演算

SELECT o.id, e.embedding, upper(e.geo) AS geo_u
FROM   orders o
JOIN   enrich_grpc_set('main.public.orders') e ON o.id = e.id

该语句产生三个输出列。geo_u的图如下:

orders.geo  ──[enrich_grpc_set(...)]──►  e.geo  ──[UPPER]──►  geo_u
orders.id   ─╮                                              (taint closure)
orders.region ─╯
  • orders.idorders.regionorders.geosource节点(enrich_grpc_set的窄输入合约声明了idregion;完整的taint closure会将所有已声明的输入连接到所有输出)。[tool-verified: _splice_commands in graph.py:223-242]
  • e.embeddinge.geocommand节点——即enrich_grpc_set的边界。
  • geo_u是由UPPER这个SQL函数产生的derived节点。

命令边界并非不透明。由于enrich_grpc_set声明了其输入列(idregion)和输出列(idembeddinggeo),血缘引擎会将taint closure从来源关系已声明的列持续连接至每个输出。[tool-verified: _splice_commands and _input_relation in graph.py:245-271]

节点种类与视觉提示

[tool-verified: LineageDag.tsx:25-29, KIND_COLOR constants; LineagePage.tsx:21-26 LEGEND]

节点种类 颜色 含义
source 绿色 基础表的一列
derived 蓝色 由SQL表达式(函数、运算符、CTE)产生
command 紫色 已注册命令的输出列

节点上的附加圆环:

  • 橙色圆环——该语句的最终输出列。
  • 双边框——该列所属的关系是物化视图(MV/CTAS快照)。
  • 红色圆环——被归类为错误的循环成员。
  • 黄色圆环——被归类为反馈回路的循环成员。

[tool-verified: LineageDag.tsx:88-103 Cytoscape style selectors]

边上的具名转换

每条边都携带产生目标列的原始SQL表达式,以及一份具名操作列表:SQL函数(sql_function)、算术/逻辑运算符(operator)、已注册命令(command)、纯列引用(identity)和字面量(constant)。[tool-verified: TransformOp and name_transform in graph.py:36-145]

来自命令调用的边,会在界面中以紫色虚线表示。[tool-verified: LineageDag.tsx:122-124]

联邦级图(REQ-1161

联邦图将每个已注册MV的语句级血缘合并为单一溯源图。节点的身份为relation.column——某视图的输出列与另一视图对同一列的输入引用会合并为单一节点。结果是从基础来源列延伸至平台上每个衍生数据集的单一DAG。[tool-verified: build_federation_graph in merge.py:205-229 and qualify_outputs in graph.py:275-299]

可使用focusdirectiondepth,在不重新计算图的情况下,于联邦规模上限定视图范围。[tool-verified: slice_graph in merge.py:160-189]

循环(REQ-1161

循环会被描述,而非被拒绝。血缘引擎会检测每个有向循环并将其分类。[tool-verified: Cycle.classification property in merge.py:43-46]

分类 边框颜色 含义
feedback 黄色 该循环经过一个物化节点——属合法、具时间延迟的反馈回路。MV快照即是使其成为良定义的版本边界。
error 红色 该回路上没有物化边界——属无稳定求值顺序的循环定义,很可能是设计错误。

[tool-verified: LineagePage.tsx:83-98 cycle alert rendering; merge.py:38-48]

feedback循环并非失败。若增强型MV将衍生列反馈至其自身的来源关系,只要回路上有一个节点已物化,这便是有效模式——快照会在时间上将两部分隔开。error循环则需要运维人员判断:通常意味着两个视图相互引用,中间没有快照。

API

两个端点均为静态——只读取定义和合约,不读取数据。

POST /admin/lineage/graph

返回单条SQL语句的列级DAG。

POST /admin/lineage/graph
Content-Type: application/json

{
  "sql": "SELECT o.id, e.embedding FROM orders o JOIN enrich_grpc_set('main.public.orders') e ON o.id = e.id",
  "dialect": "postgres"
}

[tool-verified: lineage_graph endpoint at lineage_router.py:45-54, LineageGraphRequest model at lineage_router.py:29-31]

响应结构[tool-verified: LineageGraph.to_dict in graph.py:82-105]:

{
  "nodes": [
    {"id": "orders.id", "column": "id", "relation": "orders", "kind": "source", "materialized": false}
  ],
  "edges": [
    {
      "source": "orders.id",
      "target": "e.id",
      "transform": "enrich_grpc_set(...)",
      "ops": [{"name": "enrich_grpc_set", "kind": "command"}]
    }
  ],
  "outputs": ["id", "embedding"]
}

当SQL无法解析时,返回HTTP 422。 [tool-verified: lineage_router.py:51-54]

GET /admin/lineage/federation

返回注册表中所有MV的合并溯源图。

GET /admin/lineage/federation
GET /admin/lineage/federation?focus=orders.id&direction=downstream&depth=3

[tool-verified: federation_graph endpoint at lineage_router.py:73-98]

查询参数[tool-verified: function signature at lineage_router.py:73-76]:

参数 取值 默认值 效果
focus 节点ID 将响应限定于该节点周围的子图
direction upstream | downstream | both both focus出发的遍历方向
depth 整数 无限制 focus的最大跳数

响应结构与语句图相同,并附加一个cycles字段 [tool-verified: MergedGraph.to_dict in merge.py:60-64]:

{
  "nodes": [...],
  "edges": [...],
  "outputs": [...],
  "cycles": [
    {
      "nodes": ["orders.region", "enriched_orders.region"],
      "has_materialization_boundary": true,
      "classification": "feedback"
    }
  ]
}

利用血缘治理命令合约

由于taint closure会将每个已声明的输入列连接到每个已声明的输出列,该closure的广度完全取决于你声明了什么。

试想一个命令,接收完整的orders表(idregionamountcustomer_iddiscountnotes等),并返回一个embedding。若输入合约列出全部这些列,则每个使用该embedding的下游列都会显示来自全部这些列的血缘。这虽然准确,却并不实用——难以判断实际上是什么真正起了作用。

只声明idtext(即embedding模型实际读取的列),血缘范围便会收窄至这两个来源列。这样得出的推导既严谨又精确。

有关声明窄输入合约的机制,请参阅Commands