Aller au contenu

(04) Systèmes / Étude de cas

aria-er

Les chiffres concordent avec ceux de l'ARPAE.

aria-er est une plateforme de données sur la qualité de l'air en Émilie-Romagne : open data de l'ARPAE et météo d'Open-Meteo, de l'ingestion au tableau de bord. Cette page montre comment elle est construite et comment ses résultats ont été vérifiés.

Début
Septembre 2026
Version
1.2.0, octobre 2026
Équipe
Un développeur
Code
Public, MIT

Rust · dbt · DuckDB · BigQuery · Dagster · Streamlit · Terraform · Docker

Le problème

L'ARPAE publie les mesures de la qualité de l'air de l'Émilie-Romagne en open data, mais pas sous une forme qu'on peut interroger : valeurs horaires et journalières réparties sur plusieurs services, provisoires pendant des semaines puis corrigées, identifiants de stations qui changent d'un fichier à l'autre.

Les questions sont simples : combien de fois chaque station a dépassé les limites légales, si l'air s'améliore, combien le trafic ajoute à la pollution de fond, comment le vent et la pluie agissent sur les PM10. Y répondre avec des chiffres fiables, c'est le travail.

Contraintes

  • Les valeurs récentes sont corrigées pendant des semaines : chaque exécution retraite une fenêtre de 30 jours et met à jour par station, polluant et heure. Relancer la même fenêtre produit les mêmes fichiers.
  • Les horodatages sont stockés en UTC ; jours et années se comptent en UTC+1 toute l'année, comme le fait l'ARPAE.
  • Les limites légales sont dans un seed, jamais dans le SQL d'un modèle.
  • Les valeurs négatives ou impossibles sont signalées, pas supprimées.
  • Les mêmes modèles tournent sur DuckDB en local et sur BigQuery dans le cloud.

Architecture

Quatre composants, chacun avec une seule tâche, reliés par des fichiers et des tables plutôt que par des appels : un binaire Rust écrit du Parquet partitionné, dbt en tire des marts testés, Dagster planifie et contrôle les deux, un tableau de bord ne fait que lire les marts. Chaque ligne ne dépend que de celles du dessous.

  1. dashboard

    Streamlit : une requête filtrée par mart, aucune logique métier.

    orchestration

    Dagster : planification quotidienne, partitions mensuelles, backfills, contrôles de fraîcheur et de complétude.

  2. transform

    dbt : staging, intermediate et marts, avec plus de cent tests.

  3. aq-ingest

    Workspace Rust : clients ARPAE et Open-Meteo derrière un trait de source, nouvelles tentatives avec backoff.

  4. raw/

    Parquet partitionné par année et par mois, chaque partition réécrite de façon atomique, sur disque ou dans Cloud Storage.

Une commande lance tout avec Docker sur un portable ; la cible cloud écrit dans Cloud Storage et construit les mêmes modèles dans BigQuery.

Une journée de données, de bout en bout

La mise à jour quotidienne :

  1. 01Dagster

    À l'heure prévue, il lance la mise à jour du mois en cours, une exécution à la fois.

  2. 02Ingestor

    Il télécharge les 30 derniers jours depuis l'archive de l'ARPAE et la météo depuis Open-Meteo, et réécrit chaque mois touché en un seul fichier Parquet.

  3. 03dbt

    Il normalise les unités, supprime les doublons, fusionne les nouvelles lignes et reconstruit les marts. Un test en échec arrête l'exécution.

  4. 04Dagster

    Ses contrôles avertissent quand la dernière valeur a plus de 48 heures ou quand la complétude baisse.

  5. 05Tableau de bord

    Il lit les marts : dépassements, tendances, trafic face au fond, météo, complétude.

Choix et compromis

  1. 01

    Réécrire une partition, jamais ajouter

    Chaque mois est un fichier Parquet, réécrit en entier avec les lignes fusionnées et remplacé de façon atomique. Relancer une fenêtre donne les mêmes octets ; le prix est de réécrire un mois pour changer une heure, peu de chose à cette taille.

  2. 02

    Les règles légales, pas une simple moyenne

    Un jour ne compte qu'avec 18 heures valides, la valeur est arrondie avant la comparaison avec la limite, le jour est en UTC+1. Sans l'une de ces règles, les décomptes s'écartaient de ceux de l'ARPAE.

  3. 03

    Signaler, pas supprimer

    Les valeurs négatives, nulles ou invraisemblables restent dans les données avec un indicateur, et hors des agrégats. Deux tests d'avertissement les gardent visibles au lieu de les faire disparaître en silence.

  4. 04

    Un seul jeu de modèles, deux entrepôts

    Le SQL qui diffère entre DuckDB et BigQuery tient dans quelques macros. Un émulateur vérifie la version BigQuery à chaque pull request, et l'exécution sur un vrai projet Google Cloud a donné des marts identiques.

  5. 05

    Pas de streaming

    Les sources publient des heures après la mesure et corrigent pendant des mois, et chaque question est quotidienne ou plus large. Un traitement par lot quotidien suffit ; le streaming n'ajouterait que des pièces mobiles.

Vérifié avec l'ARPAE

Chaque décompte de dépassements a été comparé à ce que publie l'ARPAE. Deux vérifications ont changé le code : les PM10 ne concordaient qu'en arrondissant la valeur journalière avant la comparaison, et l'ozone concordait pour 29 stations sur 43 tant que les fenêtres de 8 heures n'étaient pas calculées sur chaque heure, y compris les heures manquantes.

Rapport annuel sur les données 2025 du réseau de Bologne et bulletin quotidien du 12 octobre 2026.
IndicateurARPAEaria-er
Jours de PM10 au-dessus de 50 µg/m³, Porta San Felice, 2025mart_exceedances_yearly2020
Jours d'ozone au-dessus de 120 µg/m³, Via Chiarini, 2025mart_exceedances_yearly5454
Stations avec les mêmes jours de dépassement des PM10 en 2026mart_exceedances_yearly6464
Stations avec les mêmes jours de dépassement de l'ozone en 2026mart_exceedances_yearly4343

Résultats en direct

Les graphiques ci-dessous lisent l'export qu'aria-er publie chaque matin sur GitHub Pages : les mêmes marts que le tableau de bord, mis à jour par le pipeline lui-même.

Chargement des dernières données…

Tableau de bord et pipeline

Page du tableau de bord avec un histogramme des jours de dépassement des PM10 par an, de 2016 à 2026, pour trois stations de Bologne, et une ligne pointillée au maximum légal de 35.
Dépassements : jours de PM10 au-dessus de la limite par an à Bologne, face aux 35 que la loi autorise.
Page du tableau de bord avec deux courbes de moyennes mensuelles de NO2 à Bologne de 2016 à 2026, la station de trafic toujours au-dessus des stations de fond.
Trafic face au fond : NO2 mensuel à Bologne, la part de pollution qui vient du trafic.
Graphe des assets dans Dagster : l'asset d'ingestion alimente les modèles de staging, puis les modèles intermédiaires, puis cinq marts.
Le lignage dans Dagster, de l'ingestion aux cinq marts.

La suite

  • Un export quotidien des marts publié par le pipeline, pour montrer des résultats à jour sur cette page.
  • Les dépassements d'ozone en moyenne sur trois ans, comme le demande la loi, dès que trois années complètes seront chargées.
  • Charger l'archive dans une table native BigQuery, si elle dépassait le quota gratuit de lectures.

Code

Le dépôt est public, sous licence MIT. Une seule commande lance tout avec Docker et charge dix ans de données.

Lire le code sur GitHubRetour à Systèmes