Executive summary
Quando un'organizzazione gestisce centinaia di tabelle e trasformazioni che alimentano report, modelli previsionali e decisioni operative, sapere esattamente da dove proviene ogni singolo dato e quali processi lo hanno modificato diventa un requisito critico per garantire la qualità delle informazioni e la conformità alle normative. Questo articolo analizza i metodi e gli strumenti che permettono di ricostruire automaticamente il percorso dei dati attraverso l'intera catena di elaborazione, dal livello più granulare, la singola colonna di una tabella, fino alla visione d'insieme dei flussi tra sistemi diversi. L'analisi mostra che la convergenza verso uno standard aperto per la raccolta di queste informazioni ha reso possibile integrare strumenti di trasformazione, orchestrazione e calcolo distribuito in un unico grafo di tracciabilità, ma le sfide principali restano l'accuratezza dell'analisi automatica del codice di interrogazione, la gestione delle trasformazioni non dichiarative e l'adozione effettiva di queste tecniche nei processi di governo dei dati e nella diagnosi tempestiva dei problemi di qualità.
Background
La necessità di tracciare l'origine e le trasformazioni dei dati è un problema fondamentale nella gestione dei sistemi informativi, formalizzato nella letteratura con il termine data provenance. La distinzione concettuale tra le diverse forme di provenienza è stata stabilita da Buneman, Khanna e Tan [1], che nel 2001 hanno introdotto la separazione tra why-provenance, l'insieme dei dati sorgente che hanno contribuito all'esistenza di un risultato, e where-provenance, la localizzazione precisa nelle sorgenti da cui un dato è stato estratto. Questa distinzione non è puramente accademica: determina quali domande un sistema di lineage è in grado di rispondere e quali no. Green, Karvounarakis e Tannen [2] hanno successivamente unificato le diverse nozioni di provenienza attraverso il formalismo dei semiring, dimostrando che la provenienza in contesti relazionali, incluse le semantiche bag, le basi di dati probabilistiche e il why-provenance, sono istanze di un unico framework algebrico. Il risultato è significativo perché fornisce una base teorica per comporre e propagare informazioni di provenienza attraverso catene arbitrarie di operatori relazionali.
La survey di Cheney, Chiticariu e Tan [3] ha consolidato lo stato dell'arte distinguendo tre dimensioni operative della provenienza: why (quali tuple sorgente hanno contribuito a un risultato), how (attraverso quale combinazione di operazioni) e where (da quale posizione fisica nelle sorgenti). Herschel, Diestelkämper e Lahmar [4] hanno aggiornato questa tassonomia nel 2017, analizzando sistematicamente le motivazioni d'uso (debugging, auditing, riproduzione), le forme di rappresentazione (annotazioni, grafi, polinomi) e le sorgenti da cui la provenienza viene estratta (query log, workflow engine, sistemi operativi).
Nel contesto specifico dei data warehouse, il lavoro fondativo di Cui, Widom e Wiener [5] ha formalizzato il problema del lineage tracing come la capacità di risalire, dato un record in una vista materializzata, all'insieme dei record sorgente da cui è stato derivato. Gli algoritmi proposti coprono viste relazionali con aggregazione e sono stati successivamente estesi alle trasformazioni generali nei data warehouse [6], introducendo il concetto di lineage tracing per trasformazioni black-box, un problema che resta aperto quando le trasformazioni non sono espresse in SQL dichiarativo.
L'evoluzione dalle definizioni formali agli strumenti operativi ha richiesto due decenni. Il catalizzatore è stato il passaggio da architetture monolitiche, dove un singolo data warehouse centralizzava tutte le trasformazioni, a ecosistemi distribuiti con decine di strumenti specializzati: orchestratori, motori di trasformazione, sistemi di calcolo distribuito, data lake e layer semantici. In questo contesto, il lineage non può più essere ricostruito analizzando un singolo sistema: richiede un protocollo comune che ogni componente della pipeline possa utilizzare per emettere metadati di provenienza in modo standardizzato.
Column-level lineage e SQL parsing
Il lineage a livello di tabella, sapere che una tabella B dipende da una tabella A, è insufficiente per la maggior parte dei casi d'uso operativi. Se un valore anomalo appare nella colonna revenue di una tabella di reporting, è necessario sapere quali colonne sorgente lo hanno generato e attraverso quali trasformazioni. Il column-level lineage (CLL) risponde a questa esigenza tracciando le dipendenze tra singole colonne attraverso le trasformazioni SQL.
L'estrazione automatica del CLL da codice SQL è un problema di analisi statica. Il processo si articola in tre fasi: parsing del codice SQL in un albero sintattico astratto (AST), risoluzione dei riferimenti (quali tabelle e colonne sono effettivamente coinvolte, considerando alias, subquery e Common Table Expression) e costruzione del grafo di dipendenza colonna-per-colonna. Ogni fase introduce complessità specifiche.
Il parsing è la fase più matura. SQLGlot [7] è un parser e transpiler SQL scritto in Python che supporta oltre trenta dialetti (PostgreSQL, MySQL, Snowflake, BigQuery, Spark SQL, DuckDB, Trino, tra gli altri) e produce un AST navigabile programmaticamente. L'architettura di SQLGlot separa la grammatica dialetto-specifica dalla rappresentazione interna, consentendo di analizzare query scritte per un dialetto specifico senza perdere informazioni sintattiche. Il modulo di lineage integrato in SQLGlot opera su una collezione di query che selezionano l'una dall'altra, assumendo che la rete di query formi un grafo aciclico diretto (DAG), un'assunzione che nella pratica è quasi sempre soddisfatta nei progetti dbt e nei data warehouse, ma che può essere violata in presenza di viste ricorsive o dipendenze circolari [7].
La risoluzione dei riferimenti è la fase critica. Una query SQL contiene alias, subquery correlate, CTE, SELECT *, UNION, funzioni finestra e join multipli. Risolvere correttamente quale colonna sorgente alimenta quale colonna di output richiede la capacità di attraversare l'AST seguendo le catene di alias e di disambiguare i riferimenti quando la stessa colonna appare in tabelle diverse coinvolte in un join. Il parser SQL di DataHub [8], costruito sopra SQLGlot, ha affrontato questo problema con un approccio a più passaggi che raggiunge un'accuratezza del 97-99% sui test interni, ma la metrica è calcolata sulle query per cui il parser è in grado di produrre un output, la copertura, intesa come percentuale di query reali per cui viene generato un lineage, è una metrica distinta e tipicamente inferiore.
Il lavoro recente su LineageX [9], presentato alla demo track di ICDE 2025, affronta specificamente il problema della copertura. LineageX costruisce il grafo di lineage a livello colonna partendo dalle definizioni delle query e gestisce le ambiguità, tabelle non risolvibili, colonne con nome identico in tabelle diverse, attraverso un riordinamento dinamico delle query durante l'analisi. L'approccio è complementare a quello di SQLGlot: mentre SQLGlot richiede che l'ordine di risoluzione sia esplicito, LineageX adatta l'ordine di processamento in base alle dipendenze scoperte durante l'analisi stessa.
Le limitazioni strutturali dell'estrazione CLL via SQL parsing meritano una discussione esplicita. Le trasformazioni non espresse in SQL puro, codice Python in un operatore Airflow, funzioni UDF in Spark, stored procedure con logica condizionale, sono opache al parser. In questi casi il CLL si interrompe al confine della trasformazione non dichiarativa: si sa che la tabella di output dipende dalla tabella di input, ma non si sa quali colonne sono coinvolte. Le lateral join, le unpivot dinamiche e le trasformazioni JSON (estrazione di campi da colonne semi-strutturate) rappresentano ulteriori casi in cui il parser può produrre lineage incompleto o errato. La distinzione tra lineage diretto (la colonna di output è una copia o una trasformazione elementare della colonna sorgente), derivato (la colonna di output è il risultato di un'aggregazione o di un calcolo che coinvolge più colonne sorgente) e inferito (la colonna di output dipende indirettamente dalla colonna sorgente attraverso una condizione di filtro o un join) è un aspetto semantico che i parser più recenti stanno iniziando a modellare, ma che non è ancora standardizzato [9].
Lo standard OpenLineage
La frammentazione degli strumenti nella data platform moderna, orchestratori, motori SQL, framework di trasformazione, sistemi di calcolo distribuito, ha reso evidente la necessità di un protocollo comune per la raccolta dei metadati di lineage. OpenLineage [10] è lo standard aperto che risponde a questa esigenza, definendo un modello di dati e un formato di eventi JSON per descrivere le dipendenze tra job, run e dataset.
Il modello concettuale di OpenLineage è costruito attorno a tre entità fondamentali. Un Job rappresenta un processo che consuma e produce dataset, identificato univocamente da un nome all'interno di un namespace (tipicamente il nome del sistema che lo esegue: un DAG Airflow, un modello dbt, un'applicazione Spark). Un Run è un'istanza di esecuzione di un job, con un ciclo di vita descritto da eventi di tipo START, RUNNING, COMPLETE, FAIL o ABORT. Un Dataset è una rappresentazione astratta di un insieme di dati, identificato da un nome derivato dalla sua localizzazione fisica (ad esempio postgres://host:5432/db.schema.table). Ogni evento di run trasporta la lista dei dataset di input e output del job, con metadati aggiuntivi organizzati in facet [10].
Il meccanismo dei facet è l'elemento architetturale che conferisce estensibilità allo standard. Un facet è un oggetto JSON con uno schema definito che può essere allegato a un run, a un job o a un dataset per trasportare metadati aggiuntivi. La specifica core definisce un insieme di facet standard, tra cui SchemaDatasetFacet per la struttura delle colonne, DataQualityMetricsInputDatasetFacet per le metriche di qualità, SQLJobFacet per il codice SQL eseguito, ma ogni implementazione può definire facet custom per trasportare metadati specifici del proprio dominio [10].
Il facet più rilevante per il tema di questo articolo è il ColumnLineageDatasetFacet [11], che codifica il lineage a livello colonna. Per ogni colonna di un dataset di output, il facet elenca le colonne dei dataset di input che hanno contribuito alla sua derivazione, con un campo opzionale per il tipo di trasformazione. La struttura JSON è la seguente:
{
"columnLineage": {
"fields": {
"output_column_name": {
"inputFields": [
{
"namespace": "postgres://host:5432",
"name": "db.schema.source_table",
"field": "source_column",
"transformations": [
{
"type": "DIRECT",
"subtype": "IDENTITY",
"description": ""
}
]
}
]
}
}
}
}
Questa struttura consente di ricostruire il grafo di dipendenza colonna-per-colonna attraverso l'intera pipeline, a condizione che ogni componente emetta eventi OpenLineage con il facet di column lineage popolato, un'assunzione che, come si vedrà nelle sezioni successive, è soddisfatta in modo eterogeneo dai diversi integratori.
La specifica è formalizzata come JSON Schema versionato e ospitata nel repository ufficiale del progetto [10]. L'approccio schema-first consente la validazione automatica degli eventi e la generazione di client in diversi linguaggi. La governance del progetto è gestita dalla Linux Foundation AI & Data, con contributi significativi da parte di aziende come Astronomer (per l'integrazione Airflow), Datakin (il team originario) e IBM.
Marquez [12] è l'implementazione di riferimento dello standard: un server di metadati che riceve eventi OpenLineage via HTTP, li persiste in un database relazionale e li espone attraverso un'API REST e un'interfaccia web. Il grafo di lineage è navigabile visivamente, con la possibilità di esplorare le dipendenze upstream e downstream di un job o di un dataset. Marquez non è l'unico consumer di eventi OpenLineage: piattaforme come DataHub, Atlan e Datadog supportano l'ingestione di eventi OpenLineage, consentendo la visualizzazione del lineage all'interno di data catalog preesistenti.
Lineage negli strumenti della data platform moderna
L'adozione pratica dello standard OpenLineage dipende dalla qualità delle integrazioni con gli strumenti che compongono una data platform. Le tre integrazioni più rilevanti, dbt, Apache Airflow e Apache Spark, presentano livelli di maturità e granularità significativamente diversi.
dbt
dbt (data build tool) genera nativamente un grafo di dipendenza a livello di modello attraverso le macro ref() e source(), che dichiarano esplicitamente le relazioni tra trasformazioni SQL. Questo grafo è serializzato nel file manifest.json prodotto ad ogni esecuzione e costituisce la base per il lineage a livello tabella. L'estensione al column-level lineage richiede il parsing del codice SQL di ogni modello per identificare le dipendenze colonna-per-colonna. dbt Cloud offre il CLL nativamente attraverso un parser SQL integrato, che analizza il codice SQL dei modelli e lo incrocia con i metadati del catalog.json, il file che contiene lo schema effettivo delle tabelle nel warehouse [13]. Quando il parsing fallisce, ad esempio per lateral join, unpacking JSON o macro Jinja che generano SQL dinamico, dbt segnala l'incompletezza del lineage con un avviso esplicito [13].
Per dbt Core (la versione open-source), il CLL nativo non è disponibile e deve essere estratto con strumenti esterni. Il progetto dbt-column-lineage-extractor, sviluppato da Canva [14], utilizza SQLGlot per analizzare le query SQL estratte dal manifest.json e costruire il grafo di dipendenza colonna-per-colonna. L'approccio classifica le dipendenze in quattro livelli di confidenza: Direct (la colonna è copiata senza trasformazione), Aliased (la colonna è rinominata), Derived (la colonna è il risultato di un calcolo) e Star (la dipendenza è inferita da un SELECT * e può essere imprecisa) [14]. L'integrazione con OpenLineage avviene attraverso il provider dbt di OpenLineage, che intercetta gli eventi di esecuzione dbt e li traduce in eventi OpenLineage, includendo il facet di column lineage quando il parsing SQL è riuscito.
Apache Airflow
Apache Airflow ha integrato il supporto OpenLineage come provider nativo a partire dalla versione 2.7, sostituendo la libreria standalone openlineage-airflow [15]. L'architettura si basa su un sistema di extractor: per ogni tipo di operatore Airflow (BigQueryInsertJobOperator, PostgresOperator, SparkSubmitOperator, PythonOperator), un extractor specifico è responsabile di intercettare i metadati di lineage prima dell'esecuzione (evento START) e dopo il completamento (evento COMPLETE o FAIL). L'extractor accede ai parametri dell'operatore, la query SQL, la tabella di destinazione, la configurazione del job, e li traduce in dataset di input e output con i relativi facet [15].
La copertura degli extractor è il fattore limitante. Gli operatori che eseguono SQL dichiarativo (PostgresOperator, BigQueryOperator, SnowflakeOperator) sono ben supportati: l'extractor analizza la query e produce un lineage accurato a livello di tabella, e in molti casi a livello di colonna. Gli operatori generici, PythonOperator, BashOperator, KubernetesPodOperator, sono opachi per definizione: il codice eseguito può leggere e scrivere qualsiasi dataset, ma l'extractor non ha modo di analizzarlo staticamente. Per questi casi, Airflow supporta la dichiarazione manuale dei dataset di input e output attraverso le inlet e outlet API, o attraverso l'interfaccia get_openlineage_facets_on_complete() che un operatore custom può implementare [15]. Il risultato è un lineage che è accurato per i task SQL-based e che richiede intervento manuale per i task con logica arbitraria, un compromesso pragmatico ma che lascia lacune nel grafo complessivo.
Apache Spark
L'integrazione OpenLineage per Apache Spark opera a un livello architetturale diverso: si inserisce come SparkListener (io.openlineage.spark.agent.OpenLineageSparkListener), intercettando gli eventi del motore di esecuzione e analizzando il piano logico (LogicalPlan) delle query per estrarre i metadati di lineage [16]. Il column-level lineage è abilitato per default e non richiede configurazione aggiuntiva. L'implementazione attraversa i nodi del LogicalPlan utilizzando due componenti principali: l'OutputFieldsCollector, che identifica le colonne di output e le associa allo schema, e l'InputFieldsCollector, che risale alle sorgenti dati (DataSourceV2Relation, HiveTableRelation, LogicalRelation) per identificare le colonne di input [16].
L'approccio basato sul LogicalPlan ha il vantaggio di catturare il lineage indipendentemente dall'API utilizzata (DataFrame API, Spark SQL, PySpark), poiché tutte le API convergono sullo stesso piano logico ottimizzato dal Catalyst optimizer. I limiti emergono con le UDF (User Defined Function): una UDF è una funzione opaca per il Catalyst, e il listener non può determinare quali colonne di input sono effettivamente lette all'interno della funzione. In questi casi, il lineage riporta una dipendenza dalla tabella di input senza granularità a livello colonna. Il supporto per Apache Iceberg è stato introdotto nelle versioni recenti, estendendo la cattura del lineage ai DataSourceRDD associati alle tabelle Iceberg [16]. Spark 2.x non è più supportato: la versione minima è Spark 3.x.
Limiti dell'integrazione cross-tool
Il diagramma seguente illustra il flusso degli eventi OpenLineage attraverso i tre strumenti e il loro confluire in un consumer centralizzato.
graph TD
A[dbt] -->|OpenLineage events<br/>table + column lineage| D[OpenLineage Consumer<br/>Marquez / DataHub / Atlan]
B[Apache Airflow] -->|OpenLineage events<br/>per-task lineage| D
C[Apache Spark] -->|OpenLineage events<br/>LogicalPlan-based| D
B -->|orchestrazione| A
B -->|orchestrazione| C
D --> E[Lineage Graph unificato]
E --> F[Impact Analysis]
E --> G[Root Cause Analysis]
E --> H[Compliance & Audit]
Figura 1. Flusso degli eventi OpenLineage da dbt, Airflow e Spark verso un consumer centralizzato, con le applicazioni downstream del grafo unificato.
Il problema fondamentale dell'integrazione cross-tool è la riconciliazione dei namespace. Quando Airflow orchestra un task dbt che produce una tabella, e un job Spark successivamente legge quella tabella, lo stesso dataset fisico viene referenziato con namespace diversi dai tre strumenti. La corretta riconciliazione richiede che il naming dei dataset sia consistente, un requisito che OpenLineage affronta con convenzioni di naming documentate nella specifica, ma che nella pratica richiede configurazione attenta e talvolta normalizzazione post-hoc dei metadati.
Impact analysis e root cause analysis
Il grafo di lineage, una volta costruito e mantenuto aggiornato, abilita due classi di applicazioni operative che trasformano i metadati da documentazione passiva a strumento di diagnosi attiva: l'impact analysis (analisi di impatto) e la root cause analysis (analisi delle cause radice).
L'impact analysis risponde alla domanda: se modifico o rimuovo questo dataset, questa colonna o questa trasformazione, quali asset downstream ne saranno influenzati? L'operazione è una visita forward del grafo di lineage a partire dal nodo di interesse, raccogliendo tutti i nodi raggiungibili. In un contesto operativo, l'impact analysis è utilizzata prima di effettuare modifiche a schemi, trasformazioni o sorgenti dati. Se una colonna sorgente viene rinominata, il grafo di lineage identifica tutte le colonne derivate, le viste materializzate, i report e i modelli di machine learning che dipendono, direttamente o transitivamente, da quella colonna. La granularità dell'analisi dipende dalla granularità del lineage: con lineage solo a livello tabella, l'impatto è sovrastimato (ogni tabella downstream è segnalata, anche se solo una colonna è coinvolta); con CLL, l'impatto è circoscritto alle sole colonne effettivamente derivate.
La root cause analysis opera nella direzione opposta: dato un valore anomalo, un errore di qualità o un'interruzione in un dataset downstream, si risale il grafo di lineage in direzione backward per identificare l'origine del problema. In un ecosistema con centinaia di trasformazioni, un valore errato in un report finale può avere origine in una delle decine di sorgenti e trasformazioni upstream. Senza lineage, la diagnosi è manuale e richiede la conoscenza implicita dell'architettura da parte del team, un processo fragile, lento e non scalabile. Con il lineage a livello colonna, il percorso diagnostico è determinato dal grafo: dalla colonna anomala si risale, trasformazione per trasformazione, fino a identificare il punto in cui il valore è stato introdotto o alterato.
La combinazione di lineage e data observability amplifica l'efficacia di entrambe le discipline. I sistemi di data observability monitorano continuamente metriche di qualità, completezza, unicità, distribuzione, freshness, sui dataset della pipeline. Quando un'anomalia viene rilevata, il lineage fornisce il contesto per la diagnosi: la root cause analysis automatizzata propaga l'allarme lungo il grafo upstream, verificando se la stessa anomalia è presente nelle sorgenti, e l'impact analysis propaga l'allarme lungo il grafo downstream, identificando i consumatori potenzialmente compromessi. Il risultato è un ciclo di diagnosi che opera in minuti anziché in ore, trasformando gli alert isolati in diagnosi strutturate.
L'efficacia dell'impact analysis e della root cause analysis è tuttavia limitata dalla completezza del grafo. Le lacune nel lineage, trasformazioni opache, dataset non instrumentati, namespace non riconciliati, creano interruzioni nel percorso di diagnosi. Un grafo di lineage con copertura del 70% può produrre un'analisi di impatto che omette il 30% dei dataset effettivamente influenzati, una sottostima potenzialmente più dannosa dell'assenza totale di lineage, perché genera una falsa sicurezza. La completezza del grafo è quindi un prerequisito, non un nice-to-have, per l'uso operativo del lineage nella diagnosi delle anomalie.
Contesto normativo e governance
La tracciabilità dei dati non è solo un'esigenza tecnica: è un requisito normativo esplicito in diversi framework regolatori. Il BCBS 239 (Basel Committee on Banking Supervision, Principles for Effective Risk Data Aggregation and Risk Reporting), emanato nel 2013 e tuttora in fase di attuazione nel settore bancario, richiede che gli istituti finanziari siano in grado di tracciare i dati di rischio dalla sorgente originaria fino ai report regolamentari, con lineage completo a livello di attributo [17]. La Banca Centrale Europea ha specificato che il lineage deve essere completo, una vista di tutti i flussi di dati attraverso tutti i sistemi, e granulare fino al livello di singolo attributo, un requisito che corrisponde direttamente al column-level lineage [17].
Il Regolamento Generale sulla Protezione dei Dati (GDPR) non menziona esplicitamente il lineage, ma il diritto di accesso (articolo 15) e il diritto alla cancellazione (articolo 17) presuppongono la capacità di identificare tutti i sistemi e le trasformazioni che contengono o hanno processato i dati personali di un interessato, un'operazione che, in assenza di lineage, richiede indagini manuali su ogni sistema della pipeline. Il Data Governance Act europeo e l'EU AI Act introducono requisiti aggiuntivi di tracciabilità per i dataset utilizzati nell'addestramento di sistemi di intelligenza artificiale, rendendo il lineage un enabler trasversale per la conformità a normative eterogenee.
L'implicazione pratica è che il lineage, per soddisfare i requisiti normativi, deve andare oltre la documentazione tecnica e integrarsi nei processi di governance. Il data catalog assume il ruolo di registro centrale dove il lineage tecnico (generato automaticamente dagli strumenti della pipeline) viene arricchito con metadati di business (owner, classificazione, sensibilità) e reso accessibile sia ai team tecnici per la diagnosi sia ai team di compliance per l'audit. L'integrazione tra lineage automatico e governance manuale è il punto in cui la maggior parte delle organizzazioni incontra le difficoltà maggiori: la raccolta automatica dei metadati tecnici è un problema largamente risolto dagli strumenti descritti in questo articolo, ma la correlazione con i metadati di business richiede processi organizzativi che nessuno strumento può automatizzare completamente.
Limiti e problemi aperti
Nonostante i progressi significativi nell'ultimo decennio, diverse sfide restano aperte nell'adozione operativa del data lineage.
La copertura delle trasformazioni non-SQL è il limite strutturale più rilevante. Le pipeline moderne includono codice Python, script Bash, UDF Spark, stored procedure e trasformazioni in linguaggi proprietari (Informatica, Talend, SSIS). Per queste trasformazioni, l'analisi statica basata su SQL parsing non è applicabile. L'alternativa, il lineage dinamico, catturato a runtime osservando i dati effettivamente letti e scritti, risolve il problema della copertura ma introduce overhead di esecuzione e produce un lineage che è valido solo per l'esecuzione specifica osservata, non per il processo in generale. La combinazione di lineage statico e dinamico è una direzione di ricerca attiva, ma non esistono ancora soluzioni mature che integrino i due approcci in modo trasparente.
La scalabilità del grafo diventa un problema concreto in organizzazioni con migliaia di tabelle e decine di migliaia di trasformazioni. Le query di impatto su grafi di questa dimensione richiedono ottimizzazioni specifiche, indici su grafi, materializzazione dei cammini transitivi, caching delle analisi di raggiungibilità, che i sistemi di catalogazione generalisti non sempre implementano. Marquez, ad esempio, è progettato come implementazione di riferimento e può richiedere ottimizzazioni significative per scenari enterprise con grafi di lineage nell'ordine di milioni di nodi.
La freshness del lineage è un problema spesso sottovalutato. Il lineage raccolto è accurato al momento della raccolta, ma le pipeline evolvono continuamente: nuove trasformazioni vengono aggiunte, colonne vengono rinominate, sorgenti vengono sostituite. Se il lineage non viene aggiornato ad ogni esecuzione, o almeno ad ogni modifica della pipeline, il grafo diventa progressivamente inaccurato, e l'impact analysis produce risultati obsoleti. L'approccio event-driven di OpenLineage, che raccoglie il lineage ad ogni esecuzione, mitiga questo problema ma non lo elimina: le trasformazioni che non vengono eseguite per un periodo prolungato mantengono un lineage potenzialmente stale.
La standardizzazione semantica delle trasformazioni nel CLL è ancora immatura. Sapere che una colonna di output dipende da una colonna di input non è sufficiente per molti casi d'uso: è necessario sapere come dipende, se è una copia, un'aggregazione, un filtro, una trasformazione matematica. Il facet ColumnLineageDatasetFacet di OpenLineage include un campo transformations che classifica la dipendenza in tipi (DIRECT, INDIRECT) e sottotipi, ma la tassonomia è ancora limitata e non copre la ricchezza semantica delle trasformazioni SQL reali [11].
Il lineage nelle pipeline di streaming introduce complessità aggiuntive rispetto al batch. In una pipeline batch, il lineage è catturato al termine di ogni esecuzione e descrive una trasformazione completa da input a output. In una pipeline di streaming, implementata con Apache Flink, Kafka Streams o Spark Structured Streaming, le trasformazioni operano continuamente su flussi di eventi senza una demarcazione chiara tra esecuzioni. OpenLineage supporta Apache Flink come producer di eventi, ma la granularità del lineage per le trasformazioni streaming è attualmente limitata al livello di topic/tabella, senza CLL per le operazioni di windowing, join temporali o aggregazioni incrementali [10]. La sfida concettuale è che il lineage di un record in un flusso di streaming dipende non solo dalle sorgenti, ma anche dalla finestra temporale e dallo stato interno dell'operatore, informazioni che il modello attuale di OpenLineage non cattura.
Infine, il lineage per i sistemi di machine learning presenta sfide specifiche. Il lineage di un modello ML include non solo i dataset di training, ma anche gli iperparametri, le metriche di valutazione, le versioni del codice e gli artefatti del modello. L'integrazione tra lineage dei dati e lineage dei modelli, spesso gestita da strumenti separati (MLflow, Weights & Biases), è un problema aperto che lo standard OpenLineage sta iniziando ad affrontare con facet dedicati, ma che non ha ancora raggiunto la maturità delle integrazioni per le pipeline dati tradizionali.
Riferimenti
[1] P. Buneman, S. Khanna, W. C. Tan, "Why and Where: A Characterization of Data Provenance," in Proc. ICDT, 2001. https://link.springer.com/chapter/10.1007/3-540-44503-X_20
[2] T. J. Green, G. Karvounarakis, V. Tannen, "Provenance Semirings," in Proc. PODS, 2007. https://dl.acm.org/doi/10.1145/1265530.1265535
[3] J. Cheney, L. Chiticariu, W. C. Tan, "Provenance in Databases: Why, How, and Where," Foundations and Trends in Databases, vol. 1, no. 4, 2009. https://dl.acm.org/doi/10.1561/1900000006
[4] M. Herschel, R. Diestelkämper, H. Ben Lahmar, "A Survey on Provenance: What For? What Form? What From?" The VLDB Journal, vol. 26, pp. 881-906, 2017. https://link.springer.com/article/10.1007/s00778-017-0486-1
[5] Y. Cui, J. Widom, J. L. Wiener, "Tracing the Lineage of View Data in a Warehousing Environment," ACM Transactions on Database Systems, vol. 25, no. 2, pp. 179-227, 2000. https://dl.acm.org/doi/10.1145/357775.357777
[6] Y. Cui, J. Widom, "Lineage Tracing for General Data Warehouse Transformations," The VLDB Journal, vol. 12, no. 1, pp. 41-58, 2003. https://link.springer.com/article/10.1007/s00778-002-0083-8
[7] T. Mao et al., "SQLGlot: Python SQL Parser and Transpiler," GitHub repository, 2024. https://github.com/tobymao/sqlglot
[8] DataHub Project, "SQL Parsing — Extracting Column-Level Lineage from SQL," 2024. https://docs.datahub.com/docs/lineage/sql_parsing
[9] Z. Jiang et al., "LineageX: A Column Lineage Extraction System for SQL," in Proc. ICDE (Demo Track), 2025. https://arxiv.org/abs/2505.23133
[10] OpenLineage Project, "OpenLineage Specification," Linux Foundation AI & Data, 2024. https://github.com/OpenLineage/OpenLineage
[11] OpenLineage Project, "Column Level Lineage Dataset Facet," 2024. https://openlineage.io/docs/spec/facets/dataset-facets/column_lineage_facet/
[12] Marquez Project, "Marquez: Collect, Aggregate, and Visualize a Data Ecosystem's Metadata," GitHub repository, 2024. https://github.com/MarquezProject/marquez
[13] dbt Labs, "Column-Level Lineage," dbt Developer Hub, 2025. https://docs.getdbt.com/docs/explore/column-level-lineage
[14] Canva, "dbt-column-lineage-extractor," GitHub repository, 2024. https://github.com/canva-public/dbt-column-lineage-extractor
[15] Apache Software Foundation, "OpenLineage Airflow Integration," apache-airflow-providers-openlineage Documentation, 2025. https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/guides/user.html
[16] OpenLineage Project, "Spark Column-Level Lineage," 2024. https://openlineage.io/docs/integrations/spark/spark_column_lineage/
[17] Basel Committee on Banking Supervision, "Principles for Effective Risk Data Aggregation and Risk Reporting," Bank for International Settlements, 2013. https://www.bis.org/publ/bcbs239.htm