
Nell’era del big data, la gestione efficiente e affidabile delle informazioni è diventata una sfida cruciale per le aziende di ogni dimensione. Apache Spark si è affermato come uno strumento potente per l’elaborazione dei dati su larga scala, ma con l’introduzione di Delta Lake, le possibilità si sono ampliate notevolmente.
Questo articolo esplorerà come Delta Lake sta rivoluzionando la gestione dei dati e come può ottimizzare i processi aziendali, fornendo un’analisi delle sue caratteristiche e funzionalità.
Perché Delta Lake?
Prima di vedere cosa sia Delta Lake, è necessario chiedersi cosa abbia portato alla necessità di realizzare uno nuovo strumento per la gestione dati.
Non è forse vero che oggi abbiamo già tutto? Abbiamo data-warehouse, abbiamo data-lake, abbiamo sistemi di calcolo distribuito come Spark, e molto altro…
Ad oggi infatti un’architettura comune nei sistemi di gestione dei big data prevede l’utilizzo dei così detti data-lake: ovvero storage adatti ad ospitare dati destrutturati. Poi spesso, una parte dei dati processati, viene trasferita dalla medallion architecture presente nel data-lake, ad un data-warehouse per ulteriore analisi o visualizzazione.
Nel tempo si è cercato di utilizzare il data-lake come storage anche dei dati più strutturati, andando a gestire formati di file, come il “parquet” che hanno anche un concetto interno di schema. Questo per cercare di semplificare le cose, in modo da utilizzare il data-lake anche come un data-warehouse.
Tuttavia questo ha da subito messo in evidenza una verità: i data-lake non sarebbero stati un sostituto valido dei data-warehouse perchè mancavano all’appello molte delle funzionalità tipiche dei sistemi relazionali come SQL Server, Oracle, ecc…
Ad esempio la gestione delle transazioni, dello schema, dell’indicizzazione e altre funzioni erano necessarie per ottenere un sistema di analisi sicuro e performante.
Da qui, l’idea di portare queste funzionalità su un data-lake. Ok, in pratica è stato vivisezionato un database relazionale ed è stato ricostruito a pezzi in cloud… 😅
Ma per quanto possa sembrare banale, la realizzazione di questo nuovo strumento, il Delta Lake, ha portato la data-engineering e la data-science ad un nuovo livello…
Cos’è Delta Lake?
Delta Lake è uno strato software open-source che si integra con Apache Spark, portando affidabilità e prestazioni di livello enterprise ai data lakes. Sviluppato da Databricks e ora parte della Linux Foundation, Delta Lake estende le capacità di Spark introducendo funzionalità critiche per la gestione dei dati su larga scala.
In pratica è un layer che si interpone tra lo storage dati (ad esempio HDFS, Azure Blob Storage, S3, ecc…) e il cluster di compute dove viene eseguito Spark.
Questo strato software aggiuntivo permette quindi di ottenere il meglio dai due mondi: i data lakes ed i data warehouse. Ed infatti, quando ci si riferisce a termini come “data-lakehouse” o “lakehouse”, stiamo parlando proprio di sistemi che tramite Delta Lake, si comportano da “ibridi” tra i due mondi.
Lo fa mettendo a disposizione dello storage alcuni meccanismi tipici dei database relazionali usati in ambiente DWH:
- Transazioni ACID: Garantisce l’integrità dei dati attraverso operazioni atomiche, consistenti, isolate e durevoli. Grazie alle transazioni ACID, infatti, si eliminano le inconsistenze dei dati e le problematiche ad esse associate. È come disporre di un sistema che garantisce la tracciabilità e la gestione precisa di ogni modifica ai dati.
- Gestione dello Schema: Offre schema enforcement e schema evolution per mantenere la coerenza dei dati nel tempo. In un contesto dove i requisiti dei dati mutano rapidamente, la capacità di far evolvere lo schema dei dati senza interrompere le operazioni in corso è inestimabile. Delta Lake permette di farlo con facilità, adattandosi alle esigenze in continua evoluzione.
- Storage Unificato: Integra senza problemi l’elaborazione batch e streaming.
- Time Travel: Permette di accedere e ripristinare versioni precedenti dei dati. Questo risulta utile sia per il debugging, ma anche per la conformità normative ed il recupero di errori.
- Ottimizzazione delle Performance: Implementa tecniche avanzate come la compattazione dei file e l’indicizzazione Z-Order.
Quindi Delta Lake si configura come una soluzione completa che affronta sfide concrete nella gestione dei dati. Offre un equilibrio tra affidabilità, prestazioni, flessibilità e sicurezza, il tutto in un pacchetto che si integra armoniosamente con le moderne architetture cloud e big data.
Integrazione con Apache Spark
L’integrazione di Delta Lake con Apache Spark è progettata per essere semplice e potente, permettendo agli sviluppatori di sfruttare le funzionalità di Delta Lake con minime modifiche al codice esistente.
Configurazione di Spark con Delta Lake
Per iniziare a utilizzare Delta Lake con pySpark, è necessario configurare correttamente la sessione Spark, installando innanzitutto il pacchetto delta.spark.
pip install delta-spark
Successivamente è necessario eseguire pySpark andando ad definire le configurazioni Delta.
import pyspark
from delta import *
from pyspark.sql.types import *
from delta.tables import *
from pyspark.sql.functions import *
# Create a spark session with Delta
builder = pyspark.sql.SparkSession.builder.appName("DeltaTutorial") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog")
# Create spark context
spark = configure_spark_with_delta_pip(builder).getOrCreate()
spark.sparkContext.setLogLevel("ERROR")
Funzionalità chiave di Delta Lake: qualche approfondimento
1. Transazioni ACID
Delta Lake implementa transazioni ACID (Atomicity, Consistency, Isolation, Durability) attraverso un meccanismo di controllo della concorrenza ottimistico.
Implementazione Tecnica:
- Utilizza un log di transazioni per tenere traccia di tutte le modifiche.
- Implementa il controllo della concorrenza attraverso il versioning dei file.
- Gestisce i conflitti attraverso retry automatici delle transazioni in caso di conflitti.
Esempio di Codice:
# Read the DataFrame from the input path
df_rate_codes = spark \ .read \ .format("csv") \ .option("inferSchema", True) \ .option("header", True) \ .load(INPUT_PATH)
# salva il data frame in una delta table df_rate_codes.write.format("delta").saveAsTable('[schema].[table]')
Quando si scrive un file utilizzando questo formato, stiamo semplicemente scrivendo un file Parquet standard con metadati aggiuntivi.
Questi metadati aggiuntivi sono la base per abilitare le funzionalità principali di Delta Lake, e anche solo per eseguire operazioni DML tipicamente viste nei RDBMS tradizionali come INSERT, UPDATE e DELETE, tra una vasta gamma di altre operazioni.
Tali record delle transazioni sono storicizzati in un file _delta_log che, proprio come in un database relazionale, tiene traccia dello storico delle operazioni sui dati.
Tabelle managed vs unmanaged
In Delta Lake, una managed table è una tabella in cui sia i dati che il loro schema vengono gestiti dal sistema di storage (come un data lake). Quando si crea una managed table, i dati vengono salvati in una directory gestita dal sistema, e la tabella viene eliminata insieme ai dati se viene eseguito un comando DROP
.
Al contrario, una unmanaged table (o external table) consente di specificare una directory esterna per la memorizzazione dei dati. In questo caso, solo lo schema della tabella viene gestito dal sistema, mentre i dati rimangono nella posizione esterna. Se si elimina la tabella, i dati non vengono eliminati.
Questo differente approccio viene definito in fase di scrittura dei dati, in quanto il metodo “save” realizza una tabella non gestita (ed infatti l’argomento è proprio il path dello storage su cui scrivere).
Se invece si utilizza il metodo “saveAsTable” si dovrà specificare il percorso del catalog gestito ([schema].[tabella]), come avviene nell’esempio precedente.
La scelta tra managed e unmanaged table in Delta Lake dipende dalle esigenze di gestione dei dati e dai casi d’uso specifici.
Quando utilizzare una managed table:
- Gestione automatica: Se si desidera che Delta Lake gestisca sia i dati che lo schema in modo centralizzato, è preferibile utilizzare una managed table. In questo caso, il sistema si occupa dell’archiviazione e della rimozione automatica dei dati in caso di eliminazione della tabella.
- Semplicità: Questa opzione è ideale quando non è necessario controllare direttamente i file sottostanti e si preferisce una gestione automatizzata dell’intero ciclo di vita dei dati.
- Casi d’uso: Prototipazione, progetti piccoli o medi dove non è richiesta una gestione personalizzata dei file.
Quando utilizzare una unmanaged table:
Dati esistenti: Quando i dati sono già memorizzati in una posizione specifica e si desidera solo registrare lo schema, senza spostare i dati stessi.
Controllo sui file: Se si necessita di gestire direttamente il percorso di archiviazione dei dati o si vuole mantenere i dati indipendenti dallo schema della tabella, è meglio optare per una unmanaged table.
Condivisione dei dati: In situazioni in cui i dati devono essere accessibili ad altri strumenti o applicazioni (ad esempio per analisi esterne o backup), una unmanaged table permette un controllo più granulare sul file system.
2. Gestione dello schema
Delta Lake applica automaticamente lo schema ai dati in scrittura e supporta l’evoluzione dello schema nel tempo.
Implementazione Tecnica:
- Memorizza lo schema come parte dei metadati della tabella.
- Verifica la conformità dei dati in ingresso allo schema esistente.
- Supporta l’aggiunta di nuove colonne e la modifica dei tipi di dati esistenti.
Esempio di Codice:
from pyspark.sql.types import StructType, StructField, StringType, IntegerType
# Definizione dello schema iniziale
schema = StructType([
StructField("id", StringType(), True),
StructField("name", StringType(), True),
StructField("age", IntegerType(), True)
])
# Creazione della tabella con lo schema definito
df.write.format("delta").schema(schema).save("/path/to/delta-table")
# Evoluzione dello schema: aggiunta di una nuova colonna
spark.read.format("delta").load("/path/to/delta-table") \
.withColumn("email", StringType()) \
.write.format("delta").mode("overwrite").option("mergeSchema", "true") \
.save("/path/to/delta-table")
3. Time Travel
La funzionalità di Time Travel permette di accedere a versioni precedenti dei dati, facilitando audit, rollback e analisi storiche.
Implementazione Tecnica:
- Mantiene un log delle transazioni con versioni incrementali.
- Permette di specificare la versione o il timestamp per accedere ai dati storici.
Esempio di Codice:
# Leggi la versione più recente
df_latest = spark.read.format("delta").load("/path/to/delta-table")
# Leggi una versione specifica (es. versione 5)
df_version_5 = spark.read.format("delta").option("versionAsOf", 5).load("/path/to/delta-table")
# Leggi i dati a un timestamp specifico
df_timestamp = spark.read.format("delta").option("timestampAsOf", "2023-03-01 00:00:00").load("/path/to/delta-table")
4. Ottimizzazione delle Performance
Delta Lake offre diverse tecniche per ottimizzare le performance delle query e ridurre i costi di storage.
Implementazione Tecnica:
- Compattazione dei File: Combina piccoli file in file più grandi per migliorare l’efficienza delle query.
- Indicizzazione Z-Order: Organizza i dati per ottimizzare le query su colonne specifiche.
Esempio di Codice:
# Compattazione dei file
deltaTable.optimize().executeCompaction()
# Indicizzazione Z-Order
deltaTable.optimize().executeZOrderBy("date", "country")
Conclusione
Delta Lake rappresenta un significativo passo avanti nella gestione dei dati, offrendo un’architettura robusta e flessibile per le moderne esigenze di data engineering.
La combinazione di affidabilità, scalabilità e prestazioni lo rende una scelta eccellente per le organizzazioni che cercano di ottimizzare i loro processi di gestione dati
L’adozione di Delta Lake può portare a miglioramenti sostanziali in termini di efficienza operativa, qualità dei dati e capacità di analisi.