Retour au blog

La plupart des outils de données infèrent comment lire vos données. Voici pourquoi c'est à la racine de chaque corruption de pipeline que j'ai vue.

Je construisais un pipeline de conversion de données qui prenait des exports de différents systèmes et les chargeait dans une seule base de données MySQL.

Au milieu du débogage d'un énième échec en fin de pipeline, j'ai réalisé quelque chose qui a complètement changé ma façon de penser les systèmes de données : si nous avions eu un contrat de schéma unique au point d'entrée, environ 95 % des problèmes que nous traquions en aval n'auraient jamais existé. Pas corrigés, mais jamais existé.

C'est là que j'ai compris que la normalisation n'était pas juste une étape dans le pipeline, mais une étape obligatoire dont tout le reste dépendait. Et chaque outil existant que j'avais trouvé se trompait de la même manière.

L'inférence n'est pas une fonctionnalité. C'est une responsabilité.

Chaque fois qu'un outil regarde vos données et décide de leur signification sans qu'on lui ait dit, il fait un pari. Et dans les pipelines de données, les mauvais paris ne lèvent pas d'erreurs. Ils produisent des résultats faux mais plausibles, qui voyagent silencieusement en aval jusqu'à ce que quelque chose de coûteux se brise.

Voici à quoi ça ressemble concrètement

Prenez une colonne appelée amount dans un export CSV d'un système financier. Voici ce qu'elle contient réellement :

amount
1,200.50
1.200,50
"1,200"
1200
N/A

Cinq lignes. Cinq représentations différentes de ce qui pourrait être le même type de valeur, ou pas. L'une utilise la virgule comme séparateur de milliers. Une autre utilise la virgule comme séparateur décimal. Une est entre guillemets. Une est un entier brut. Une est un null déguisé en chaîne de caractères.

Un outil basé sur l'inférence scanne cette colonne, choisit un pattern qui correspond à la majorité (parfois sur un échantillon qui ne représente pas forcément la majorité réelle de la colonne, ce qui est un autre problème) et traite le fichier. Il ne demande pas. Il ne s'arrête pas. Il produit un résultat.

Ce qui finit dans votre base de données dépend entièrement du pattern qu'il a choisi. S'il adopte la convention anglo-saxonne, 1.200,50 devient 1.2. Ce n'est pas une erreur, ce n'est pas un null, c'est juste silencieusement faux. S'il adopte la convention européenne, 1,200.50 devient 1.2005, ou une chaîne, ou un null, selon la façon dont il résout les priorités de marqueurs. Aussi faux, aussi silencieux.

La valeur est maintenant dans votre migration. Elle a passé la validation parce que c'est un float valide. Elle a passé votre pipeline parce que rien n'a levé d'exception. Elle se trouve dans votre base de données avec l'apparence exacte de données correctes.

Trois mois plus tard, quelqu'un lance un rapport de réconciliation. Les chiffres ne correspondent pas. Personne ne sait pourquoi. Les données sont là depuis trois mois. Chaque processus en aval qui les a touchées a produit des résultats légèrement faux. La corruption n'est pas arrivée à la requête. Elle s'est produite à l'import, silencieusement, parce qu'un outil a fait une supposition. Pensez au coût que ça représente.

Pourquoi chaque outil existant continue de faire ça

Parce que l'inférence fonctionne sur des données propres. Et la plupart des démos utilisent des données propres.

Quand vos colonnes sont cohérentes, vos types homogènes et votre source prévisible, l'inférence est rapide et elle s'en sort la plupart du temps. Le problème, c'est que la majorité des systèmes produisent des données qui ne sont rien de tout ça.

Le problème plus profond, c'est que vous ne contrôlez pas la source. Vous ne savez pas quel schéma vous recevrez demain. Une colonne qui contenait des entiers la semaine dernière contient des types mixtes cette semaine. La source a changé sans vous prévenir. Et votre outil, inférant à partir de ce qu'il voit aujourd'hui, n'a aucun moyen de savoir ce qui a changé, ni pourquoi.

