Salta el contingut

Data Lake i Lakehouse

Un Data Lake (llac de dades) és un repositori centralitzat que emmagatzema dades de qualsevol format —estructurat, semiestructurat o no estructurat— en el seu estat natiu, sense imposar un esquema previ a la càrrega. Mentre que el Data Warehouse exigeix definir l'esquema abans d'escriure les dades (schema-on-write), el Data Lake aplica l'esquema en el moment de la lectura (schema-on-read). Aquesta flexibilitat el va convertir en l'opció predilecta per emmagatzemar logs, imatges, JSON, vídeo o dades de sensors IoT que mai encaixarien bé en un esquema relacional rígid. El 2026, pràcticament cap arquitectura de Big Data prescindeix d'un Data Lake com a capa base d'emmagatzematge.


Per qué va aparèixer el Data Lake

El Data Warehouse és excel·lent per a dades estructurades i conegudes per endavant: vendes, clients, productes. Però moltes empreses van començar a generar volums massius de dades que no encaixaven en aquest model: clics web, logs d'aplicació, imatges de producte, transcripcions de trucades, dades de sensors. Carregar tot això en un DW relacional és car, lent i sovint impossible (un DW no sap on guardar un fitxer de vídeo).

El Data Lake resol aquest problema separant dues decisions que el DW acobla: on s'emmagatzemen les dades i quina estructura tenen. Al Data Lake, qualsevol dada es pot desar immediatament en el seu format original; l'estructura (l'esquema) es decideix més tard, quan algú la necessita per a una anàlisi concreta.

Característica Data Warehouse Data Lake
Esquema Schema-on-write (definit abans de carregar) Schema-on-read (definit en llegir)
Tipus de dades Estructurades Estructurades, semiestructurades i no estructurades
Format d'emmagatzematge Propietari, optimitzat pel motor Obert (Parquet, ORC, Avro, JSON, imatges, vídeo)
Cost d'emmagatzematge Alt Baix (object storage: S3, ADLS Gen2)
Usuaris típics Analistes de negoci, BI Data Engineers, Data Scientists, ML Engineers
Casos d'ús Informes, dashboards, KPIs Machine Learning, exploració, dades crues per a transformar
Transaccions ACID Natives Depèn del format (Parquet no en té; Delta Lake/Iceberg/Hudi sí)

Arquitectura per zones (Medallion Architecture)

Un Data Lake mal organitzat és simplement una carpeta gegant de fitxers sense estructura. Per evitar-ho, la pràctica estàndard de la indústria és organitzar el lake en zones (també anomenada arquitectura medallion: bronze, silver, gold), on cada zona representa un grau creixent de qualitat i refinament de les dades.

flowchart LR
    FONT["Fonts de dades\n(BD operacionals, APIs,\nlogs, IoT, fitxers)"]

    subgraph RAW["Zona Raw / Bronze"]
        R["Dades en brut\nFormat original\nImmutables\nSense transformar"]
    end

    subgraph CURATED["Zona Curated / Silver"]
        C["Dades netes i validades\nTipades, deduplicades\nFormat Parquet/Delta"]
    end

    subgraph SERVING["Zona Serving / Gold"]
        S["Dades agregades\nModel dimensional\nLlestes per a consum"]
    end

    CONSUM["BI, ML, APIs,\naplicacions"]

    FONT --> R
    R -->|"ETL: neteja,\nvalidació, tipat"| C
    C -->|"ETL: agregació,\nmodelatge dimensional"| S
    S --> CONSUM

Zona Raw (Bronze)

La zona raw conserva una còpia exacta i immutable de les dades tal com arriben de la font, en el seu format original (CSV, JSON, logs, imatges). No s'aplica cap transformació ni validació. El propòsit és tenir sempre una font de veritat a la qual tornar si una transformació posterior falla o si cal reprocessar amb una lògica diferent.

  • S'organitza típicament per font i per data de partició: s3://datalake/bronze/vendes/any=2026/mes=02/dia=23/.
  • Pot incloure metadades d'ingestió (timestamp de càrrega, sistema origen) sense modificar les dades originals.
  • Habitualment s'aplica una política de retenció llarga, ja que l'espai d'object storage és barat.

Zona Curated (Silver)

A la zona curated, les dades de la zona raw es netegen, validen, tipen i deduplican. S'eliminen registres corruptes, es normalitzen formats de data, es resolen valors nuls i s'aplica un esquema consistent. El resultat és un conjunt de dades fiable, encara a granularitat de detall, llest per a ser combinat i agregat.

  • Format recomanat: Parquet o un format de taula obert (Delta Lake, Iceberg, Hudi) particionat de forma eficient.
  • És habitual aplicar control de qualitat de dades (data quality checks) en aquesta capa: rangs de valors vàlids, claus úniques, integritat referencial.

Zona Serving (Gold)

La zona serving conté les dades ja agregades i modelades per al consum final: taules de fets i dimensions en esquema estrella, mètriques de negoci precalculades, o vistes materialitzades optimitzades per a un cas d'ús concret (un dashboard de Power BI, un endpoint d'API, un model de recomanació).

  • És la capa que consulten directament els analistes de BI, els data scientists o les aplicacions.
  • Sovint es replica cap a un Data Warehouse (Redshift, Synapse) o es consulta directament amb un motor SQL sobre el lake (Athena, Synapse Serverless).

