Brains Up AnalyticsBRAINSUPAnalytics
Delta LakePythondelta-rsDatabricksData Engineering

Delta Lake en Python pur : écrivez des tables Delta sans Spark avec le package deltalake (delta-rs)

Comment le package deltalake (delta-rs, un cœur Rust/Arrow) écrit de vraies tables Delta sans Spark ni JVM — écriture, MERGE, OPTIMIZE et time travel en Python, et où Spark garde l'avantage.

Il y a une supposition silencieuse dans beaucoup d'équipes data : « Delta Lake, c'est un truc de Spark ». Ça se comprend — Delta est né dans l'écosystème Databricks/Spark, et la majorité de la documentation suppose un cluster en marche. Mais cette supposition coûte cher quand le travail est petit. Lancer un cluster Spark pour écrire quelques centaines de milliers de lignes dans une table Delta, c'est comme louer un camion pour transporter un carton : ça marche, mais vous payez le démarrage, le coût d'infrastructure et une dépendance JVM qui n'avait pas lieu d'exister.

Le package deltalake — l'interface Python du projet delta-rs — défait cette supposition. Il implémente le protocole Delta Lake avec un cœur en Rust et Apache Arrow, et livre le tout en Python sans toucher à une JVM, à Spark ou à Java. Et la partie qui change la donne pour qui vit déjà dans le monde Databricks : la table qu'il écrit est une vraie table Delta — la même que votre workspace Databricks et Unity Catalog liront ensuite. Ce n'est pas du « presque Delta » ; c'est du vrai Delta, dans le même format de fichiers et de journal de transactions.

Cet article montre le quoi, le comment et le quand — et où se situe vraiment la frontière avec Spark.

Le problème concret

Une bonne partie des charges d'une équipe data n'est pas du big data. Ce sont des ingestions d'API, des fichiers qui arrivent toutes les heures, des exports de systèmes transactionnels, des dumps de webhook. Des volumes qui tiennent confortablement dans la mémoire d'une machine modeste. Pour ces cas, le pattern « Spark écrit en Delta » a trois problèmes :

  1. Temps de démarrage. Un cluster met de quelques secondes à quelques minutes à être prêt. Pour un job qui s'exécute en 4 secondes, la surcharge domine.
  2. Coût. Un cluster allumé, c'est de l'argent qui tourne, même inactif entre les micro-lots.
  3. Poids opérationnel. Une JVM, des versions de Spark, des dépendances de connecteur — toute une pile à maintenir juste pour pouvoir faire un append.

La bonne question n'est pas « Spark ou pas Spark pour toujours ? ». C'est : pourquoi payer Spark quand le travail ne demande pas Spark ?

La solution : deltalake (delta-rs)

delta-rs est une implémentation de Delta Lake écrite en Rust, avec des bindings Python. Étant Arrow-native, il dialogue naturellement — et souvent avec zéro copie — avec pandas, Polars, PyArrow, DuckDB, Dask et Daft. Vous lisez depuis n'importe laquelle de ces engines, écrivez en Delta, et relisez dans une autre.

Étape 1 — Installer (une ligne)

pip install deltalake

Sans JDK, sans SPARK_HOME, sans connecteur à configurer. Le binaire Rust est déjà embarqué dans le package.

Étape 2 — Écrire depuis n'importe quel DataFrame

from deltalake import write_deltalake, DeltaTable
import pandas as pd

df = pd.DataFrame({"jour": ["2026-09-10"], "magasin": [42], "ventes": [1830.0]})

# écrit (crée la table si elle n'existe pas)
write_deltalake("s3://lake/ventes", df, mode="append")

Le paramètre mode accepte append (ajoute), overwrite (remplace) et travaille avec schema_mode pour l'évolution de schéma quand de nouvelles colonnes apparaissent. Ça marche sur disque local (/data/ventes), sur S3, ADLS/Azure et GCS — il suffit de passer les identifiants via storage_options ou des variables d'environnement.

Remplacer pandas par Polars est direct — Polars a même df.write_delta(...) par-dessus le même moteur :