Couvrir une infinité de patterns n'est pas la bonne solution. Vous ne pouvez pas énumérer toutes les façons dont les données peuvent être fausses. Vous pouvez seulement éliminer les suppositions.

La seule issue

Mettez un humain au milieu. Avant que le pipeline ne traite une seule ligne, quelqu'un doit dire au système ce que les données signifient, pas à quoi elles ressemblent, mais ce qu'elles signifient. Quel type la colonne amount contient-elle réellement ? Quelles conventions décimales cette source utilise-t-elle ? En cas de conflits, comment les résoudre ? Que doit-il se passer quand une valeur est N/A, null, zéro, ou faut-il rejeter la ligne entièrement ?

Ce n'est pas du nettoyage manuel. Le nettoyage manuel, c'est réagir au désordre après coup, ligne par ligne, avec des formules qui cassent dès que les données changent. C'est un contrat défini une fois, appliqué de manière cohérente, qui rend le comportement du système explicite et prévisible, peu importe ce qui arrive.

Le coût de ce contrat : une étape de confirmation par ingestion. Le coût de ne pas l'avoir : des données auxquelles vous ne pouvez pas faire confiance.

Ce que l'IA a produit et ce que j'ai changé

Quand j'ai commencé à construire Normalize, j'ai utilisé l'IA pour réfléchir à l'approche de détection de schéma. Elle a suggéré une inférence avec conscience des locales, une meilleure supposition en somme : reconnaissance de patterns plus sophistiquée, détection de types plus fine, heuristiques améliorées pour gérer les valeurs ambiguës. Tout dans cette suggestion était conçu pour rendre l'inférence plus précise.

Elle n'a jamais remis en question le fait que l'inférence soit la bonne approche.

C'est là l'écart. L'IA a optimisé la mauvaise chose. Le problème n'a jamais été que l'inférence n'était pas assez intelligente. C'est qu'elle est structurellement mauvaise pour des sources de données imprévisibles, peu importe à quel point elle devient intelligente. Un outil avec conscience des locales devinerait quand même que 1.200,50 est de la notation européenne. Il devinerait juste avec plus de confiance.

J'ai rejeté toute cette direction et l'ai remplacée par l'étape de confirmation. Pas de supposition plus intelligente, simplement aucune supposition. C'est la décision que l'IA ne pouvait pas prendre parce qu'elle résolvait le problème que je lui avais donné, sans questionner si c'était le bon problème à résoudre.

C'est pourquoi j'ai construit Normalize.

Chaque outil que j'avais évalué faisait de l'inférence. Certains étaient plus malins que d'autres. Aucun ne résolvait le problème fondamental : l'inférence est une supposition, et les suppositions corrompent les données.

Normalize introduit une étape obligatoire de pause. Les données arrivent, il infère et suggère sa compréhension de la structure et des formats, le pipeline s'arrête, vous revoyez sa lecture de vos données, corrigez là où il s'est trompé ou ajoutez ce qu'il ne pouvait pas voir, et lui dites comment les données doivent être interprétées et ce qu'elles doivent produire. Rien ne bouge tant que ce contrat n'existe pas. Normalize ne devine jamais.

Il est open source. Si vous voulez l'exécuter localement, l'intégrer à votre propre pipeline, ou l'utiliser comme moteur de normalisation dans votre propre système, le cœur est disponible sur GitHub. Si vous voulez l'utiliser directement sans installation, il est accessible sur normalizeonline.com. Le support CLI est disponible pour les équipes qui souhaitent l'intégrer dans des workflows existants sans toucher à l'interface ou l'exécuter sur des fichiers locaux.

Si vous travaillez avec des données dont vous ne contrôlez pas la source, il a été construit exactement pour ça.

Author image

Victoire Habamungu

Ingénieur logiciel spécialisé en systèmes de données, architecture distribuée et ingénierie de plateforme.

Share post: