Adrienne Vermorel

Premiers pas avec le dbt Semantic Layer et MetricFlow

Le dbt Semantic Layer permet de définir vos métriques une seule fois et de les interroger depuis n’importe quel outil, pour que toute l’organisation obtienne des chiffres cohérents. La mise en place est plus accessible qu’on ne le pense.

Ce guide couvre l’installation de MetricFlow, la configuration d’un premier semantic model, la définition de métriques et l’exécution de requêtes. À la fin, vous disposerez d’un semantic layer fonctionnel que vous pourrez enrichir au fil de vos besoins.

Comprendre l’architecture

MetricFlow est le moteur de génération SQL derrière le dbt Semantic Layer. Quand vous définissez des métriques en YAML, MetricFlow construit un semantic graph (une structure relationnelle qui cartographie les connexions entre vos tables via des entités). C’est un système de navigation qui sait comment joindre les tables sans que vous ayez à détailler chaque relation.

Quand vous interrogez une métrique, MetricFlow :

  1. Lit vos définitions YAML
  2. Détermine les jointures nécessaires
  3. Génère du SQL optimisé pour votre plateforme de données
  4. Exécute la requête et renvoie les résultats

MetricFlow gère la logique de jointure automatiquement. Vous définissez les entités (les clés de jointure) une seule fois, et il détermine comment naviguer entre les tables.

dbt Core vs dbt Cloud

Les fonctionnalités diffèrent entre les deux :

Fonctionnalitédbt Coredbt Cloud
Définir semantic models et métriquesOuiOui
Générer du SQL depuis les configsOuiOui
Requêtes via CLIcommandes mfcommandes dbt sl
Requêtes via APIs (JDBC, GraphQL)NonOui
Intégrations BINonOui
Exports pour matérialiser les métriquesNonOui

Avec dbt Core, vous bénéficiez de la définition complète des métriques et des requêtes CLI. La couche API et les intégrations BI nécessitent dbt Cloud.

Installation

Pour dbt Core, installez le bundle MetricFlow correspondant à votre adapter :

Terminal window
pip install "dbt-metricflow[dbt-snowflake]"

Remplacez dbt-snowflake par votre adapter : dbt-bigquery, dbt-databricks, dbt-redshift ou dbt-postgres.

Pour dbt Cloud, MetricFlow est intégré. Vous utiliserez les commandes dbt sl au lieu de mf.

Plateformes supportées : Snowflake, BigQuery, Databricks, Redshift, Postgres (Core uniquement) et Trino.

Configurer le time spine

Les métriques cumulatives et les calculs temporels nécessitent un time spine, une table avec une ligne par jour. MetricFlow l’utilise comme dimension temporelle fiable pour ses jointures.

Créez un modèle appelé metricflow_time_spine.sql :

{{ config(materialized='table') }}
{{ dbt.date_spine(
datepart="day",
start_date="CAST('2020-01-01' AS DATE)",
end_date="CAST('2030-12-31' AS DATE)"
) }}

Puis configurez-le dans votre dbt_project.yml :

semantic-layer:
time_spine:
standard_granularity_column: date_day

Exécutez dbt build -s metricflow_time_spine pour le matérialiser.

Définir un semantic model

Les semantic models sont des abstractions YAML qui décrivent vos modèles dbt pour MetricFlow. Chaque semantic model a une relation un-à-un avec un modèle SQL ou Python de dbt.

Ce semantic model décrit une table de commandes :

models/semantic/sem_orders.yml
semantic_models:
- name: orders
description: Order transactions with revenue and quantity
model: ref('mrt__sales__orders')
defaults:
agg_time_dimension: order__created_at
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
- name: product_id
type: foreign
dimensions:
- name: order__created_at
type: time
type_params:
time_granularity: day
- name: order__status
type: categorical
- name: order__channel
type: categorical
measures:
- name: order_total
agg: sum
expr: order__amount
description: Sum of order amounts
- name: order_count
agg: count
expr: order_id
description: Count of orders
- name: distinct_customers
agg: count_distinct
expr: customer_id

Détail des composants

Les entities sont les clés de jointure qui connectent les semantic models. Il en existe quatre types :

  • primary : un enregistrement par ligne, pas de nulls (comme order_id)
  • unique : un par ligne, nulls autorisés
  • foreign : zéro à plusieurs instances (comme customer_id dans une table de commandes)
  • natural : colonnes identifiant de manière unique les enregistrements à partir de données réelles

Les dimensions permettent le regroupement, le découpage et le filtrage. Utilisez time pour les dates et categorical pour les valeurs textuelles.

Les measures sont les agrégations numériques qui servent de briques de base aux métriques. Agrégations supportées : sum, count, count_distinct, avg, min, max, median et percentile.

Définir des métriques

Les métriques référencent les measures que vous avez définies. Ces métriques simples s’appuient sur le semantic model des commandes :

models/semantic/metrics_orders.yml
metrics:
- name: revenue
description: Total order revenue
type: simple
label: Revenue
type_params:
measure: order_total
- name: orders
description: Total number of orders
type: simple
label: Order Count
type_params:
measure: order_count
- name: unique_customers
description: Count of distinct customers
type: simple
label: Unique Customers
type_params:
measure: distinct_customers

Types de métriques selon les besoins

Les métriques simples référencent directement une measure, comme les exemples ci-dessus.

Les métriques dérivées se calculent à partir d’autres métriques. Cet exemple calcule le revenu par client :

metrics:
- name: revenue_per_customer
description: Average revenue per unique customer
type: derived
label: Revenue per Customer
type_params:
expr: revenue / unique_customers
metrics:
- name: revenue
- name: unique_customers

Les métriques ratio calculent correctement les ratios en agrégeant numérateur et dénominateur indépendamment avant la division :

metrics:
- name: average_order_value
description: Average value per order
type: ratio
label: AOV
type_params:
numerator: order_total
denominator: order_count

Les métriques cumulatives agrègent sur des fenêtres temporelles :

metrics:
- name: revenue_mtd
description: Month-to-date revenue
type: cumulative
label: Revenue MTD
type_params:
measure: order_total
grain_to_date: month

Valider votre configuration

Avant d’interroger vos métriques, validez que vos définitions sont correctement parsées :

Terminal window
# dbt Core
mf validate-configs
# dbt Cloud
dbt sl validate

En cas d’échec de la validation, vérifiez ces problèmes courants :

  • Erreur “ensure that you’ve ran an artifacts…” : exécutez dbt parse ou dbt build d’abord pour générer le semantic manifest.
  • Conflit Metafont : la commande mf peut entrer en conflit avec le package LaTeX Metafont. Désinstallez-le si vous observez un comportement inattendu.
  • Dimensions absentes : chaque dimension a besoin d’une entité primaire dans son semantic model.

Interroger les métriques

Générez d’abord le semantic manifest :

Terminal window
dbt parse

Puis interrogez vos métriques :

Terminal window
# dbt Core
mf query --metrics revenue --group-by metric_time
# dbt Cloud
dbt sl query --metrics revenue --group-by metric_time

Ajoutez des dimensions pour découper les résultats :

Terminal window
mf query --metrics revenue,orders --group-by metric_time,order__channel

Filtrez avec le flag --where :

Terminal window
mf query --metrics revenue --group-by metric_time --where "{{ Dimension('orders__order__channel') }} = 'web'"

La syntaxe de filtre utilise du templating Jinja. Référencez les dimensions avec {{ Dimension('semantic_model__dimension_name') }}.

Organiser les semantic models à grande échelle

Pour les petits projets, regroupez les définitions sémantiques avec vos modèles dbt :

models/
marts/
mrt__sales__orders.sql
mrt__sales__orders.yml # semantic model + métriques
mrt__sales__customers.sql
mrt__sales__customers.yml

Pour les projets plus importants, séparez-les dans des répertoires dédiés :

models/
marts/
mrt__sales__orders.sql
mrt__sales__customers.sql
semantic/
semantic_models/
sem_orders.yml
sem_customers.yml
metrics/
revenue_metrics.yml
customer_metrics.yml

Un exemple complet

Voici l’ensemble en pratique avec un modèle de commandes :

-- models/marts/mrt__sales__orders.sql
SELECT
order_id,
customer_id,
created_at AS order__created_at,
channel AS order__channel,
status AS order__status,
amount AS order__amount
FROM {{ ref('int__orders_enriched') }}

Définition du semantic layer :

models/semantic/sem_orders.yml
semantic_models:
- name: orders
model: ref('mrt__sales__orders')
defaults:
agg_time_dimension: order__created_at
entities:
- name: order_id
type: primary
- name: customer_id
type: foreign
dimensions:
- name: order__created_at
type: time
type_params:
time_granularity: day
- name: order__status
type: categorical
- name: order__channel
type: categorical
measures:
- name: order_total
agg: sum
expr: order__amount
- name: order_count
agg: count
expr: order_id
metrics:
- name: revenue
type: simple
type_params:
measure: order_total
- name: orders
type: simple
type_params:
measure: order_count
- name: aov
type: ratio
type_params:
numerator: order_total
denominator: order_count

Build et requête :

Terminal window
dbt build
dbt parse
mf query --metrics revenue,aov --group-by metric_time,order__channel

Et ensuite

Une fois votre semantic layer opérationnel, vous pouvez :

  • Ajouter d’autres semantic models pour les clients, produits et autres entités. MetricFlow gère automatiquement les jointures via les entités partagées.
  • Définir des métriques period-over-period avec des métriques dérivées et offset_window pour des comparaisons comme la croissance mois par mois.
  • Connecter des outils BI (dbt Cloud) via JDBC ou l’API GraphQL.
  • Exposer vos métriques aux LLMs en donnant accès à vos métriques gouvernées aux outils d’IA capables d’interroger en langage naturel des définitions cohérentes.

La vraie valeur apparaît quand plusieurs équipes interrogent les mêmes métriques et obtiennent les mêmes résultats, sans maintenir de logique dupliquée dans les dashboards et les rapports.