ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Validation sémantique dans dbt

Comment encoder les règles métier sous forme de tests dbt — validation de patterns regex, logique multi-colonnes, validation IA en langage naturel, et quand chaque approche convient.

Planté
dbtelementarydata qualitytesting

Les tests structurels vérifient que vos données ont la bonne forme — les clés primaires sont uniques, les clés étrangères référencent des parents valides, les champs obligatoires ne sont pas nuls. La détection d’anomalies capture les déviations statistiques par rapport aux patterns historiques. Mais entre ces deux couches existe un écart : les règles métier qui sont spécifiques au domaine, déterministes et invisibles à la fois pour les vérifications structurelles et les méthodes statistiques.

Une colonne status qui contient "active" alors que l’activité attend "Active" passe tous les tests structurels. Une colonne email remplie de "test@test.com" passe not_null. Un contrat avec une signed_date en 2087 passe tous les vérifications de type. Ce sont des violations sémantiques — les données sont structurellement valides mais significativement incorrectes.

Validation de patterns regex

La validation sémantique la plus courante encode les contraintes de format sous forme d’expressions régulières. dbt-expectations fournit expect_column_values_to_match_regex à cet effet.

columns:
- name: customer__email
data_tests:
- dbt_expectations.expect_column_values_to_match_regex:
regex: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
row_condition: "customer__email IS NOT NULL"
- name: product__sku
data_tests:
- dbt_expectations.expect_column_values_to_match_regex:
regex: "^[A-Z]{2}-[0-9]{4}-[A-Z]{3}$"
- name: customer__phone
data_tests:
- dbt_expectations.expect_column_values_to_match_regex:
regex: "^\\+?[1-9]\\d{1,14}$"

Le paramètre row_condition est essentiel pour les colonnes nullables. Sans lui, les valeurs NULL sont testées contre le regex et échouent, ce qui produit des faux positifs si les NULL sont acceptables (le champ est optionnel) mais pas les valeurs malformées.

Les tests regex sont déterministes, rapides et faciles à comprendre. Ils fonctionnent bien pour :

  • Les formats d’e-mail où vous voulez détecter les entrées manifestement invalides comme "n/a" ou "none" sans construire un parseur RFC 5322 complet
  • Les codes produits et SKU avec des structures connues comme XX-1234-ABC
  • Les numéros de téléphone aux formats E.164 ou régionaux
  • Les codes postaux avec des patterns spécifiques au pays
  • Les codes de devise (trois lettres majuscules correspondant à l’ISO 4217)

La limitation est que le regex valide le format, pas le contenu. Un e-mail comme nobody@example.com passe le regex mais n’est pas l’adresse d’une vraie personne. Pour la validation au niveau du contenu, vous avez besoin d’outils différents.

Vérifications de plage et de distribution

Les règles métier contraignent souvent les valeurs à des plages attendues non capturées par les types de données seuls. Une colonne NUMERIC pour le revenu autorise les valeurs négatives que l’activité considère comme invalides. Une colonne FLOAT pour les taux de conversion ne devrait jamais dépasser 1,0, mais le type ne l’impose pas.

columns:
- name: order__revenue
data_tests:
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
strictly: true
- dbt_expectations.expect_column_mean_to_be_between:
min_value: 10
max_value: 10000
- name: conversion_rate
data_tests:
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
max_value: 1
- name: event__timestamp
data_tests:
- dbt_expectations.expect_column_values_to_be_between:
min_value: "2020-01-01"
max_value: "{{ dbt.dateadd('day', 1, dbt.current_timestamp()) }}"

La distinction entre les vérifications de plage au niveau ligne (expect_column_values_to_be_between) et les vérifications agrégées (expect_column_mean_to_be_between) est importante. Les vérifications au niveau ligne détectent des valeurs individuelles incorrectes. Les vérifications agrégées détectent les glissements de distribution où chaque valeur individuelle peut être valide mais le pattern global est incorrect. Une colonne de revenu où chaque valeur est entre 0 et 100 000 € peut quand même avoir un problème si la moyenne passe de 500 à 50 €.

Validation multi-colonnes

Certaines règles métier couvrent plusieurs colonnes. Une end_date doit être postérieure à start_date. Un discount_amount ne peut pas dépasser subtotal. Un shipping_status à "delivered" nécessite une delivery_date non nulle.

