Créer une custom materialization dans dbt : guide complet avec exemple
Dans dbt, les materializations déterminent comment un modèle est transformé en objet physique dans le data warehouse (par exemple une table ou une vue). Par défaut, dbt fournit plusieurs materializations comme view
, table
, incremental
ou ephemeral
. Mais dans certains cas avancés, il est utile de définir une materialization personnalisée (custom materialization) afin d’adapter le comportement à des besoins spécifiques.
Cet article vous explique comment créer une custom materialization avec un exemple complet.
🔍 Pourquoi créer une custom materialization ?
Voici quelques cas d’usage :
- Gérer une stratégie d’insertion personnalisée (par exemple : supprimer les anciennes lignes avant d’insérer les nouvelles)
- Ajouter des hooks de logging ou d’audit
- Implémenter une logique conditionnelle (par exemple : faire un full refresh tous les lundis)
- Intégrer des spécificités d’un data warehouse
📂 Structure de base d’une custom materialization
Les materializations sont des macros déclarées dans macros/materializations/<nom>.sql
. Une materialization doit :
- Utiliser le décorateur
{% materialization nom, default %}
- Utiliser le contexte
adapter.get_relation
/adapter.drop_relation
pour interagir avec le warehouse - Retourner l’objet
rel
représentant la table créée ou modifiée
🌐 Exemple : materialization safe_overwrite
Ce comportement permet de :
- Supprimer la table cible uniquement si elle existe
- Ensuite créer une nouvelle table via une requête
1. Fichier macros/materializations/safe_overwrite.sql
{% materialization safe_overwrite, default %}
{%- set identifier = model['alias'] -%}
{%- set target_relation = api.Relation.create(
database=target.database,
schema=target.schema,
identifier=identifier) -%}
{% do log("[safe_overwrite] dropping existing table if exists", info=True) %}
{% do adapter.drop_relation(target_relation) %}
{% do log("[safe_overwrite] creating new table", info=True) %}
{% set sql = materialization_default_sql(model) %}
{% do run_query(sql) %}
{{ return({'relations': [target_relation]}) }}
{% endmaterialization %}
2. Utilisation dans un modèle
-- models/fact/fact_ventes.sql
{{ config(materialized='safe_overwrite') }}
select * from {{ ref('stg_ventes') }}
📊 Astuces et bonnes pratiques
- ✅ Tu peux utiliser
is_incremental()
si tu veux un comportement mixte initial/incrémental - ✅ Tu peux ajouter des
pre_hook
/post_hook
dans la macroconfig()
pour faire du logging, de l’audit ou de la notification - ✅ Pense à documenter les configs attendues dans la macro si tu ajoutes des options personnalisées (ex :
unique_key
,mode
, etc.)
🧰 Conclusion
Les custom materializations te permettent d’étendre dbt et de l’adapter à tes contraintes techniques et métiers. Elles offrent un haut niveau de contrôle tout en bénéficiant de l’infrastructure de compilation, d’execution et de documentation de dbt.
N’oublie pas : ce sont de simples macros Jinja, donc tu peux loger, configurer, conditionner tout ce que tu veux, de façon testable et maintenable !