Bronze, Silver, Gold: un nom, moltes implementacions

Els noms "raw/curated/serving" i "bronze/silver/gold" són equivalents conceptualment; el segon és la terminologia popularitzada per Databricks i s'ha convertit en l'estàndard de facto de la indústria. AWS, Azure i la majoria d'eines moderns assumeixen aquesta organització per zones encara que no usin exactament aquests noms.


Parquet en profunditat

Els fitxers de la zona curated/serving quasi sempre estan en format Parquet, el format columnar que ha esdevingut l'estàndard de facto del Data Lake modern. Entendre la seva estructura interna explica per què és tan ràpid per a càrregues analítiques.

Estructura interna: fitxer, row groups i column chunks

Un fitxer Parquet no és un simple bolcat de columnes: s'organitza en una jerarquia de tres nivells que combina l'eficiència columnar amb la possibilitat de processar-lo en paral·lel per blocs.

flowchart TD
    F["Fitxer Parquet"] --> RG1["Row Group 1\n(p. ex. 1 milió de files)"]
    F --> RG2["Row Group 2"]
    RG1 --> CC1["Column Chunk: id_venda"]
    RG1 --> CC2["Column Chunk: import_net"]
    RG1 --> CC3["Column Chunk: pais"]
    CC2 --> P1["Page 1\n(valors + estadístiques\nmin/max/nulls)"]
    CC2 --> P2["Page 2"]

    style F fill:#1e3a5f,color:#e2e8f0,stroke:#3b82f6
    style RG1 fill:#1d4ed8,color:#ffffff,stroke:#3b82f6
    style RG2 fill:#1d4ed8,color:#ffffff,stroke:#3b82f6
    style CC1 fill:#7c3aed,color:#ffffff,stroke:#a78bfa
    style CC2 fill:#7c3aed,color:#ffffff,stroke:#a78bfa
    style CC3 fill:#7c3aed,color:#ffffff,stroke:#a78bfa
    style P1 fill:#166534,color:#ffffff,stroke:#22c55e
    style P2 fill:#166534,color:#ffffff,stroke:#22c55e
  • Un row group és un bloc horitzontal de files (típicament desenes o centenars de MB) que es pot llegir i processar de forma independent, permetent paral·lelitzar la lectura entre workers.
  • Dins de cada row group, cada columna es guarda com un column chunk separat i contigu al disc: llegir només import_net de milions de files implica llegir únicament els seus column chunks, ignorant totalment id_client, pais, etc.
  • Cada column chunk es divideix en pages, la unitat mínima de codificació i compressió.

Compressió i estadístiques

Com que cada column chunk conté valors del mateix tipus (tots enters, tots strings de país...), Parquet aplica tècniques de compressió molt més efectives que en un format per files: codificació de diccionari (per a columnes amb pocs valors únics, com pais), Run-Length Encoding (per a valors repetits consecutius) i compressors genèrics per pàgina (Snappy, per defecte; Zstd, per a millor ràtio de compressió a canvi de més CPU).

A més, cada column chunk emmagatzema estadístiques (valor mínim, valor màxim, nombre de nuls) al seu propi metadata, sense necessitat de llegir les dades.

Predicate pushdown

Aquestes estadístiques són el que fa possible el predicate pushdown: el motor de consulta pot descartar row groups sencers sense llegir-los, només mirant-ne les estadístiques.

# Si el row group té estadístiques min=2025-01-01, max=2025-06-30
# per a la columna 'data', i la consulta filtra WHERE data >= '2026-01-01',
# el motor sap que aquest row group no pot contenir cap fila rellevant
# i el descarta sense llegir ni un sol byte de dades.
import pyarrow.parquet as pq

fitxer = pq.ParquetFile("vendes_2026.parquet")

# Inspeccionar els metadades sense llegir les dades
print(f"Nombre de row groups: {fitxer.num_row_groups}")
print(f"Esquema: {fitxer.schema_arrow}")

metadata_rg0 = fitxer.metadata.row_group(0)
columna_import = metadata_rg0.column(metadata_rg0.num_columns - 1)
print(f"Min: {columna_import.statistics.min}, Max: {columna_import.statistics.max}")

