Derivazione a livello di colonna¶
Provisa tiene traccia della derivazione dei dati a livello di colonna in modo statico — calcolata a partire dalle definizioni SQL e dai contratti di comando, senza necessità di esecuzione. Sono disponibili due viste: un DAG per singola istruzione e un grafo di provenienza a livello di federazione che copre tutte le viste e le viste materializzate (MV) registrate.
L'esploratore di derivazione¶
Accedere a Lineage nell'interfaccia utente (/lineage). Incollare un'istruzione SQL e fare clic
su Build statement graph per visualizzarne il DAG a livello di colonna. Fare clic su
Federation graph per caricare il grafo di provenienza su ogni MV nel registro.
[tool-verified: LineagePage.tsx:28-119]
DAG a livello di istruzione (REQ-1160)¶
Ogni colonna di output denominata nel proprio SQL diventa un nodo. Il generatore la ripercorre attraverso ogni CTE, sottoquery, join e chiamata di comando inline fino alle colonne di origine, costruendo un grafo diretto dagli input di origine agli output finali.
Esempio svolto¶
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
Questa istruzione produce tre colonne di output. Il grafo per geo_u è il seguente:
orders.geo ──[enrich_grpc_set(...)]──► e.geo ──[UPPER]──► geo_u
orders.id ─╮ (taint closure)
orders.region ─╯
orders.id,orders.regioneorders.geosono nodi source (il contratto di input ristretto dienrich_grpc_setdichiaraideregion; la taint closure completa collega tutti gli input dichiarati a tutti gli output). [tool-verified:_splice_commandsin graph.py:223-242]e.embeddingede.geosono nodi command — il confine dienrich_grpc_set.geo_uè un nodo derived prodotto dalla funzione SQLUPPER.
Il confine del comando non è opaco. Poiché enrich_grpc_set dichiara le proprie colonne di
input (id, region) e di output (id, embedding, geo), il motore di derivazione collega la
taint closure in modo continuo dalle colonne dichiarate della relazione di origine fino a ciascun
output. [tool-verified: _splice_commands e _input_relation in graph.py:245-271]
Tipi di nodo e indizi visivi¶
[tool-verified: LineageDag.tsx:25-29, KIND_COLOR constants; LineagePage.tsx:21-26 LEGEND]
| Tipo di nodo | Colore | Significato |
|---|---|---|
source |
Verde | Una colonna di una tabella di base |
derived |
Blu | Prodotta da un'espressione SQL (funzione, operatore, CTE) |
command |
Viola | Una colonna di output di un comando registrato |
Anelli aggiuntivi su un nodo:
- Anello arancione — una colonna di output finale dell'istruzione.
- Bordo doppio — la relazione della colonna è una vista materializzata (snapshot MV/CTAS).
- Anello rosso — membro di un ciclo classificato come errore.
- Anello giallo — membro di un ciclo classificato come ciclo di retroazione (feedback loop).
[tool-verified: LineageDag.tsx:88-103 Cytoscape style selectors]
Trasformazioni denominate sugli archi¶
Ogni arco riporta l'espressione SQL grezza che produce la colonna di destinazione, oltre a un
elenco di operazioni denominate: funzioni SQL (sql_function), operatori aritmetici/logici
(operator), comandi registrati (command), riferimenti di colonna semplici (identity) e
letterali (constant). [tool-verified: TransformOp and name_transform in graph.py:36-145]
Un arco proveniente da una chiamata di comando viene rappresentato come una linea viola tratteggiata nell'interfaccia utente. [tool-verified: LineageDag.tsx:122-124]
Grafo a livello di federazione (REQ-1161)¶
Il grafo di federazione unisce la derivazione per singola istruzione di ogni MV registrata in un
unico grafo di provenienza. L'identità del nodo è relation.column — la colonna di output di una
vista e il riferimento di input di un'altra vista alla stessa colonna collassano in un unico nodo.
Il risultato è un unico DAG dalle colonne di origine di base fino a ogni dataset derivato nella
piattaforma. [tool-verified: build_federation_graph in merge.py:205-229 e qualify_outputs in
graph.py:275-299]
Utilizzare focus, direction e depth per delimitare la vista su scala di federazione senza
ricalcolare il grafo. [tool-verified: slice_graph in merge.py:160-189]
Cicli (REQ-1161)¶
I cicli vengono descritti, non rifiutati. Il motore di derivazione rileva ogni ciclo diretto e lo
classifica. [tool-verified: Cycle.classification property in merge.py:43-46]
| Classificazione | Colore del bordo | Significato |
|---|---|---|
feedback |
Giallo | Il ciclo attraversa un nodo materializzato — un ciclo di retroazione legittimo e sfasato nel tempo. Lo snapshot della MV costituisce il confine di versione che lo rende ben definito. |
error |
Rosso | Nessun confine di materializzazione sul ciclo — una definizione circolare senza un ordine di valutazione stabile. Probabilmente un errore di progettazione. |
[tool-verified: LineagePage.tsx:83-98 cycle alert rendering; merge.py:38-48]
Un ciclo feedback non è un errore. Una MV di arricchimento che reinserisce una colonna derivata
nella propria relazione di origine è un pattern valido, purché un nodo del ciclo sia materializzato
— lo snapshot isola temporalmente le due metà. Un ciclo error richiede il giudizio di un
operatore: di norma significa che due viste si fanno riferimento reciprocamente senza uno snapshot
intermedio.
API¶
Entrambi gli endpoint sono statici — leggono definizioni e contratti, non dati.
POST /admin/lineage/graph¶
Restituisce il DAG a livello di colonna per una singola istruzione SQL.
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]
Forma della risposta [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"]
}
Restituisce HTTP 422 quando l'SQL non può essere analizzato. [tool-verified: lineage_router.py:51-54]
GET /admin/lineage/federation¶
Restituisce il grafo di provenienza unificato su tutte le MV nel registro.
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]
Parametri di query [tool-verified: function signature at lineage_router.py:73-76]:
| Parametro | Valori | Predefinito | Effetto |
|---|---|---|---|
focus |
Un id di nodo | — | Delimita la risposta al sottografo attorno a questo nodo |
direction |
upstream | downstream | both |
both |
Direzione di attraversamento a partire da focus |
depth |
intero | illimitato | Distanza massima in hop da focus |
La risposta ha la stessa forma del grafo di istruzione, con l'aggiunta di un campo 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"
}
]
}
Utilizzare la derivazione per governare i contratti di comando¶
Poiché la taint closure collega ogni colonna di input dichiarata a ogni colonna di output dichiarata, l'ampiezza di tale closure dipende interamente da ciò che si dichiara.
Si consideri un comando che riceve una tabella orders completa (id, region, amount,
customer_id, discount, notes, ...) e restituisce un embedding. Se il contratto di input
elenca tutte queste colonne, ogni colonna a valle che utilizza l'embedding mostrerà la derivazione
da tutte quante. Ciò è corretto ma poco utile — è difficile capire cosa abbia effettivamente
contato.
Dichiarando solo id e text (le colonne che il modello di embedding legge realmente), il cono di
derivazione si restringe a queste due colonne di origine. La derivazione risulta così al tempo
stesso corretta e precisa.
Vedere Commands per la meccanica di dichiarazione di un contratto di input ristretto.