ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Patterns avancés MetricFlow

Patterns de métriques complexes dans MetricFlow — comparaisons période-sur-période avec offset_window, métriques filtrées avec Jinja, et gestion des lacunes dans les séries temporelles

Planté
dbtdata modelinganalytics

Les cinq types de métriques couvrent la plupart des cas d’usage, mais les métriques du monde réel nécessitent des patterns qui vont au-delà de la sélection de type de base. Les comparaisons période-sur-période, les métriques de segment filtrées et la gestion des lacunes dans les séries temporelles sont les trois patterns qui reviennent régulièrement une fois que l’on dépasse les agrégations simples.

Comparaisons période-sur-période

Le paramètre offset_window sur les métriques dérivées décale une métrique dans le temps. C’est la base des taux de croissance, des analyses d’écarts et de tout calcul « comparé à la période précédente ».

Le pattern de base compare une métrique à sa valeur à un point précédent :

metrics:
- name: bookings_vs_last_week
label: "Bookings Change vs Last Week"
type: derived
type_params:
expr: bookings - bookings_7_days_ago
metrics:
- name: bookings
- name: bookings
offset_window: 7 days
alias: bookings_7_days_ago

La même métrique (bookings) apparaît deux fois dans la liste metrics — une fois au moment actuel, une fois décalée de 7 jours. L’alias est requis car MetricFlow a besoin d’un moyen de les distinguer dans l’expression.

Pour un changement en pourcentage, encapsulez le dénominateur dans NULLIF pour gérer le cas de démarrage à froid où la période précédente n’avait pas de données :

metrics:
- name: bookings_growth_wow
label: "Bookings Growth % W/W"
type: derived
type_params:
expr: (bookings - bookings_7_days_ago) / NULLIF(bookings_7_days_ago, 0) * 100
metrics:
- name: bookings
- name: bookings
offset_window: 7 days
alias: bookings_7_days_ago

Sans NULLIF, une période précédente à zéro bookings produit une erreur de division par zéro. NULLIF convertit zéro en null, et la division par null retourne null — ce qui est la bonne réponse. « Le taux de croissance est indéfini quand la période précédente n’avait pas d’activité » est plus exact que « le taux de croissance est infini ».

Fenêtres de décalage courantes

PériodeDécalageCas d’usage
Semaine-sur-semaine7 daysMétriques opérationnelles avec cycles hebdomadaires
Mois-sur-mois1 monthRevenus, croissance, KPIs métier
Trimestre-sur-trimestre3 monthsReporting exécutif
Année-sur-année1 yearEntreprises saisonnières, comparaisons annuelles

On peut composer plusieurs décalages dans une seule métrique dérivée pour l’analyse de tendances :

metrics:
- name: revenue_trend
label: "Revenue Current vs 1W vs 4W"
type: derived
type_params:
expr: >
revenue - revenue_1w AS delta_1w,
revenue - revenue_4w AS delta_4w
metrics:
- name: revenue
- name: revenue
offset_window: 7 days
alias: revenue_1w
- name: revenue
offset_window: 28 days
alias: revenue_4w

Métriques filtrées

Les filtres utilisent le templating Jinja pour référencer les dimensions via leur chemin d’entité. C’est la syntaxe de MetricFlow pour dire « applique cette clause WHERE en utilisant le graphe sémantique ».

Filtres de dimension

metrics:
- name: enterprise_revenue
type: simple
type_params:
measure: revenue
filter:
- "{{ Dimension('customer__segment') }} = 'enterprise'"

La fonction Dimension() se résout à la colonne et la table correctes en se basant sur les relations d’entités du modèle sémantique. On n’écrit pas des noms de colonnes bruts — MetricFlow gère le chemin de jointure du modèle sémantique de la métrique jusqu’à la source de la dimension.

C’est l’approche préférable à l’encodage des filtres dans les mesures. Une mesure générale revenue combinée avec des filtres au niveau de la métrique produit enterprise_revenue, smb_revenue, startup_revenue, et n’importe quel autre segment sans avoir à définir de nouvelles mesures.

Filtres de dimension temporelle

Pour le filtrage basé sur le temps avec une granularité spécifique :

filter:
- "{{ TimeDimension('order__ordered_at', 'month') }} >= '2024-01-01'"