# Llegir només les columnes necessàries (column pruning) i aplicar un filtre
# que activa el predicate pushdown a nivell de row group
taula = pq.read_table(
    "vendes_2026.parquet",
    columns=["data", "import_net"],
    filters=[("data", ">=", "2026-01-01")],
)
print(f"Files després del pushdown: {taula.num_rows}")

Column pruning + predicate pushdown: la combinació que fa ràpid l'anàlisi al lake

Llegir només les columnes necessàries (column pruning) i descartar row groups sencers per les seves estadístiques (predicate pushdown) són els dos motius principals pels quals una consulta analítica sobre Parquet és ordres de magnitud més ràpida que la mateixa consulta sobre un CSV: el motor evita llegir la immensa majoria de bytes del fitxer.


Particionament: organitzar terabytes de dades

Amb terabytes de dades, ni tan sols Parquet és prou ràpid si cal escanejar tots els fitxers per a cada consulta. El particionament organitza físicament les dades en carpetes segons el valor d'una o més columnes, de manera que el motor de consulta pugui descartar directoris sencers sense ni tan sols obrir-ne els fitxers.

Particionament a l'estil Hive

El patró estàndard (popularitzat per Hive) codifica el valor de la partició directament al nom del directori:

s3://datalake/silver/vendes/
├── any=2025/
│   ├── mes=11/dia=28/part-00001.parquet
│   └── mes=12/dia=15/part-00002.parquet
└── any=2026/
    ├── mes=01/dia=03/part-00001.parquet
    └── mes=02/dia=23/part-00001.parquet
import pyarrow.dataset as ds

# Escriure un dataset particionat per any i mes
ds.write_dataset(
    taula,
    base_dir="s3://datalake/silver/vendes",
    format="parquet",
    partitioning=ds.partitioning(
        pa.schema([("any", pa.int32()), ("mes", pa.int32())]), flavor="hive"
    ),
)

Partition pruning

Quan una consulta filtra per la columna de partició, el motor ni tan sols llista els directoris que no coincideixen amb el filtre, un pas previ i encara més eficient que el predicate pushdown a nivell de row group:

-- Amb partition pruning, el motor només llegeix
-- s3://datalake/silver/vendes/any=2026/mes=02/**
-- ignorant completament any=2025 sencer
SELECT SUM(import_net)
FROM silver.vendes
WHERE any = 2026 AND mes = 2;

El "small file problem"

Un error de disseny molt habitual és particionar amb massa granularitat (per exemple, per hora o per minut) sobre un volum de dades que no ho justifica: el resultat són milers de fitxers Parquet molt petits (uns quants KB cadascun) en lloc de pocs fitxers grans.

Això és perjudicial perquè:

  • Cada fitxer petit implica una petició d'I/O separada a l'object storage (S3, ADLS), amb la seva pròpia latència de xarxa.
  • El catàleg de metadades (Hive Metastore, Glue Catalog) ha de mantenir una entrada per fitxer, i llistar milions d'entrades es torna lent.
  • La sobrecàrrega de metadades (capçalera Parquet, estadístiques) pesa proporcionalment molt més en fitxers petits.
Símptoma Causa típica
Milers de fitxers d'uns quants KB per partició Particionament massa fi (per minut/hora) sobre poc volum
Molts fitxers petits generats per streaming Cada micro-batch de Spark Streaming escriu el seu propi fitxer
Consultes lentes malgrat tenir Parquet El coll d'ampolla és el nombre de peticions d'I/O, no la mida de les dades

