Découvrez les système de stockage Open Table Formats Delta Lake et Apache Iceberg

Après avoir exploré les concepts théoriques des architectures Lakehouse, votre directeur technique Marc vous confie maintenant une mission pratique : choisir et implémenter le format de table ouvert le plus adapté aux besoins de l'entreprise. Les équipes ont identifié deux candidats principaux : Delta Lake et Apache Iceberg. Chacun promet des transactions ACID, une évolution des schémas et des performances optimisées, mais lequel répondra le mieux aux spécificités agricoles de GreenFarm ? Marc vous demande de plonger dans les détails techniques de ces deux technologies et de réaliser vos premières expérimentations. C'est parti !

Les data lakes sont des entrepôts de fichiers : flexibles, peu coûteux, mais sans garantie d’intégrité.
Pour une requête analytique ou une mise à jour de données, cela peut devenir un casse-tête : fichiers partiels, schémas incohérents, difficultés à rejouer une opération...

Les open table formats résolvent ces problèmes en ajoutant :

  • un journal de transactions pour garantir les opérations ACID ;

  • un système de versioning (time travel) ;

  • une gestion des métadonnées pour optimiser les requêtes ;

  • et une compatibilité multi-outils : Spark, Trino, Flink, DuckDB, Python...

Ces formats, comme Delta Lake ou Apache Iceberg, sont la clé de l’architecture Lakehouse — un pont entre la souplesse du data lake et la fiabilité du data warehouse.

 

Maîtrisez l'écosystème Delta Lake

Delta Lake est un format de stockage open source créé par Databricks et aujourd’hui géré par la Linux Foundation. Il a été conçu pour apporter fiabilité et gouvernance aux data lakes modernes, tout en restant interopérable et ouvert. Delta Lake s’appuie sur des fichiers Parquet, mais leur ajoute une couche de gestion transactionnelle et un mécanisme d’historisation. Autrement dit, il transforme un simple répertoire de fichiers en une véritable table de base de données transactionnelle stockée sur le cloud. 

Avant Delta Lake, les pipelines de données “classiques” écrivaient directement dans des fichiers Parquet. Voici le problème :

  • si un job échoue, les données peuvent être partiellement écrites ;

  • il n’y a pas de contrôle de version ou de rollback possible ;

  • et les utilisateurs ne savent jamais si la lecture d’un fichier reflète un état complet et cohérent.

Delta Lake résout cela grâce à :

  • des transactions ACID (comme dans une base de données relationnelle) ;

  • un journal de logs (_delta_log) qui enregistre chaque modification ;

  • une compatibilité ascendante avec Parquet (les données restent lisibles par d’autres outils) ;

  • et un support multi-langages : Spark, Python, Rust, Scala, Java, Presto, Trino…

Le fonctionnement interne : le Transaction Log

Delta Lake enregistre toutes les opérations dans un dossier spécial nommé _delta_log.

Chaque opération (ajout, suppression, modification, changement de schéma) génère un fichier JSON contenant la description des fichiers affectés, des métadonnées, et de la nouvelle version de la table.

Chaque fichier JSON représente un commit avec les actions effectuées sur les données.

/data/customers/

├── part-0000.parquet

├── part-0001.parquet

└── _delta_log/

    ├── 00000000000000000000.json

    ├── 00000000000000000001.json

Grâce à ce mécanisme :

  • les opérations sont atomiques ;

  • les tables sont versionnées ;

  • l’intégrité est garantie même en cas de panne.

C’est ce qui permet à Delta Lake d’offrir un comportement de base de données ACID tout en conservant la scalabilité du stockage objet (S3, ADLS, GCS...).

Installez et expérimentez avec Delta Lake

Delta Lake est simple à prendre en main : une fois installé, vous pouvez manipuler vos tables directement depuis Python.

Voyons comment le mettre en place, créer une table, lire son contenu et explorer la gestion des versions.

Option 1 : installation Python native

Commençons par installer la librairie deltalake, qui est l’implémentation Python du moteur Delta-RS (en Rust). Cette bibliothèque vous permet d’écrire et de lire des tables Delta de manière locale, tout en profitant des fonctionnalités clés : versioning, métadonnées, et compatibilité Parquet.

pip install deltalake pandas pyarrow

Une fois la bibliothèque installée, vous êtes prêt à créer votre première table Delta !

Créez votre première table Delta

Nous allons créer une petite table à partir d’un DataFrame pandas. Ce DataFrame représente une liste de clients fictifs, que nous allons ensuite sauvegarder au format Delta.

from pathlib import Path
import pandas as pd
from deltalake import write_deltalake
df = pd.DataFrame({
     "id": [1, 2, 3],
     "name": ["Alice", "Bob", "Charlie"]
})
base_path = Path(__file__).parent
delta_path = base_path / "delta_demo"
write_deltalake(
      str(delta_path),
      df,
      "overwrite"
)
print(f"Table Delta créée dans : {delta_path.resolve()}")

Ce code crée automatiquement un dossier  /tmp/delta_demo contenant  :

  • vos données en fichiers Parquet, 

  • et le dossier spécial  _delta_log   où sont enregistrées les métadonnées et versions.

Terminal affichant le contenu d’un dossier Delta Lake : un dossier _delta_log contenant un fichier JSON de log nommé 00000000000000000000.json et un fichier parquet compressé.
Votre dossier en fichiers Parquet et le dossier _delta_log sont créés

Lisez et versionnez vos données

 Maintenant que votre table est créée, vous pouvez la lire et la manipuler. Voyons comment l’ouvrir, ajouter des lignes, et vérifier la version courante de la table. 

# Lecture simple
table = DeltaTable(str(delta_path))
print(table.to_pandas())
# Ajout de nouvelles données
df2 = pd.DataFrame({"id": [4], "name": ["Diana"]})
write_deltalake(
      str(delta_path),
      df2,
      mode="append"
)
print(f"Table Delta updated.")
# Relecture de la table pour vérifier l'insertion
table = DeltaTable(str(delta_path))
print(table.to_pandas())
# Vérifiez la nouvelle version
print("Version :", table.version())

À chaque écriture, Delta Lake crée une nouvelle version de la table dans le  dossier _delta_log  .

Cela permet d’assurer une traçabilité complète de toutes les opérations.

 

Terminal montrant l'exécution d’un script Python qui met à jour une table Delta avec un nouvel enregistrement. Deux fichiers JSON de log apparaissent ensuite dans le dossier delta log
Delta Lake crée une nouvelle version de la table dans le dossier _delta_log

Time travel : remontez dans le temps

Vous pouvez revenir à n’importe quelle version précédente grâce à la fonctionnalité de time travel.

C’est particulièrement utile pour restaurer une table, comparer deux états ou auditer les modifications passées.

# Lecture simple
old_table = DeltaTable(str(delta_path), version=0)
print(old_table.to_pandas())

 

Terminal affichant le résultat d’un script Python lisant une table Delta contenant trois lignes avec les noms Alice, Bob et Charlie associés aux identifiants 1, 2 et 3.
La première version de la table 

Ici, nous lisons la première version (v0) de la table, avant l’ajout de “Diana”. Delta Lake gère automatiquement la reconstruction de cette version à partir de son journal de transactions.

pip install polars deltalake

mport polars as pl
from pathlib import Path
from deltalake import write_deltalake, DeltaTable
base_path = Path(__file__).parent
delta_path = base_path / "delta_polars"
df = pl.DataFrame({"id": [1, 2, 3], "city": ["Paris", "Lyon", "Marseille"]})
# Conversion Polars -> Arrow (robuste)
arrow_table = df.to_arrow()
write_deltalake(str(delta_path),arrow_table, mode="overwrite")
table = DeltaTable(str(delta_path))
print(table.to_pyarrow_table().to_pandas().head())

Option 2 : Exécuter Delta Lake via Docker

Delta Lake propose une image Docker prête à l’emploi : Delta Lake Docker est une image auto-contenue intégrant tous les composants nécessaires pour lire et écrire avec Delta Lake : Python, Rust, PySpark, Apache Spark et Jupyter Notebooks.

docker pull deltaio/delta-docker
docker run -it -p 8888:8888 deltaio/delta-docker

Vous obtiendrez un environnement complet, idéal pour tester vos pipelines localement ou dans un atelier de formation.

Comprenez l'écosystème Apache Iceberg

Apache Iceberg est un format open source de gestion de tables conçu à l’origine par Netflix, puis adopté par la fondation Apache. Son objectif est similaire à celui de Delta Lake : apporter des garanties transactionnelles, du versioning et des métadonnées structurées sur les données d’un data lake.

Cependant, Iceberg met particulièrement l’accent sur :

  • la performance dans les environnements distribués (notamment sur S3) ;

  • la portabilité totale entre outils (Spark, Flink, Trino, Dremio, DuckDB, etc.) ;

  • et une architecture de métadonnées hiérarchisée, plus adaptée aux très grands volumes.

Comment Iceberg fonctionne-t-il ?

Iceberg organise les informations d’une table en trois niveaux de métadonnées :

  1. Les fichiers de données: Généralement au format Parquet (ou ORC), ils contiennent les lignes de données brutes.

  2. Les fichiers de manifestes: Ils listent les fichiers de données associés à un instant donné de la table.

  3. Les fichiers de métadonnées de table (metadata.json,manifest-list, snapshots…) Ils décrivent :

  • le schéma de la table,

  • les partitions,

  • les snapshots disponibles.

Chaque modification (ajout, suppression ou mise à jour) génère un nouveau snapshot, qui référence un ensemble cohérent de fichiers de données via des manifestes.

  • Delta Lake peut être vu comme un journal de bord : on suit les changements étape par étape.

  • Iceberg, lui, fonctionne comme un album photo : chaque snapshot est une photo complète et cohérente de la table à un instant donné.

Vous pouvez revenir à une ancienne “photo” sans rejouer toutes les opérations intermédiaires.

Un format ouvert et extensible

Iceberg est maintenu par la fondation Apache, ce qui garantit son indépendance vis-à-vis de tout éditeur. Il est compatible avec la plupart des moteurs de traitement distribués (Spark, Flink, Trino, Dremio, etc.), et peut s’appuyer sur différents catalogues de métadonnées :

  • Hive Metastore,

  • AWS Glue,

  • Nessie,

  • ou un catalogue REST autonome.

Cela lui permet d’être intégré dans des architectures très hétérogènes et multi-clouds.

Le rôle du catalogue Iceberg

Une table Iceberg ne peut pas exister sans catalogue.

Le catalogue est responsable de :

  • référencer les tables (par exempledefault.customers) ;

  • stocker l’emplacement des métadonnées ;

  • gérer les versions et les snapshots ;

  • permettre aux moteurs de retrouver les tables.

Dans ce chapitre, pour simplifier l’expérimentation, nous utilisons :

  • un catalogue SQL local (SQLite) pour stocker les métadonnées ;

  • un warehouse local situé dans le même dossier que le script Python.

Cela permet d’expérimenter Iceberg sans serveur externe, tout en conservant les concepts fondamentaux.

Installez et expérimentez avec Apache Iceberg

Installez le module officiel pyiceberg, qui permet d’interagir avec des tables Iceberg directement depuis Python :

pip install pyiceberg pyarrow 'pyiceberg[sql-sqlite]'

Dans ce script :

  • on crée un dossier iceberg_demo/ à côté du fichier Python (warehouse),

  • on configure un catalogue SQLite local,

  • on crée la table default.customers si elle n’existe pas (sinon on la recharge).

from pathlib import Path
import pyarrow as pa
from pyiceberg.schema import Schema
from pyiceberg.types import NestedField, LongType, StringType
from pyiceberg.catalog import load_catalog
from pyiceberg.exceptions import TableAlreadyExistsError
# --- Chemins locaux (à côté du script) ---
base_path = Path(__file__).parent
warehouse_path = base_path / "iceberg_demo"
warehouse_path.mkdir(parents=True, exist_ok=True)
# --- Schéma Iceberg (champs optionnels pour matcher PyArrow par défaut) ---
schema = Schema(
                NestedField(1, "id", LongType(), required=False),
                NestedField(2, "name", StringType(), required=False),
)
# --- Catalogue local (SQLite) + warehouse local ---
catalog = load_catalog(
                       "local",
                       {
                           "type": "sql","uri": f"sqlite:///{(base_path / 'iceberg_catalog.db').resolve()}","warehouse": warehouse_path.resolve().as_uri(),
                           
                       },
)
# Namespace (création si besoin)
try:
    catalog.create_namespace("default")
    except Exception:
    pass
identifier = "default.customers"
# Table : create-or-load
try:
            table = catalog.create_table(identifier, schema=schema)
            print("Table créée :", identifier)
            except TableAlreadyExistsError:
                table = catalog.load_table(identifier)
                print("Table déjà existante, chargée :", identifier)
print("Location :", table.location())
# --- Écriture via PyArrow ---
arrow_table = pa.table(
                        {
                            "id": [1, 2, 3] "name": ["Alice", "Bob", "Charlie"],
                        }
)
table.append(arrow_table)
print("Données ajoutées (nouveau snapshot créé)")
# --- Lecture ---
print("\nContenu de la table :")
for row in table.scan().to_arrow().to_pylist():
                print(row)
# --- Snapshots ---
print("\nSnapshots disponibles :")
for snapshot in table.snapshots():
            print(snapshot.snapshot_id, snapshot.timestamp_ms)

Vous devriez voir l’affichage suivant après exécution:

Terminal montrant la création d’une table Iceberg nommée default.customers, avec ajout de données (Alice, Bob, Charlie) et génération de deux snapshots disponibles.
Le resultat après exécution

Que se passe-t-il “sur le disque” ?

 Une fois le script exécuté, Iceberg matérialise la table dans le warehouse sous forme de dossiers et de fichiers. Tu peux visualiser une structure de ce type :

iceberg_demo/
└── default/
 └── customers/
 ├── data/
  └── 00000-*.parquet
└── metadata/
  ├── v1.metadata.json
  ├── snap-*.avro
  └── manifest-*.avro

 Comment lire cette structure ?

  • data/contient les fichiers de données (souvent Parquet). Ce sont eux qui stockent réellement les lignes.

  • metadata/contient les métadonnées Iceberg, qui décrivent la table et ses versions :

    • v1.metadata.jsondécrit la table (schéma, partitions, localisation, snapshots…),

    • snap-*.avroreprésente les snapshots (versions) successifs,

    • manifest-*.avroréférence les fichiers de données impliqués dans un snapshot donné.

À chaque écriture (append), Iceberg :

  1. écrit de nouveaux fichiers Parquet dansdata/;

  2. génère un nouveau snapshot ;

  3. met à jour les fichiers de métadonnées pour pointer vers cette nouvelle version.

 

Choisissez entre Delta Lake et Iceberg

Fonctionnalité

Delta Lake

Apache Iceberg

Organisation interne

Journal de transactions (_delta_log, JSON)

Snapshots avec manifests et métadonnées (metadata.avro)

Mécanisme de versioning

Incrémental (commit par commit)

Par snapshot complet

Compatibilité moteur

Spark, Databricks, Trino, DuckDB …

Spark, Databricks,  Flink, Trino, Dremio, DuckDB …

Catalogues pris en charge

Local, Hive, REST, Databricks

Hive, Glue, Nessie, REST, Databricks

Time travel, Transactions ACID, Schéma évolutif

✅ Oui

✅ Oui

Positionnement

Databricks / Linux Foundation

Fondation Apache

Delta Lake vs Iceberg : la “guerre des formats” touche à sa fin

Pendant plusieurs années, le monde de la donnée a été marqué par une compétition entre ces deux formats. Chacun cherchait à devenir le standard du Lakehouse, au même titre qu’Apache Parquet l’est devenu pour le stockage colonne. Mais aujourd’hui, cette opposition s’estompe :

  • Les deux formats convergent vers des spécifications communes et des interfaces unifiées.

  • Databricks et les contributeurs d’Iceberg ont lancé Uniform, une initiative d’interopérabilité entre les formats de tables ouvertes.

  • Et surtout, Databricks a acquis Tabular — la société fondée par les créateurs d’Apache Iceberg — en 2024.

Cette acquisition a marqué un tournant : elle a rapproché les deux projets et aligné leurs roadmaps techniques. En pratique :

  • Les moteurs analytiques modernes (Trino, Flink, Dremio, Snowflake, Databricks…) savent désormais lire à la fois Delta et Iceberg.

  • Delta Lake 3.0 a introduit le Universal Format (UniForm), rendant les tables Delta compatibles avec les lecteurs Iceberg et Hudi.

  • Ainsi, la “guerre des formats” se transforme en standardisation ouverte au bénéfice des utilisateurs.

 

Après cette exploration des formats ouverts, GreenFarm a tranché. L’équipe data, déjà équipée de Databricks pour ses traitements analytiques et la gouvernance des données, a décidé d’adopter Delta Lake comme format unique au sein de son architecture Lakehouse. Cette décision s’appuie sur la maturité de Delta, son intégration native à Spark et les garanties de performance et de fiabilité offertes par l’écosystème Databricks.

À vous de jouer !

Contexte 

Votre mission est de testez Delta Lake et Iceberg sur un vrai jeu de données ! Vous allez manipuler deux open table formats — Delta Lake et Apache Iceberg — à partir d’un petit jeu de données clients.

Consigne 

  1. Créer une table Delta Lake locale à partir de clients.csv avec la librairie deltalake.

  2. Ajouter deux nouveaux clients dans cette table, puis vérifier le numéro de version.

  3. Utiliser la fonction time travel pour relire la table d’origine (version 0).

  4. Créer une table Iceberg équivalente avec pyiceberg, en ajoutant le même jeu de données.

  5. Lister les snapshots pour comprendre comment Iceberg gère ses versions.

En résumé

  • Ces formats garantissent des transactions ACID, un time travel complet et un schéma évolutif.

  • Delta Lake repose sur un journal de transactions incrémental (_delta_log), parfaitement intégré à Databricks et Spark.

  • Apache Iceberg gère ses versions via des snapshots complets et se distingue par sa compatibilité avec de nombreux moteurs.

  • La “guerre des formats” s’estompe : Delta et Iceberg convergent vers un standard interopérable grâce à Uniform et à l’acquisition de Tabular par Databricks.

  • Cette évolution consacre l’idée d’un écosystème unifié et ouvert pour les données analytiques et le machine learning.

Dans le prochain chapitre, vous découvrirez le fonctionnement interne de Delta Lake : comment il enregistre les transactions, gère ses versions et optimise les tables à grande échelle.

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best