Travailler avec des Data Lakehouses en Python, sans Spark

Romain Clement

PyConFR Lyon 2025
1er novembre 2025

Travailler avec des Data Lakehouses en Python, sans Spark

💡 Qu'est-ce qu'un Data Lakehouse ?

Évolution du Data Lakehouse

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

💡 Qu'est-ce qu'un Data Lakehouse ?

Pont entre Data Lakes et Data Warehouses

✅ FlexibilitĂ© des Data Lakes
✅ Gouvernance des Data Warehouses
✅ SĂ©paration du stockage et calcul
✅ Open Table Formats : Delta, Iceberg, Hudi, DuckLake

Popularisé par Databricks & Snowflake

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

⚙ FonctionnalitĂ©s Data Lakehouse

Performance & Coût

  • Stockage et calcul scalables
  • Dimensionnement indĂ©pendant

Fiabilité des données

  • Transactions ACID
  • Application et Ă©volution de schĂ©ma

Flexibilité opérationnelle

  • Time-travel
  • Snapshots / branching
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—‚ïž Exemple de format de donnĂ©es (Delta)

table_name
|-- _delta_log
|   |-- 00000000000000000000.json
|   |-- 00000000000000000001.json
|   |-- 00000000000000000002.json
|-- partition=1
    |-- part-00001-1a31a393-6db6-4d1a-bf4e-81ea061ff8cd-c000.snappy.parquet
|-- partition=2
    |-- part-00001-5af77102-9207-4c89-aaf6-37e1f815ec26-c000.snappy.parquet
    |-- part-00001-b11bab55-43d0-4d05-ae88-5b9481ae57db-c000.snappy.parquet

Stockage = Fichiers Parquet + Journal transactionnel

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ”„ Pourquoi (ne pas utiliser) Spark ?

Conçu pour les traitements de données massives (>= 1 To)

Complexité d'infrastructure de cluster de calcul

Gestion de JVM

Développement local complexe

Qu'en est-il des données à petite/moyenne échelle ?

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

🐍 DĂ©marrer en Python

Format Librairie native Polars DuckDB
Delta deltalake ✅ ⚠
Iceberg pyiceberg ✅ ⚠
Hudi hudi - -
DuckLake - - ✅

Note : état actuel en octobre 2025

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Exemple Delta avec deltalake

Démonstration pratique

✅ CrĂ©er des tables & Ă©crire des donnĂ©es
✅ OpĂ©rations de fusion
✅ Historique et time-travel
✅ Python pur, sans clusters

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Créer une table

>>> from deltalake import DeltaTable, Field, Schema
>>>
>>> weather_table_uri = ".datasets/weather"
>>> table = DeltaTable.create(
        weather_table_uri,
        storage_options=None,
        schema=Schema(
            [
                Field("time", "timestamp"),
                Field("city", "string"),
                Field("temperature", "float"),
            ]
        ),
        name="Weather",
        description="Forecast weather data",
    )
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Créer une table

.datasets/weather
└── _delta_log
    └── 00000000000000000000.json

Répertoire de table avec journal transactionnel initial

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Inspecter les métadonnées de la table

>>> str(table.metadata())
Metadata(
  id: '830c7cf1-f8f8-4c59-b3f7-369d93d914ca',
  name: Weather,
  description: 'Forecast weather data',
  partition_columns: [],
  created_time: 1758725496285,
  configuration: {}
)
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Inspecter le schéma de la table

>>> table.schema().to_arrow()
arro3.core.Schema
------------
time: Timestamp(Microsecond, Some("UTC"))
city: Utf8
temperature: Float32
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Écrire dans une table

Ajoutons d'abord des données :

>>> import pandas as pd
>>> from deltalake import write_deltalake
>>>
>>> weather_df_1 = pd.DataFrame(
  [
    {"time": "2025-09-30T12:00:00Z", "city": "Paris", "temperature": 10.0},
    {"time": "2025-09-30T13:00:00Z", "city": "Paris", "temperature": 11.0},
    {"time": "2025-09-30T14:00:00Z", "city": "Paris", "temperature": 12.0},
  ]
)
>>> write_deltalake(weather_table_uri, weather_df_1, mode="append", storage_options=None)
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Écrire dans une table

.datasets/weather
├── _delta_log
│   ├── 00000000000000000000.json
│   └── 00000000000000000001.json
└── part-00001-4f6cdffe-981b-4157-b19b-7fba04b1f7a6-c000.snappy.parquet

Nouvelle transaction et un fichier Parquet

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Écrire dans une table

Effectuons un upsert de données :

>>> weather_df_2 = pd.DataFrame(
  [
    {"time": "2025-09-30T13:00:00Z", "city": "Paris", "temperature": 12.0},
    {"time": "2025-09-30T14:00:00Z", "city": "Paris", "temperature": 13.0},
    {"time": "2025-09-30T15:00:00Z", "city": "Paris", "temperature": 14.0},
  ]
)
>>> table = DeltaTable(weather_table_uri, storage_options=None)
>>> (
      table.merge(
        source=weather_df_2,
        source_alias="source",
        target_alias="target",
        predicate="target.time = source.time and target.city = source.city",
      )
      .when_matched_update(updates={"temperature": "source.temperature"})
      .when_not_matched_insert(
        updates={"time": "source.time", "city": "source.city", "temperature": "source.temperature"}
      )
      .execute()
    )
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Écrire dans une table

.datasets/weather
├── _delta_log
│   ├── 00000000000000000000.json
│   ├── 00000000000000000001.json
│   └── 00000000000000000002.json
├── part-00001-4f6cdffe-981b-4157-b19b-7fba04b1f7a6-c000.snappy.parquet
├── part-00001-d7036469-24e9-4362-9871-9a3641365b29-c000.snappy.parquet
└── part-00001-f06d4ec1-4545-4844-976c-c80d31bba1dd-c000.snappy.parquet

Nouvelle transaction et deux fichiers Parquet

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark
.datasets/weather/part-00001-4f6cdffe-981b-4157-b19b-7fba04b1f7a6-c000.snappy.parquet
┌──────────────────────────┬─────────┬────────────────┐
│           time           │  city   │  temperature   │
│ timestamp with time zone │ varchar │     float      │
├──────────────────────────┌─────────┌────────────────┌
│ 2025-09-30 12:00:00+00   │ Paris   │           10.0 │
│ 2025-09-30 13:00:00+00   │ Paris   │           11.0 │
│ 2025-09-30 14:00:00+00   │ Paris   │           12.0 │
└──────────────────────────┮─────────┮────────────────┘

.datasets/weather/part-00001-d7036469-24e9-4362-9871-9a3641365b29-c000.snappy.parquet
┌──────────────────────────┬─────────┬────────────────┐
│           time           │  city   │  temperature   │
│ timestamp with time zone │ varchar │     float      │
├──────────────────────────┌─────────┌─────────────────
│ 2025-09-30 13:00:00+00   │ Paris   │           12.0 │
│ 2025-09-30 14:00:00+00   │ Paris   │           13.0 │
│ 2025-09-30 12:00:00+00   │ Paris   │           10.0 │
└──────────────────────────┮─────────┮────────────────┘

.datasets/weather/part-00001-f06d4ec1-4545-4844-976c-c80d31bba1dd-c000.snappy.parquet
┌──────────────────────────┬─────────┬────────────────┐
│           time           │  city   │  temperature   │
│ timestamp with time zone │ varchar │     float      │
├──────────────────────────┌─────────┌─────────────────
│ 2025-09-30 15:00:00+00   │ Paris   │      14.0      │
└──────────────────────────┮─────────┮────────────────┘
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Lire une table

>>> table = DeltaTable(weather_table_uri, storage_options=None)
>>> table.version()
2
>>> table.to_pandas()
                       time   city     temperature
0 2025-09-30 15:00:00+00:00  Paris            14.0
1 2025-09-30 13:00:00+00:00  Paris            12.0
2 2025-09-30 14:00:00+00:00  Paris            13.0
3 2025-09-30 12:00:00+00:00  Paris            10.0
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Récupérer l'historique de la table

Version 0 (création de la table) :

>>> table.history()
[
  {
    'timestamp': 1758720246806,
    'operation': 'CREATE TABLE',
    'operationParameters': {
      'protocol': '{"minReaderVersion":1,"minWriterVersion":2}',
      'mode': 'ErrorIfExists',
      'location': 'file:///.../.datasets/weather',
      'metadata': '{"configuration":{},"createdTime":1758720246797...}'
    },
    'engineInfo': 'delta-rs:py-1.1.0',
    'clientVersion': 'delta-rs.py-1.1.0',
    'version': 0
  }
  ...
]
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Récupérer l'historique de la table

Version 1 (ajout de données) :

>>> table.history()
[
  ...
  {
    'timestamp': 1758720703062,
    'operation': 'WRITE',
    'operationParameters': {'mode': 'Append'},
    'engineInfo': 'delta-rs:py-1.1.0',
    'clientVersion': 'delta-rs.py-1.1.0',
    'operationMetrics': {
      'execution_time_ms': 142,
      'num_added_files': 1,
      'num_added_rows': 3,
      'num_partitions': 0,
      'num_removed_files': 0
    },
    'version': 1
  }
  ...
]
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Récupérer l'historique de la table

Version 2 (fusion de données) :

>>> table.history()
[
  ...
  {
    'timestamp': 1758726633699,
    'operation': 'MERGE',
    'operationParameters': {...},
    'readVersion': 1,
    'engineInfo': 'delta-rs:py-1.1.0',
    'operationMetrics': {
      'execution_time_ms': 45,
      'num_output_rows': 4,
      'num_source_rows': 3,
      'num_target_files_added': 2,
      'num_target_files_removed': 1,
      'num_target_files_scanned': 1,
      'num_target_files_skipped_during_scan': 0,
      'num_target_rows_copied': 1,
      'num_target_rows_deleted': 0,
      'num_target_rows_inserted': 1,
      'num_target_rows_updated': 2,
      'rewrite_time_ms': 10,
      'scan_time_ms': 0
    },
    'clientVersion': 'delta-rs.py-1.1.0',
    'version': 2
  }
]
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Time-travel

>>> table.load_as_version(0)
>>> table.to_pandas()
Empty DataFrame
Columns: [time, city, temperature]
Index: []

>>> table.load_as_version(1)
>>> table.to_pandas()
                       time   city     temperature
0 2025-09-30 12:00:00+00:00  Paris            10.0
1 2025-09-30 13:00:00+00:00  Paris            11.0
2 2025-09-30 14:00:00+00:00  Paris            12.0

>>> table.load_as_version(2)
>>> table.to_pandas()
                       time   city     temperature
0 2025-09-30 15:00:00+00:00  Paris            14.0
1 2025-09-30 13:00:00+00:00  Paris            12.0
2 2025-09-30 14:00:00+00:00  Paris            13.0
3 2025-09-30 12:00:00+00:00  Paris            10.0
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Exemple Delta avec duckdb

✅ Scanner une table Delta
✅ InteropĂ©rabilitĂ© avec deltalake

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Scanner une table Delta

$ from delta_scan('.datasets/weather');
┌──────────────────────────┬─────────┬────────────────┐
│           time           │  city   │  temperature   │
│ timestamp with time zone │ varchar │     float      │
├──────────────────────────┌─────────┌─────────────────
│ 2025-09-30 15:00:00+00   │ Paris   │           14.0 │
│ 2025-09-30 13:00:00+00   │ Paris   │           12.0 │
│ 2025-09-30 14:00:00+00   │ Paris   │           13.0 │
│ 2025-09-30 12:00:00+00   │ Paris   │           10.0 │
└──────────────────────────┮─────────┮────────────────┘
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Interopérabilité avec deltalake

>>> import duckdb
>>>
>>> weather_ds = table.to_pyarrow_dataset()
>>> conn = duckdb.connect()
>>> conn.register("weather", weather_ds)
>>> conn.execute("select * from weather").df()
                       time   city     temperature
0 2025-09-30 15:00:00+00:00  Paris            14.0
1 2025-09-30 13:00:00+00:00  Paris            12.0
2 2025-09-30 14:00:00+00:00  Paris            13.0
3 2025-09-30 12:00:00+00:00  Paris            10.0
Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—Œ PrĂ©sentation de laketower

Application Python utilitaire local-first (CLI + Web)

Gestion simple des tables lakehouse

Licence OSS Apache-2

Pour commencer :

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—Œ PrĂ©sentation de laketower

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—Œ PrĂ©sentation de laketower

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—Œ PrĂ©sentation de laketower

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—Œ PrĂ©sentation de laketower

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

đŸ—Œ PrĂ©sentation de laketower

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

🚀 À retenir

Commencez simple, montez en puissance quand nécessaire

✅ BĂ©nĂ©fices du lakehouse sans la complexitĂ© Spark
✅ Écosystùme Python riche et disponible aujourd'hui
✅ PrĂȘt pour la production pour les charges petites et moyennes

Prochaines étapes : Choisissez un format, choisissez une librairie, construisez quelque chose !

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

Romain CLEMENT

Consultant indepedent, Datalpia

Co-organisateur Meetup Python Grenoble

🌐 datalpia.com
🌐 romain-clement.net
🔗 linkedin.com/in/romainclement

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

🙋 Questions ?

Merci ! Discutons !

Romain Clement - PyConFR Lyon 2025
Travailler avec des Data Lakehouses en Python, sans Spark

📚 References

Romain Clement - PyConFR Lyon 2025

Avez-vous déjà démarré un cluster Spark juste pour mettre à jour trois lignes dans une table Delta ? Bonjour à tous, je suis Romain. Pour les 30 prochaines minutes, nous allons plonger dans les workflows Data Lakehouse avec du Python uniquement, sans Spark. Avant de démarrer, qui est familier avec le concept de Data Lakehouse ?

Voici un diagramme rĂ©capitulatif par Databricks prĂ©sentant l'Ă©volution dans le temps de l'architecture d'analytique de donnĂ©es : - depuis les data warehouses des annĂ©es 80, - jusqu'Ă  l'Ă©mergence des data lakes dans les annĂ©es 2010 avec les cas d'usage de machine learning en tĂȘte (besoin d'accĂšs au niveau des fichiers), - jusqu'Ă  l'unification du data lakehouse dans l'Ăšre 2020.

Alors, qu'est-ce qu'un Data Lakehouse exactement, et dans quel cadre cela est utile ? Avez-vous dĂ©jĂ  eu du mal avec des lacs de donnĂ©es qui deviennent des marĂ©cages ? Le concept de lakehouse comble ce fossĂ© entre Data Lakes et Data Warehouses en : - Conservant la flexibilitĂ© des data lakes - Apportant les garanties de cohĂ©rence des data warehouses - DĂ©couplant le stockage et le calcul pour l'optimisation des coĂ»ts, avec notamment du stockage distribuĂ© dans le cloud comme S3 ou ADLS Les formats de data lakehouse sont tous des formats de tables dits ouverts : on les dĂ©nomment "Open Table Formats". Vous avez probablement entendu parler de Delta Lake de Databricks, Iceberg de Netflix, Hudi d'Uber ou mĂȘme le dernier en date, DuckLake de DuckDB.

Alors, qu'obtenez-vous réellement avec un lakehouse ? Laissez-moi mettre en avant les fonctionnalités clés qui résolvent ces problÚmes de marécages de données en combinant le meilleur des deux mondes : data lakes et data warehouses. PremiÚrement, vous obtenez les avantages de performance et de coût : des ressources de stockage et calcul que vous pouvez dimensionner indépendamment, plus besoin de payer pour des clusters de calcul inactifs. DeuxiÚmement, vous obtenez la fiabilité des données : grùce aux transactions ACID les données ne sont plus corrompues lors des jobs échoués, et grùce à l'application de schéma pré-défini vos données restent cohérentes. Et enfin, vous obtenez la flexibilité opérationnelle : le time-travel pour le débogage et l'audit, les snapshots pour l'expérimentation. Des fonctionnalités qui facilitent grandement votre vie en tant que data engineer ou data scientist. Ce ne sont pas que des mots à la mode : ce sont des solutions pratiques à de vrais problÚmes auxquels nous sommes confrontés réguliÚrement.

Laissez-moi vous montrer Ă  quoi ressemble rĂ©ellement un format Data Lakehouse sous le capot : prenons Delta Lake comme exemple. Vos donnĂ©es sont stockĂ©es dans des fichiers Parquet : pensez "CSV mais en colonnes, compressĂ©, et avec des types de donnĂ©es." La magie rĂ©side dans le rĂ©pertoire _delta_log : des fichiers JSON qui tracent chaque changement. Ce journal transactionnel indique aux moteurs de requĂȘte exactement quels fichiers Parquet lire pour une version donnĂ©e. Cette simple combinaison vous donne les transactions ACID, le time-travel, et toutes ces fonctionnalitĂ©s dont nous venons d'Ă©voquer. Pas d'infrastructure complexe : juste des fichiers sur un stockage avec lesquels n'importe quel moteur de requĂȘte peut travailler.

Maintenant, voici le problĂšme : Spark est une technologie incroyable, c'est le systĂšme distribuĂ© de facto pour les traitements de donnĂ©es depuis 10 ans, mais cela a un coĂ»t. Spark est conçu pour des charges massives : nous parlons de centaines de gigaoctets, de tĂ©raoctets et au-delĂ . Mais Ă  quelle frĂ©quence traitez-vous rĂ©ellement autant de donnĂ©es ? Le plus souvent, vous gĂ©rez la configuration de cluster de calcul, le tuning de la JVM, et un dĂ©veloppement local complexe juste pour mettre Ă  jour quelques centaines de lignes. Et le pire : mĂȘme lorsque votre stockage est important, votre requĂȘte rĂ©elle ne touche peut-ĂȘtre qu'un petit sous-ensemble de ces donnĂ©es. Alors pourquoi ne pas commencer simplement ? Obtenez les avantages de stockage des formats lakehouse sans la complexitĂ© opĂ©rationnelle. Vous pourrez toujours migrer sur Spark plus tard quand vous avez rĂ©ellement un besoin de mise Ă  l'Ă©chelle.

Alors, comment dĂ©marrer concrĂštement ? L'Ă©cosystĂšme Python a explosĂ© avec le support lakehouse ces derniĂšres annĂ©es. Pour chaque format, vous avez le choix : gestion de tables bas-niveau avec des librairies comme `deltalake` et `pyiceberg`, ou opĂ©rations plus haut niveau sur des dataframe avec `polars`. Mais une autre approche Ă©mergente se rĂ©vĂšle tout aussi excitante : `duckdb` a un support partiel pour Delta et Iceberg, et bien sĂ»r un support complet pour DuckLake. Cependant, comme nous le verrons, vous pouvez le faire fonctionner avec n'importe quel format de table avec une astuce simple. Des performances simple-noeud qui rivalisent avec les systĂšmes distribuĂ©s, et il peut lire tous les formats lakehouse majeurs. Nous nous concentrerons sur Delta Lake aujourd'hui car c'est le plus facile pour dĂ©marrer, mais tout ce que je vous montre peut ĂȘtre adaptĂ© aux autres formats. Le point clĂ© ici ? En 2025, il n'y a aucune raison pour que Spark soit votre choix par dĂ©faut pour les traitements de donnĂ©es Ă  base de lakehouse en Python.

Passons maintenant à la pratique avec un exemple simple utilisant des données météo. Nous allons parcourir les bases : créer des tables, écrire des données, effectuer des fusions, et explorer les fonctionnalités de time-travel de Delta. Tout s'exécute localement avec juste Python - aucune configuration de cluster nécessaire.

Commençons simplement : créer une table Delta consiste juste à définir un schéma et pointer vers un répertoire. Remarquez que nous utilisons des types de données appropriés : timestamp pour les données de temps, string pour les données catégorielles, et float pour les données quantitatives (mesures). La librairie deltalake gÚre tous les détails du protocole Delta Lake pour nous.

Voici ce qui est créé : juste un répertoire avec un dossier _delta_log contenant le journal transactionnel. Ce premier fichier JSON contient les données transactionnelles de la version initiale de la table, traçant l'historique de notre table. Aucun fichier de données pour l'instant puisque nous n'avons encore rien écrit.

Chaque table Delta possÚde des métadonnées associées. Remarquez l'ID unique autogénéré et l'horodatage de création. Les colonnes de partition vides signifient que nous ne partitionnons pas encore nos données, ce qui convient parfaitement pour les petits jeux de données.

Le schéma de la table est compatible avec le format Arrow, ce qui nous donne une large compatibilité avec l'écosystÚme. Remarquez comment nos types Python sont mappés aux types Arrow.

Écrire des donnĂ©es dans une table est simple : crĂ©ez un DataFrame pandas (ou toute autre librairie DataFrame) et utilisez la fonction utilitaire write_deltalake. Le mode='append' garantit que nous n'Ă©crasons pas les donnĂ©es existantes. Nous pouvons Ă©galement utiliser mode='overwrite' pour remplacer tout le contenu de la table. En coulisse, cela crĂ©e des fichiers Parquet et met Ă  jour le journal transactionnel de maniĂšre atomique.

Nous voyons maintenant la puissance de Delta : une nouvelle entrée dans le journal transactionnel et un fichier Parquet contenant nos données. Chaque opération d'écriture est tracée, nous donnant une piste d'audit complÚte et permettant le time-travel.

Voici une autre fonctionnalitĂ© puissante de Delta : l'opĂ©ration de fusion (merge), permettant par exemple d'effectuer des opĂ©rations de dĂ©duplication ou d'upserts. Ici, nous mettons Ă  jour les prĂ©visions de tempĂ©rature existantes oĂč time et city correspondent, et insĂ©rons les nouvelles. Cela serait complexe avec des fichiers Parquet bruts, mais Delta le gĂšre Ă©lĂ©gamment.

AprĂšs la fusion, nous avons trois fichiers Parquet et trois entrĂ©es dans le journal transactionnel. Nous allons voir dans un instant pourquoi deux nouveaux fichiers au lieu d'un seul ont Ă©tĂ© créés. Cela peut sembler beaucoup de fichiers, mais le planificateur de requĂȘtes de Delta sait exactement quels fichiers contiennent quelles donnĂ©es pour des requĂȘtes efficaces.

Jetons un oeil aux fichiers Parquet pour comprendre ce qui s'est passé. Le premier fichier Parquet est l'insertion de données initiale avec le mode 'append'. Ensuite, l'opération de fusion a créé deux nouveaux fichiers plutÎt que de modifier l'existant : - Le premier contient les lignes mises à jour - Le second contient les lignes insérées. C'est la clé des garanties ACID de Delta. Les fichiers Parquet immuables signifient que les lecteurs concurrents ne sont jamais bloqués.

Lire une table est plutÎt simple : Delta lit automatiquement tous les fichiers Parquet pertinents et vous donne la vue la plus récente. Remarquez que nous sommes à la version 2 maintenant, et les données reflÚtent notre opération de fusion avec des températures mises à jour. L'objet DeltaTable permet de spécifier des conditions de filtrage et des noms de colonnes pour éviter de lire tous les fichiers Parquet (c'est ce qu'on appelle les optimisations de file skipping, predicate pushdown et column pruning).

Pouvoir rĂ©cupĂ©rer l'historique de la table est prĂ©cieux pour le dĂ©bogage et l'audit des changements dans le temps. Chaque opĂ©ration est tracĂ©e avec des mĂ©triques : combien de fichiers ont Ă©tĂ© impactĂ©s, temps d'exĂ©cution, lignes affectĂ©es. Ces mĂ©tadonnĂ©es opĂ©rationnelles nĂ©cessiteraient un effort d'ingĂ©nierie significatif pour ĂȘtre implĂ©mentĂ©es Ă  partir de zĂ©ro. Ceci est la version initiale de la table (version 0) avec les mĂ©tadonnĂ©es de crĂ©ation de table.

Ceci est la deuxiÚme version de la table (version 1) avec l'opération d'ajout de données.

Ceci est la troisiÚme version de la table (version 2) avec l'opération de fusion de données.

Le time-travel est l'une des fonctionnalités phares de Delta. Chargez n'importe quelle version précédente pour le débogage, la récupération de données, ou l'analyse reproductible. Comme attendu, la version 0 est vide (juste aprÚs la création de la table), la version 1 contient nos données initiales, la version 2 inclut la fusion. C'est pourquoi Delta conserve tous ces journaux transactionnels.

Maintenant que nous avons explorĂ© comment dĂ©marrer avec le package Python deltalake, passons Ă  DuckDB. DuckDB apporte la sĂ©mantique SQL Ă  vos workflows lakehouse Python. RequĂȘtes rapides grĂące au multithreading efficace, configuration simple, et support natif Delta Lake : le complĂ©ment parfait Ă  deltalake pour l'exploration et l'analyse de donnĂ©es.

C'est lĂ  que DuckDB brille : scan direct de table Delta sans aucune configuration. Pointez simplement DuckDB vers votre rĂ©pertoire de table Delta et interrogez-la comme n'importe quelle base de donnĂ©es. Remarquez que nous obtenons les mĂȘmes donnĂ©es que nous avons créées prĂ©cĂ©demment, mais maintenant nous pouvons utiliser simplement du SQL. Pas d'ETL, pas de dĂ©placement de donnĂ©es, juste de la puissance analytique pure. À noter que DuckDB a encore de nombreuses restrictions concernant les formats Lakehouse en octobre 2025 : - Seulement des opĂ©rations de lecture, pas d'Ă©criture (Iceberg vient d'arriver) - Les opĂ©rations de time-travel sont encore en dĂ©veloppement

Mais la vraie magie rĂ©side dans l'interopĂ©rabilitĂ©. Prenez votre table Delta depuis deltalake, convertissez-la en dataset PyArrow, et enregistrez-la dans DuckDB. Et vous pouvez Ă©galement faire l'inverse : effectuez des requĂȘtes complexes sur des tables Delta dans DuckDB, exportez les rĂ©sultats sous forme de structure Arrow Record Batches, et streamez les rĂ©sultats pour les Ă©crire avec la fonction write_deltalake ! De cette façon, vous pouvez effectuer des pipelines de donnĂ©es out-of-core pour des jeux de donnĂ©es plus volumineux. Maintenant vous avez le meilleur des deux mondes : les opĂ©rations ACID de Delta pour les Ă©critures, l'analytique ultra-rapide de DuckDB pour les lectures. C'est la promesse du lakehouse : un jeu de donnĂ©es, plusieurs moteurs, le tout sans la complexitĂ© de Spark.

Dernier outil Python pour les formats lakehouse : laissez-moi vous présenter un projet sur lequel je travaille depuis quelques mois, "Laketower". Je développe celui-ci pour répondre à mes propres besoins, car la plupart des applications de données haut niveau ne supportent pas les formats lakehouse. C'est une application utilitaire Python open-source sous licence Apache-2, fournissant une interface en ligne de commande et une interface web pour explorer et gérer les tables lakehouse. Elle est local-first, compatible avec les tables stockées localement et à distance. Elle ne supporte que Delta Lake pour l'instant, mais d'autres formats comme Iceberg et DuckLake viendront. La maniÚre la plus simple de commencer à l'utiliser : "uvx laketower" (vous pouvez bien sûr faire "pip install laketower")

Voici donc ce qu'il faut retenir : vous n'avez pas besoin de sur-complexifier votre stack de donnĂ©es. Commencez avec les librairies lakehouse Python pour vos charges de travail petites Ă  moyennes. Obtenez tous les bĂ©nĂ©fices : transactions ACID, time-travel, application de schĂ©ma, sans le fardeau opĂ©rationnel. L'Ă©cosystĂšme est mature, les outils sont prĂȘts, et vous pouvez commencer aujourd'hui. Et quand vous avez rĂ©ellement besoin de traitement distribuĂ© massif ? C'est Ă  ce moment que vous passez Ă  Spark. Mais commencez simple. Votre moi du futur vous remerciera de ne pas avoir lancĂ© de clusters de calcul pour mettre Ă  jour trois lignes.

Questions anticipĂ©es : "Comment se connecter aux tables Delta sur Databricks ?" - `deltalake` fournit maintenant une intĂ©gration native de l'API Unity Catalog pour obtenir l'URI de stockage objet et le jeton d'accĂšs temporaire - mais nĂ©cessite des permissions spĂ©ciales Ă  activer dans l'espace de travail Databricks concernant le "credential vending" "Quel est le seuil Ă  partir duquel je dois passer Ă  Spark ?" - Une bonne rĂšgle empirique serait 100Go sur un seul noeud - Certaines Ă©tudes sur internet montrent que DuckDB et Polars peuvent encore gĂ©rer cette plage sur une machine puissante - Mais si les donnĂ©es croissent continuellement et que vous devez vraiment en traiter une partie ou la totalitĂ©, Spark pourrait ĂȘtre plus sage / plus pĂ©renne dans ce cas "Est-ce prĂȘt pour la production ?" - "Ça dĂ©pend" de vos exigences - Librairies bas niveau : oui, elles sont matures, supportent la plupart des opĂ©rations mais ne sont pas encore aussi complĂštes que leurs homologues Spark (par exemple `deltalake` ne supporte pas les "deletion vectors" en septembre 2025) - DuckDB : trĂšs bonnes performances, mais ne supporte que les opĂ©rations de lecture pour Delta (Iceberg supporte l'Ă©criture depuis octobre 2025), la fonctionnalitĂ© de time-travel est partiellement implĂ©mentĂ©e aujourd'hui "La mise Ă  jour des tables crĂ©e beaucoup de fichiers Parquet, pas efficace pour les moteurs de requĂȘte. Comment corriger ?" - Utilisez l'optimisation "data compaction" - Elle ne fera que marquer les fichiers de donnĂ©es comme "supprimĂ©s" dans le journal transactionnel mais ne les supprime pas physiquement - Pour supprimer ces fichiers "marquĂ©s pour suppression", vous avez besoin de l'opĂ©ration "data vaccuming" "Qu'en est-il de la rĂ©tention des donnĂ©es ?" - Utilisez l'opĂ©ration "data vaccuming" pour supprimer les anciens fichiers au-delĂ  d'une pĂ©riode de rĂ©tention donnĂ©e et ceux marquĂ©s pour suppression (aprĂšs une opĂ©ration d'optimisation par exemple) "Pourquoi crĂ©er beaucoup de fichiers Parquet au lieu de les mettre Ă  jour ?" - Parquet est un format de fichier immuable "Peut-on avoir des clĂ©s primaires ?" - Contraintes disponibles : NOT NULL, CHECK "Qu'en est-il du traitement out-of-core mais avec des tailles de donnĂ©es moyennes ?" - Vous pouvez lire et Ă©crire des donnĂ©es par lots avec deltalake et duckdb - Cela nĂ©cessite gĂ©nĂ©ralement d'utiliser le format PyArrow Dataset entre les deux et ça fonctionne trĂšs bien "Puis-je avoir accĂšs au flux de changements de donnĂ©es dans une table ?" - Oui, en utilisant le Change Data Feed (CDF) - Il doit ĂȘtre activĂ© Ă  la crĂ©ation de la table en utilisant "delta.enableChangeDataFeed" "Y a-t-il des benchmarks de performance comparant Spark vs Delta-rs ou DuckDB ?" - Je ne l'ai pas fait moi-mĂȘme - Mais il y a une comparaison 2025 par Miles Cole disponible : https://milescole.dev/data-engineering/2025/06/30/Spark-v-DuckDb-v-Polars-v-Daft-Revisited.html - La conclusion est : Ă  partir de 100GB Ă  traiter, Spark est toujours roi, sinon utilisez Delta-rs, Polars et/ou DuckDB pour la rĂ©duction des coĂ»ts