ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Concepts fondamentaux de dlt

Les quatre blocs de construction des pipelines dlt — sources, ressources, pipelines et schémas — et les trois write dispositions qui contrôlent la manière dont les données atterrissent.

Planté
dltdata engineeringetl

dlt (data load tool) organise le chargement de données autour de quatre concepts : les sources, les ressources, les pipelines et les schémas. Comprendre ces quatre blocs de construction explique pourquoi un pipeline dlt peut tenir en 20 lignes de Python et gérer automatiquement la pagination, le rate limiting, l’inférence de schéma et le chargement incrémental.

Sources

Une source est un regroupement logique d’extractions de données liées. Vous en déclarez une avec le décorateur @dlt.source. La source définit une configuration que plusieurs endpoints partagent — URL de base, credentials d’authentification, headers communs. Considérez-la comme le conteneur qui détient plusieurs ressources.

@dlt.source
def my_api(api_key=dlt.secrets.value):
return [users(), orders()]

Les sources ne font pas le travail d’extraction elles-mêmes. Ce sont des objets de coordination : elles détiennent la configuration partagée et regroupent les ressources afin que vous puissiez les exécuter comme une unité.

Ressources

Les ressources sont les unités d’extraction modulaires. Chaque ressource représente une extraction de données spécifique — un endpoint, une table, un flux. Vous les déclarez avec @dlt.resource.

Le choix de conception clé dans dlt est que les ressources sont des générateurs Python. Les générateurs produisent les données de manière incrémentale plutôt que de les accumuler toutes en mémoire d’abord, ce qui signifie qu’une ressource peut traiter des millions d’enregistrements sans s’écraser sur les limites mémoire :

@dlt.resource(write_disposition="merge", primary_key="id")
def users():
for page in paginate_api("/users"):
yield page

Les ressources sont composables. Elles peuvent être exécutées seules ou regroupées dans une source. Elles portent leur propre configuration — write disposition, clé primaire, indices de schéma — de sorte que le comportement est autonome et ne dépend pas de la façon dont elles sont invoquées.

Pipelines

Un pipeline exécute le travail. Vous en créez un avec dlt.pipeline(), en nommant la destination et le dataset :

pipeline = dlt.pipeline(
pipeline_name="my_pipeline",
destination="bigquery",
dataset_name="raw_data"
)

Le pipeline gère le cycle complet d’extraction-normalisation-chargement. Il extrait depuis vos ressources, normalise les structures imbriquées en tables relationnelles et charge dans la destination. Entre les exécutions, il suit l’état pour que le chargement incrémental sache où reprendre.

Exécuter un pipeline est un seul appel :

load_info = pipeline.run(users())

L’objet load_info contient des détails sur ce qui a été chargé — nombres de lignes, changements de schéma, timing. C’est votre principal indicateur de ce qui s’est passé.

Schémas

dlt infère les schémas automatiquement à partir de vos données. Il détecte les types, normalise le JSON imbriqué en tables relationnelles et gère l’évolution du schéma sans intervention manuelle. Quand votre source ajoute un nouveau champ, dlt déclenche une migration automatique de table. Vous n’écrivez pas d’instructions ALTER TABLE.

L’inférence de schéma est la plus grande différence de flux de travail par rapport à l’écriture de code de pipeline brut. Au lieu de maintenir les mappings de colonnes au fur et à mesure que votre source évolue, vous laissez dlt les découvrir et les mettre à jour. Pour les APIs sources qui changent fréquemment — ce qui représente presque toutes — cela élimine une grande catégorie de maintenance.

Pour les pipelines de production où vous souhaitez imposer plutôt qu’accepter les changements, les contrats de schéma vous permettent de définir des règles explicites :

@dlt.resource(schema_contract={"columns": "freeze"})
def orders():
yield from get_orders()

Les modes de contrat peuvent être freeze (rejeter les changements inattendus), evolve (accepter tout changement) ou disallow (rejeter les nouvelles colonnes tout en autorisant les changements de type). La plupart des pipelines de production utilisent evolve pendant le développement et resserrent sur freeze une fois le schéma stabilisé.

Write dispositions

Les write dispositions contrôlent comment les données atterrissent dans la table de destination. Il y en a trois :

Replace supprime et recrée la table à chaque exécution. Simple et correct, mais coûteux à grande échelle. Adapté aux petites tables de référence ou quand vous avez besoin d’une table vierge.

Append ajoute de nouveaux enregistrements aux données existantes sans toucher ce qui est déjà là. Le bon choix pour les flux d’événements immuables où les enregistrements ne se mettent jamais à jour.

Merge fait un upsert en utilisant une clé primaire ou une clé de fusion. Les lignes correspondantes se mettent à jour ; les nouvelles lignes s’insèrent. C’est ce que vous voulez pour les entités mutables — utilisateurs, commandes, comptes — où les enregistrements changent au fil du temps :

@dlt.resource(write_disposition="merge", primary_key="id")
def orders():
yield from get_orders()

Le choix de write disposition a des implications significatives sur les performances et les coûts. Merge nécessite de comparer les lignes entrantes avec les données existantes ; sur les grandes tables, cela devient coûteux. Voir Chargement incrémental dlt pour la façon dont les write dispositions interagissent avec l’état de chargement incrémental.

Pourquoi l’ensemble s’emboîte

Les quatre concepts sont conçus pour se composer. Une source regroupe des ressources. Les ressources produisent des données de manière incrémentale. Le pipeline les exécute, infère les schémas et charge avec la write disposition spécifiée. Vous écrivez des fonctions Python — pas du YAML, pas un DSL propriétaire, pas un connecteur configuré via une interface graphique. Le pipeline est versionné, testable et s’exécute partout où Python s’exécute.

Un pipeline de base complet ciblant BigQuery pourrait faire 20 à 30 lignes :

import dlt
@dlt.resource(write_disposition="merge", primary_key="id")
def users():
for page in paginate_api("/users"):
yield page
pipeline = dlt.pipeline(
pipeline_name="user_sync",
destination="bigquery",
dataset_name="raw"
)
load_info = pipeline.run(users())
print(load_info)

Cela gère la pagination via le pattern générateur, l’inférence de schéma, la création de table BigQuery et le comportement d’upsert — sans aucune configuration de framework supplémentaire.

Pour plus de détails sur la façon dont dlt gère l’état entre les exécutions et récupère uniquement les nouvelles données, voir Chargement incrémental dlt. Pour les stratégies de chargement spécifiques à BigQuery et les optimisations, voir dlt et intégration BigQuery.