import polars as pl
pl.read_parquet("brut/*.parquet").write_delta("s3://lake/ventes", mode="append")

Étape 3 — Lire, entretenir et remonter le temps

dt = DeltaTable("s3://lake/ventes")

# compacte les petits fichiers et co-localise les données liées
dt.optimize.compact()
dt.optimize.z_order(["jour"])

# lit vers l'engine de votre choix
df = dt.to_pandas()                 # pandas
ds = dt.to_pyarrow_dataset()        # Arrow / DuckDB / Polars lazy

# time travel : la table telle qu'elle était à la version 0
v0 = DeltaTable("s3://lake/ventes", version=0)

Voici la valeur que vous n'avez pas à construire à la main :

  • Commits ACID. Chaque écriture est une transaction atomique enregistrée dans _delta_log. Pas de fichier à moitié écrit, pas de lecture sale.
  • Vérification et évolution de schéma. La table refuse les données incompatibles ; et vous autorisez explicitement de nouvelles colonnes quand vous le voulez.
  • Time travel. Chaque commit devient une version interrogeable — audit, retraitement et débogage deviennent triviaux.
  • Maintenance du layout. optimize.compact() résout le problème des « petits fichiers » ; z_order([...]) améliore le data skipping sur les filtres multi-colonnes.

Bonus — Upsert (MERGE) et CDC léger

Besoin d'un chargement incrémental qui met à jour les enregistrements existants ? delta-rs expose merge :

(
    dt.merge(
        source=nouveau_df,
        predicate="cible.id = source.id",
        source_alias="source",
        target_alias="cible",
    )
    .when_matched_update_all()
    .when_not_matched_insert_all()
    .execute()
)

C'est du CDC (Change Data Capture) sans monter un pipeline Spark Structured Streaming pour un volume qui n'en a pas besoin.

Où ça brille — et où Spark garde l'avantage

Adopter delta-rs, ce n'est pas abandonner Spark. C'est choisir l'outil selon la charge.

Utilisez delta-rs quand :

  • La charge tient (ou tient presque) dans la mémoire d'une machine : ingestions petites et moyennes.
  • Vous tournez dans des fonctions serverless ou de petits conteneurs, où lancer Spark est irréalisable ou cher.
  • Vous voulez des tests locaux qui écrivent un Delta identique à celui de production.
  • Vous faites le premier saut d'un prototype en pandas vers une table gouvernée, sans tout réécrire en PySpark.

Restez sur Spark quand :

  • Il y a des shuffles lourds, des jointures entre tables géantes ou des agrégations qui débordent la RAM.
  • Vous avez besoin de streaming à haut débit avec des garanties exactly-once à l'échelle.
  • Le traitement vit déjà sur un cluster Databricks et la distribution est le vrai goulot.

Une note de gouvernance : sur Databricks/Unity Catalog, les tables gérées bénéficient du predictive optimization — l'OPTIMIZE tourne tout seul — et la recommandation actuelle pour le layout est le liquid clustering plutôt que ZORDER/partitions. Autrement dit : utilisez le z_order de delta-rs là où vous gérez vous-même la maintenance ; laissez Unity Catalog s'en charger quand la table est gérée par lui.

Conclusion

Delta Lake n'est plus synonyme de Spark. Avec le package deltalake, un script Python de dix lignes écrit, lit, optimise et versionne des tables Delta — avec ACID, vérification de schéma et time travel d'origine — et livre exactement le format que le reste de votre plateforme Databricks/Azure consomme déjà. Le gain n'est pas d'échanger une technologie contre une autre : c'est d'arrêter de payer un cluster quand le travail ne demande pas de cluster, et de raccourcir la distance entre un prototype et une table de production gouvernée.

Si vous gardez de petites ingestions qui tournent sur Spark aujourd'hui, ça vaut la peine de mesurer : combien de temps et de coût disparaissent quand write_deltalake prend le relais ?

Articles liés

Vous avez aimé ? Découvrez les e-books pour du contenu approfondi.

E-books