dbt-utils fournit expression_is_true pour des assertions SQL arbitraires :

models:
- name: mrt__sales__orders
data_tests:
- dbt_utils.expression_is_true:
expression: "end_date >= start_date"
config:
where: "end_date IS NOT NULL AND start_date IS NOT NULL"
- dbt_utils.expression_is_true:
expression: "discount_amount <= subtotal"
- dbt_utils.expression_is_true:
expression: >
(shipping_status != 'delivered')
OR (delivery_date IS NOT NULL)

Pour les assertions multi-tables complexes ou les règles qui ne s’adaptent pas bien à une seule expression SQL, les tests singuliers (fichiers SQL autonomes dans le répertoire tests/) offrent une flexibilité totale. La requête retourne les lignes qui violent la règle ; zéro ligne signifie un succès.

Validation pilotée par l’IA

Elementary a introduit des tests ai_data_validation qui utilisent des prompts en langage naturel pour exprimer les règles métier :

tests:
- elementary.ai_data_validation:
prompt: "Il ne doit y avoir aucune date de contrat dans le futur"
- elementary.ai_data_validation:
prompt: "Chaque commande avec le statut 'shipped' doit avoir un numéro de suivi"
- elementary.ai_data_validation:
prompt: "Les noms de clients ne doivent pas contenir de caractères numériques"

Le test envoie des échantillons de données à un LLM avec le prompt en langage naturel et interprète la réponse comme succès ou échec. C’est genuinement utile pour les règles métier difficiles à exprimer en SQL — des règles impliquant une correspondance approximative, une logique contextuelle, ou une connaissance du domaine qu’un LLM peut approximer.

Les compromis sont significatifs :

  • Non déterministe. Les mêmes données peuvent produire des résultats différents à des exécutions différentes, selon l’interprétation du LLM. Cela viole l’attente fondamentale que les tests sont déterministes.
  • Coût. Chaque exécution de test entraîne des coûts d’API LLM qui évoluent avec le volume de données et le nombre de tests.
  • Latence. Les appels LLM sont plusieurs ordres de grandeur plus lents que la validation basée sur SQL.
  • Raisonnement opaque. Quand le test échoue, vous ne pouvez pas inspecter la logique comme vous le feriez avec un regex ou une expression SQL.

La validation IA doit être traitée comme un complément aux tests déterministes, pas un remplacement. Utilisez-la pour la validation exploratoire — découvrir des règles qui devraient finalement être encodées en SQL — ou pour des vérifications genuinement approximatives où l’encodage déterministe est impraticable. Ne l’utilisez pas comme substitut à un regex quand un regex fonctionnerait.

Construire une stratégie de tests sémantiques

L’approche pratique de la validation sémantique suit un ordre de priorité :

Premièrement, la sémantique structurelle. Clés primaires, clés étrangères, contraintes non nulles, valeurs acceptées. Ce sont les tests génériques que chaque modèle devrait avoir. Ils détectent les violations les plus courantes avec le moins d’effort de configuration.

Deuxièmement, la sémantique de format. Patterns regex pour les colonnes avec des structures connues. Appliquez-les à toute colonne où des formats invalides ont causé des problèmes en aval ou où la source est connue pour produire des données malformées.

Troisièmement, la sémantique de plage. Limites de valeurs et vérifications de distribution pour les colonnes numériques et de date. Focalisez-vous sur les colonnes qui alimentent des métriques, des rapports ou des modèles ML où des valeurs incorrectes ont un impact métier mesurable.

Quatrièmement, la sémantique relationnelle. Règles multi-colonnes et assertions multi-tables pour la logique métier qui couvre plusieurs champs. Ces règles nécessitent une connaissance du domaine pour être définies et sont généralement informées par des incidents passés.

Cinquièmement, la sémantique exploratoire. Validation pilotée par l’IA pour les règles difficiles à formaliser ou pour la découverte initiale de patterns de qualité des données. Faites passer les règles validées à des tests SQL déterministes une fois le pattern confirmé.

Une couverture ciblée — focalisée sur les colonnes où une violation sémantique a un impact aval mesurable — est plus pratique qu’une couverture exhaustive. Une colonne customer__email alimentant un système d’automatisation marketing justifie une validation regex ; une colonne de texte libre notes sans utilisation aval structurée généralement pas.