Le second argument de TimeDimension() spécifie la granularité. C’est important car la troncature de date affecte les lignes correspondantes. Filtrer au grain day versus month produit des résultats différents quand la valeur du filtre est à la limite d’un mois.

Filtres sur les métriques ratio

Les filtres sur les métriques ratio peuvent cibler le numérateur, le dénominateur, ou les deux indépendamment :

metrics:
- name: mobile_conversion_rate
label: "Mobile Conversion Rate"
type: ratio
type_params:
numerator:
name: conversions
filter:
- "{{ Dimension('session__device_type') }} = 'mobile'"
denominator: sessions

Ceci calcule « conversions mobile divisées par toutes les sessions ». Si l’on veut « conversions mobile divisées par sessions mobile », il faut appliquer le filtre aux deux :

type_params:
numerator:
name: conversions
filter:
- "{{ Dimension('session__device_type') }} = 'mobile'"
denominator:
name: sessions
filter:
- "{{ Dimension('session__device_type') }} = 'mobile'"

La distinction importe. « Taux de conversion mobile sur tout le trafic » et « taux de conversion mobile sur le trafic mobile » sont des métriques différentes avec des significations métier différentes. Le placement du filtre rend cela explicite.

Gestion des nulls dans les séries temporelles

Les métriques sans données pour une période de temps retournent null par défaut. Dans un rapport de revenus quotidien, un jour sans ventes retourne null, pas zéro. Cela crée des lacunes dans les graphiques et perturbe les consommateurs en aval qui interprètent null comme « données manquantes » plutôt que « rien ne s’est passé ».

Deux paramètres corrigent cela :

type_params:
measure:
name: revenue
fill_nulls_with: 0
join_to_timespine: true

join_to_timespine: true garantit que chaque date dans la plage de temps apparaît dans les résultats, même les dates sans données sous-jacentes. MetricFlow maintient une table de colonne vertébrale temporelle (une séquence de dates continue) et fait une jointure gauche sur vos résultats de métrique.

fill_nulls_with: 0 remplace les valeurs null par des zéros après la jointure avec la colonne vertébrale. Ensemble, ils produisent des séries temporelles complètes sans lacunes.

Quand utiliser chaque paramètre :

  • Les deux ensemble pour les métriques opérationnelles où zéro est significatif (revenu quotidien, nombre de commandes, pages vues). Un jour sans commandes est un vrai point de données, pas des données manquantes.
  • join_to_timespine uniquement (sans fill) pour les métriques où null et zéro sont différents. Un capteur qui ne rapporte aucune lecture est différent d’un capteur qui rapporte zéro.
  • Aucun des deux pour les métriques basées sur des événements où on ne se soucie que des périodes avec de l’activité (performances de campagne, utilisation de fonctionnalités dans un produit pas toujours actif).

Configuration de la timespine

La table timespine doit exister dans le projet dbt. MetricFlow l’utilise comme épine dorsale pour la complétude des séries temporelles :

# Dans le projet dbt
models:
- name: metricflow_time_spine
description: "Continuous date sequence for time series gap filling"

La table est simplement une liste de dates couvrant la plage de données. MetricFlow s’attend à ce qu’elle existe et l’utilise automatiquement quand join_to_timespine est activé.

Combiner les patterns

Ces patterns se composent naturellement. Une comparaison période-sur-période d’une métrique filtrée avec le remplissage des lacunes de la timespine :

metrics:
- name: enterprise_revenue_growth_mom
label: "Enterprise Revenue Growth % M/M"
type: derived
type_params:
expr: >
(enterprise_rev - enterprise_rev_last_month)
/ NULLIF(enterprise_rev_last_month, 0) * 100
metrics:
- name: enterprise_revenue
alias: enterprise_rev
- name: enterprise_revenue
offset_window: 1 month
alias: enterprise_rev_last_month

La métrique enterprise_revenue (elle-même une métrique simple filtrée) est utilisée deux fois à différents décalages temporels. MetricFlow résout le filtre, le décalage et la dérivation dans le bon ordre. On exprime l’intention métier ; MetricFlow gère la complexité SQL.

Cette composabilité est la valeur fondamentale de définir les métriques-as-code. Chaque couche construit sur celle en dessous, et les changements se propagent automatiquement. Mettez à jour le filtre enterprise sur la métrique de base, et le calcul de croissance l’intègre sans modification.