Solucions habituals:

  • Triar la granularitat de partició segons el patró de consulta real (si la majoria de consultes filtren per mes, no particionis per dia).
  • Compactar periòdicament els fitxers petits en fitxers més grans (l'operació OPTIMIZE de Delta Lake, vista més endavant, automatitza això).
  • Apuntar a una mida objectiu de fitxer d'uns 128 MB–1 GB, un bon equilibri entre paral·lelisme de lectura i sobrecàrrega d'I/O.

El problema del Data Swamp

Un data swamp (pantà de dades) és el que passa quan un Data Lake es construeix sense governança: dades de qualsevol origen es carreguen sense documentar, sense control de qualitat i sense catàleg de metadades. Amb el temps, ningú sap qué conté cada fitxer, quina és la font de veritat, ni si les dades són fiables. El Data Lake deixa de ser un actiu i es converteix en un passiu: ocupa espai, costa diners i ningú confia en ell.

Les causes més habituals d'un data swamp són:

  • Absència de catàleg de metadades: no hi ha cap inventari de quines dades existeixen, on són ni qué signifiquen les seves columnes.
  • Absència d'estructura per zones: tot es barreja en una sola carpeta plana, sense distingir dades en brut de dades validades.
  • Absència de propietaris (data ownership): ningú és responsable de la qualitat o l'actualització d'un conjunt de dades concret.
  • Absència de polítiques de retenció: les dades s'acumulen indefinidament sense criteris de purga ni d'arxivat.
  • Absència de control d'accés granular: tothom pot escriure a qualsevol carpeta, generant duplicats i versions inconsistents.

Com evitar el data swamp: governança de dades

  • Catàleg de metadades centralitzat: eines com AWS Glue Data Catalog, Azure Purview o Unity Catalog (Databricks) documenten automàticament l'esquema, la ubicació i el llinatge (lineage) de cada conjunt de dades.
  • Arquitectura per zones obligatòria: cap dada es consulta directament des de la zona raw en producció; sempre passa per un procés de validació cap a la zona curated.
  • Control d'accés granular: permisos a nivell de carpeta o de taula (ACLs POSIX a ADLS Gen2, polítiques IAM a S3) que limiten qui pot llegir i escriure cada zona.
  • Llinatge de dades (data lineage): traçabilitat de quina transformació ha generat cada conjunt de dades i a partir de quines fonts, fonamental per a auditories i depuració.
  • Qualitat de dades automatitzada: validacions executades en cada càrrega (esquemes esperats, rangs de valors, unicitat de claus) que rebutgen o marquen els registres anòmals.

Data Lakehouse: el millor dels dos mons

Durant anys, les organitzacions havien de triar entre dues arquitectures amb compromisos oposats: el Data Warehouse (ràpid, fiable, però rígid i car per a dades no estructurades) o el Data Lake (flexible i barat, però sense transaccions ACID ni garanties de consistència). El Data Lakehouse és l'arquitectura que neix per eliminar aquest compromís: aplica les garanties tradicionals del Data Warehouse (transaccions ACID, control de versions, esquemes aplicats) directament sobre l'emmagatzematge obert i barat d'un Data Lake (S3, ADLS Gen2).

flowchart TD
    DW["Data Warehouse\nACID, esquema rígid\nCar, format propietari\nNomés dades estructurades"]
    DL["Data Lake\nBarat, format obert\nQualsevol tipus de dada\nSense ACID ni consistència"]
    LH["Data Lakehouse\nACID + format obert\nBarat i fiable alhora\nEstructurades i no estructurades"]

    DW -->|"Aporta fiabilitat"| LH
    DL -->|"Aporta flexibilitat i cost"| LH

La clau tècnica que fa possible el Lakehouse és l'aparició dels formats de taula oberts: una capa de metadades que s'afegeix sobre fitxers Parquet normals i els dota de capacitats transaccionals, sense necessitat d'un motor de base de dades propietari.

Per qué Parquet sol no és suficient

Parquet és un format de fitxer columnar excel·lent per al rendiment de lectura, però no té cap noció de "taula": no hi ha transaccions, no es pot fer un UPDATE o DELETE atòmic sobre les files existents, i si una escriptura falla a mig camí, el conjunt de dades pot quedar en un estat inconsistent (alguns fitxers nous escrits, altres no). Els formats de taula oberts resolen exactament aquest problema afegint un registre transaccional (un "log") per sobre dels fitxers Parquet.


Delta Lake

Delta Lake és el format de taula obert creat per Databricks (els creadors d'Apache Spark) i és el més usat en l'ecosistema Azure/Databricks. Emmagatzema les dades en fitxers Parquet estàndard i afegeix un transaction log (carpeta _delta_log) que registra cada operació (insercions, actualitzacions, esborrats, canvis d'esquema) de forma ordenada i atòmica.

Capacitats principals de Delta Lake

  • Transaccions ACID: cada escriptura és atòmica; si falla, no deixa dades parcials visibles.
  • Time travel: es pot consultar l'estat de la taula tal com era en una versió o en un moment anteriors.
  • Schema enforcement i schema evolution: rebutja escriptures que no compleixin l'esquema, però permet evolucionar-lo de forma controlada (afegir columnes noves).
  • UPSERT i DELETE eficients amb l'operació MERGE INTO, impossible amb Parquet pur sense reescriure tota la taula.
  • Optimització automàtica: compactació de fitxers petits (auto-compaction) i ordenació multidimensional (Z-ordering) per accelerar les consultes.
-- Crear una taula Delta Lake a Databricks / Spark SQL
CREATE TABLE silver.vendes (
    id_venda BIGINT,
    data_venda DATE,
    id_client INT,
    id_producte INT,
    import_net DECIMAL(10,2)
)
USING DELTA
LOCATION 'abfss://silver@datalake.dfs.core.windows.net/vendes/';

-- UPSERT (MERGE) de noves vendes sobre la taula existent
MERGE INTO silver.vendes AS dest
USING staging.vendes_noves AS src
ON dest.id_venda = src.id_venda
WHEN MATCHED THEN
    UPDATE SET dest.import_net = src.import_net
WHEN NOT MATCHED THEN
    INSERT (id_venda, data_venda, id_client, id_producte, import_net)
    VALUES (src.id_venda, src.data_venda, src.id_client, src.id_producte, src.import_net);

-- Time travel: consultar la taula tal com era fa 3 versions
SELECT * FROM silver.vendes VERSION AS OF 3;
SELECT * FROM silver.vendes TIMESTAMP AS OF '2026-02-01';

Manteniment de la taula: VACUUM i OPTIMIZE

El MERGE INTO i les actualitzacions contínues generen, amb el temps, fitxers Parquet petits i fitxers "morts" (versions antigues que el time travel encara referencia). Delta Lake ofereix dues comandes de manteniment imprescindibles en producció:

-- OPTIMIZE: compacta els fitxers petits en fitxers grans (bin-packing)
-- i, opcionalment, els reordena per les columnes més consultades (Z-ORDER)
OPTIMIZE silver.vendes
ZORDER BY (data_venda, id_client);

-- VACUUM: elimina físicament els fitxers de dades que ja no pertanyen
-- a cap versió dins del període de retenció (per defecte, 7 dies)
VACUUM silver.vendes RETAIN 168 HOURS;
  • OPTIMIZE resol directament el small file problem descrit més amunt: reescriu molts fitxers petits en pocs fitxers grans ben dimensionats, sense canviar el contingut lògic de la taula. Z-ORDER ordena físicament les dades segons una o diverses columnes perquè el predicate pushdown sigui encara més efectiu quan es filtra per aquestes columnes.
  • VACUUM allibera espai d'emmagatzematge eliminant fitxers que ja no calen. Compte: un VACUUM amb un període de retenció massa curt pot trencar consultes de time travel o processos concurrents que encara llegeixen versions antigues de la taula.

VACUUM i time travel són incompatibles a llarg termini

Si necessites poder consultar l'estat de la taula de fa 6 mesos, no pots executar VACUUM RETAIN 168 HOURS (7 dies): els fitxers d'aquella versió ja no existirien. Defineix la política de retenció segons els requisits d'auditoria del cas d'ús, no només segons l'espai en disc disponible.


Apache Iceberg

Apache Iceberg és un format de taula obert creat originalment a Netflix per resoldre els problemes de rendiment i consistència de les taules Hive a gran escala. És el format més neutral respecte als proveïdors de cloud i compta amb suport natiu d'AWS (Athena, Glue, EMR, Redshift), Snowflake i Google BigQuery, cosa que el converteix en l'opció preferida en arquitectures multi-cloud o on es vol evitar el lock-in d'un sol proveïdor.

Capacitats principals d'Iceberg

  • Transaccions ACID i time travel, igual que Delta Lake.
  • Partition evolution: es pot canviar l'esquema de particionament d'una taula sense haver de reescriure totes les dades existents, un problema seriós a les taules Hive tradicionals.
  • Hidden partitioning: l'usuari no necessita conèixer ni escriure manualment les columnes de partició a les consultes; Iceberg gestiona el partition pruning de forma transparent.
  • Múltiples motors de còmput simultanis: Spark, Trino, Flink i Athena poden llegir i escriure la mateixa taula Iceberg de forma consistent.
-- Crear una taula Iceberg des d'Amazon Athena
CREATE TABLE bronze.vendes (
    id_venda bigint,
    data_venda date,
    id_client int,
    import_net decimal(10,2)
)
PARTITIONED BY (month(data_venda))
LOCATION 's3://datalake/bronze/vendes/'
TBLPROPERTIES ('table_type' = 'ICEBERG');

-- DELETE eficient: esborrar les dades d'un client (compliment GDPR)
DELETE FROM bronze.vendes WHERE id_client = 48213;

-- Time travel amb Iceberg
SELECT * FROM bronze.vendes FOR TIMESTAMP AS OF TIMESTAMP '2026-02-01 00:00:00';

La capa de metadades: com Iceberg sap què conté la taula

La diferència més profunda d'Iceberg respecte a Hive no és visible a primer cop d'ull: en lloc de descobrir els fitxers d'una taula llistant un directori (lent i poc fiable a gran escala), Iceberg manté una jerarquia explícita de metadades que indica exactament quins fitxers formen la taula en cada moment.

flowchart TD
    CAT["Catàleg\n(Glue, Hive Metastore...)"] --> MD["Metadata file\n(esquema, partition spec,\nllista de snapshots)"]
    MD --> SNAP["Snapshot actual"]
    SNAP --> ML["Manifest list"]
    ML --> M1["Manifest file 1"]
    ML --> M2["Manifest file 2"]
    M1 --> D1["Fitxer de dades\nParquet"]
    M1 --> D2["Fitxer de dades\nParquet"]
    M2 --> D3["Fitxer de dades\nParquet"]

    style CAT fill:#1e3a5f,color:#e2e8f0,stroke:#3b82f6
    style MD fill:#1d4ed8,color:#ffffff,stroke:#3b82f6
    style SNAP fill:#7c3aed,color:#ffffff,stroke:#a78bfa
    style ML fill:#b45309,color:#ffffff,stroke:#f59e0b
    style M1 fill:#166534,color:#ffffff,stroke:#22c55e
    style M2 fill:#166534,color:#ffffff,stroke:#22c55e
    style D1 fill:#374151,color:#ffffff,stroke:#6b7280
    style D2 fill:#374151,color:#ffffff,stroke:#6b7280
    style D3 fill:#374151,color:#ffffff,stroke:#6b7280
  • Un snapshot és una fotografia immutable de l'estat complet de la taula en un moment donat: la llista exacta de fitxers de dades que la componen. Cada escriptura crea un snapshot nou; els antics es conserven (fins que es "podin") i són el mecanisme que fa possible el time travel.
  • Una manifest list enumera els manifest files que pertanyen a un snapshot concret.
  • Cada manifest file conté la llista de fitxers de dades reals, més estadístiques a nivell de fitxer (min/max per columna), permetent descartar fitxers sencers sense obrir-los — el mateix principi del predicate pushdown de Parquet, aplicat un nivell més amunt.

Gràcies a aquesta estructura, Iceberg pot saber en mil·lisegons quins fitxers ha de llegir per a una consulta, encara que la taula tingui milions de fitxers, sense necessitat de llistar cap directori físicament.

Merge-on-read vs copy-on-write

Quan cal actualitzar o esborrar files d'una taula Iceberg (o Delta/Hudi), hi ha dues estratègies possibles:

Copy-on-Write (COW) Merge-on-Read (MOR)
Què passa en escriure un UPDATE/DELETE Es reescriu immediatament el fitxer de dades afectat sencer, amb les files ja modificades Es desa només un petit fitxer de delta/esborrat (delete file) que marca quines files ja no són vàlides
Cost de l'escriptura Alt (reescriure fitxers grans per canviar poques files) Baix (escriptura petita i ràpida)
Cost de la lectura Baix (les dades ja estan "netes", no cal fusionar res) Més alt (cal fusionar el fitxer de dades base amb els delete/delta files a cada lectura)
Cas d'ús ideal Poques actualitzacions, moltes lectures (analítica clàssica) Moltes actualitzacions incrementals (CDC, streaming)
-- Configurar una taula Iceberg en mode merge-on-read
ALTER TABLE bronze.vendes SET TBLPROPERTIES (
    'write.delete.mode' = 'merge-on-read',
    'write.update.mode' = 'merge-on-read'
);

Aquesta és exactament la decisió que distingeix Hudi d'Iceberg/Delta

Apache Hudi (vist a continuació) va néixer precisament centrat en el mode merge-on-read per a càrregues d'actualització massives i freqüents; Iceberg i Delta Lake el suporten com a opció però estan optimitzats per defecte per a copy-on-write.


Time travel i versionat avançat

Consultar una versió anterior (VERSION AS OF, TIMESTAMP AS OF) és només l'ús més bàsic del model de snapshots. Els formats de taula oberts moderns (sobretot Iceberg) ofereixen operacions de versionat directament inspirades en el control de versions de codi (Git).

Rollback: restaurar l'estat actual a una versió anterior

A diferència d'una simple consulta de time travel (que llegeix el passat sense tocar res), un rollback canvia quin és l'estat "actual" de la taula, apuntant-la de nou a un snapshot anterior:

-- Amb Spark SQL sobre una taula Iceberg
CALL catalog.system.rollback_to_snapshot('bronze.vendes', 8735192837465123);

-- O per timestamp
CALL catalog.system.rollback_to_timestamp('bronze.vendes', TIMESTAMP '2026-02-01 00:00:00');

Útil per revertir immediatament una càrrega defectuosa (per exemple, si un pipeline ha escrit dades duplicades o corruptes) sense haver de refer tot el processament.

Branching: línies de treball paral·leles

Un branch a Iceberg és una referència amb nom (com una branca de Git) que apunta al seu propi historial de snapshots, independent de la branca principal (main). Permet escriure i provar canvis sense afectar les consultes de producció que llegeixen main:

-- Crear una branca per provar una transformació nova sense afectar producció
ALTER TABLE bronze.vendes CREATE BRANCH `prova_nova_etl`;

-- Escriure i validar a la branca de prova
INSERT INTO bronze.vendes.branch_prova_nova_etl VALUES (...);

-- Si tot va bé, es pot fusionar el resultat cap a main;
-- si no, simplement s'elimina la branca sense cap impacte
ALTER TABLE bronze.vendes DROP BRANCH `prova_nova_etl`;

Tags: referències permanents per a auditoria

Un tag és una referència amb nom a un snapshot concret que no avança amb noves escriptures (a diferència d'un branch). S'usa per marcar snapshots que cal conservar indefinidament amb finalitats d'auditoria, independentment de la política de retenció general:

ALTER TABLE bronze.vendes CREATE TAG `tancament_fiscal_2025` AS OF VERSION 4123;

Cherry-pick: aplicar un canvi concret sense arrossegar-hi la resta

Permet incorporar el canvi introduït per un snapshot concret (fet, per exemple, en una branca de prova) cap a main, sense aplicar-hi cap altre canvi intermedi que s'hagi produït mentrestant a la branca d'origen:

CALL catalog.system.cherrypick_snapshot('bronze.vendes', 8735192837465999);

Per què això importa en un Data Lake, i no només en un repositori de codi

Aquestes operacions converteixen les dades en un actiu auditable i reversible, exactament com el codi font. Un error de qualitat detectat després d'una càrrega ja no obliga a "arreglar-ho a mà": es pot fer rollback a l'últim estat correcte en segons, provar la correcció en una branca aïllada, i només fusionar-la quan estigui validada.


Apache Hudi

Apache Hudi (Hadoop Upserts Deletes and Incrementals), creat originalment a Uber, està especialment optimitzat per a càrregues amb moltes actualitzacions incrementals (per exemple, sincronitzar contínuament canvis des d'una base de dades operacional mitjançant Change Data Capture). Mentre que Delta Lake i Iceberg estan més orientats a càrregues batch, Hudi destaca en escenaris on cal aplicar milions de petits canvis (upserts) de forma eficient i gairebé en temps real.

Capacitats principals de Hudi

  • Dos tipus de taula: Copy on Write (optimitzat per a lectura, reescriu fitxers en cada actualització) i Merge on Read (optimitzat per a escriptura ràpida, fusiona els canvis en el moment de la lectura).
  • Incremental queries: permet consultar únicament els registres que han canviat des de l'última consulta, ideal per a pipelines incrementals.
  • Integració nativa amb eines de CDC (Debezium, AWS DMS) per replicar bases de dades operacionals cap al Data Lake en temps quasi real.

Comparativa dels tres formats de taula oberts

Característica Delta Lake Apache Iceberg Apache Hudi
Origen Databricks Netflix Uber
Millor integració Azure / Databricks / Spark AWS (Athena, Glue, Redshift), multi-cloud Càrregues amb CDC i upserts intensius
Time travel
Partition evolution Limitat Sí (punt fort) Limitat
Cas d'ús ideal Lakehouse general sobre Spark/Databricks Interoperabilitat multi-motor i multi-cloud Ingestió incremental contínua (CDC)
Maduresa al 2026 Molt alta Molt alta i creixent Alta, més especialitzada

No cal triar-ne només un per sempre

Els tres formats són compatibles amb Parquet i cada vegada més eines (Snowflake, BigQuery, Databricks) suporten lectura creuada entre formats. La tria depèn principalment de l'ecosistema cloud predominant (Azure → Delta Lake; AWS multi-motor → Iceberg) i del patró de càrrega (batch → Delta/Iceberg; CDC intensiu → Hudi).


Comparativa final: Data Warehouse vs Data Lake vs Lakehouse

Aspecte Data Warehouse Data Lake Data Lakehouse
Esquema Schema-on-write Schema-on-read Schema-on-write (aplicat per la capa de taula)
Tipus de dades Només estructurades Qualsevol tipus Qualsevol tipus, amb estructura per a l'anàlisi
Transaccions ACID Sí (nativa) No Sí (Delta Lake, Iceberg, Hudi)
Cost d'emmagatzematge Alt Baix Baix (mateix object storage que el lake)
Rendiment analític Molt alt Variable (depèn del format) Alt, comparable al DW
Machine Learning Difícil (dades ja agregades) Natural (dades en brut accessibles) Natural
Exemples d'eines Redshift, Synapse SQL Pool, Snowflake S3 + Athena, ADLS Gen2 Databricks (Delta Lake), Snowflake + Iceberg, Redshift Spectrum + Iceberg

La tendència del 2026

Cada vegada més organitzacions adopten directament una arquitectura Lakehouse en lloc de mantenir un Data Warehouse i un Data Lake separats. Això simplifica l'arquitectura (una sola còpia de les dades, no dues), redueix els costos de duplicació i permet que els mateixos equips de BI i de Data Science treballin sobre la mateixa font de dades amb les eines que prefereixin.


Catàlegs i governança de dades

La secció del Data Swamp ja ha introduït per què cal governança; aquí s'aprofundeix en com s'implementa concretament amb un catàleg de dades, que fa quatre feines diferenciades.

1. Descobriment (discovery)

Sense catàleg, "saber quines dades existeixen" depèn de preguntar a algú de l'equip o de rebuscar entre carpetes de S3. Un catàleg indexa totes les taules del lake (nom, esquema, ubicació, mida, última actualització) i ofereix cerca per nom, per etiqueta o pel contingut de l'esquema, de manera que qualsevol analista pugui trobar per si mateix "hi ha alguna taula amb dades de vendes per país?" sense dependre de ningú.

2. Llinatge (lineage)

El llinatge respon "d'on ve aquesta dada i què li ha passat pel camí?": quina taula raw l'ha originada, quines transformacions ha travessat, i quines taules o dashboards en depenen aigües avall.

flowchart LR
    A["raw.vendes_api\n(zona Bronze)"] -->|"ETL: neteja,\ntipat"| B["silver.vendes\n(zona Silver)"]
    B -->|"ETL: agregació\nper trimestre"| C["gold.kpi_vendes_trimestre\n(zona Gold)"]
    C --> D["Dashboard Power BI\n'Rendiment comercial'"]
    B --> E["Model ML\nde recomanació"]

    style A fill:#92400e,color:#ffffff,stroke:#f59e0b
    style B fill:#9ca3af,color:#1f2937,stroke:#6b7280
    style C fill:#b45309,color:#ffffff,stroke:#f59e0b
    style D fill:#166534,color:#ffffff,stroke:#22c55e
    style E fill:#166534,color:#ffffff,stroke:#22c55e

Aquest graf és el que permet respondre, sense investigació manual, preguntes com "si canvio l'esquema de silver.vendes, quins dashboards i models es trencaran?" — vital abans de fer qualsevol canvi estructural en producció.

3. Permisos i control d'accés granular

Un catàleg modern no només documenta les dades: també n'aplica els permisos, idealment a un nivell més fi que "tot el bucket" o "tota la taula":

-- Amb Databricks Unity Catalog: accés a nivell de columna i de fila
GRANT SELECT ON TABLE silver.vendes TO ROLE analista_regional;

-- Màscara de columna: el DNI del client només és visible per al rol de compliance
ALTER TABLE silver.clients ALTER COLUMN dni
    SET MASK compliance_only_mask;

-- Filtre de fila: un analista regional només veu les vendes de la seva regió
ALTER TABLE silver.vendes SET ROW FILTER filtre_per_regio ON (regio);

4. Contractes de dades: la peça que falta al catàleg

Un catàleg documenta què hi ha; no garanteix per si sol que seguirà complint el mateix format demà. Aquesta garantia és exactament el paper dels contractes de dades vistos al Bloc 5: un acord versionat entre qui produeix una taula del lake i qui la consumeix, amb el seu schema, les seves regles de canvi (breaking vs no-breaking) i el seu propietari. En un Lakehouse madur, catàleg i contractes de dades es complementen: el catàleg respon "què existeix i qui hi pot accedir", el contracte respon "quines garanties tinc que no es trenqui res demà".

Eina de catàleg Proveïdor Punt fort
AWS Glue Data Catalog AWS Integració nativa amb Athena, EMR i Redshift Spectrum
Microsoft Purview Azure Descobriment i classificació automàtica de dades sensibles
Unity Catalog Databricks Permisos granulars (columna/fila) unificats entre Lakehouse i ML
Apache Atlas Open source Alternativa autogestionada, independent de cap cloud

AC5074/04/04 — Comparativa de costos i capacitats AWS vs Azure

Retoma el cas de Sapa-Shop (e-commerce català, 50 milions de transaccions/any, 2 TB de logs diaris) treballat en els blocs anteriors.

  1. Proposa una arquitectura Lakehouse completa per a Sapa-Shop especificant les tres zones (raw/curated/serving) i el format de taula obert que triaries (Delta Lake, Iceberg o Hudi). Justifica la tria en funció de si optaries per AWS o per Azure.
  2. Identifica almenys dos riscos concrets de "data swamp" que podrien aparèixer si Sapa-Shop no aplica governança des del primer dia, i proposa una mesura concreta per evitar cadascun.
  3. Compara el cost mensual aproximat d'emmagatzemar 2 TB/dia de logs durant 12 mesos a S3 Standard (AWS) versus ADLS Gen2 Hot tier (Azure), usant les taules de preus dels capítols anteriors.
  4. Quina diferència pràctica suposaria per a Sapa-Shop triar Apache Iceberg en lloc de Delta Lake, tenint en compte que ja tenen part de la infraestructura a AWS Athena?

Format de lliurament: document text (màx. 2 pàgines) amb la proposta d'arquitectura, els riscos identificats i la taula comparativa de costos.


Recursos de referència


Mòdul M5074 Sistemes de Big Data | Institut Sa Palomera (Blanes) | Curs CEIABD 2026-2027