Apache Superset : Comment contourner les limitations du filtre de date dans les versions 3.x–6.x
Apache Superset ne permet pas de lier un filtre de date à une colonne temporelle spécifique au niveau du graphique — sa sélection est toujours globale pour l’ensemble du jeu de données et dépend de l’ordre lexicographique des noms de champs. Cela engendre des problèmes critiques en production : modifications incontrôlées de la logique métier, conflits entre tableaux de bord et régressions cachées lorsque la colonne temporelle par défaut est modifiée. Dans cet article, nous examinons les raisons architecturales de ces limitations, les solutions de contournement testées ainsi que les contraintes techniques des solutions actuelles.
Pourquoi Superset choisit bot_profile__updated — et pourquoi c’est dangereux
Superset attribue automatiquement une colonne temporelle par défaut lors de la création d’un jeu de données, uniquement en fonction de l’ordre alphabétique des colonnes de type TIMESTAMP, DATETIME ou DATE. Dans le jeu de données « messages », le champ bot_profile__updated se retrouve en première position dans le tri lexicographique parmi bot_profile__updated, ts, created_at et updated_at. Ce comportement est codé en dur dans superset/datasets/models.py, où la méthode get_default_time_column() utilise sorted([col for col in dataset.columns if col.is_temporal]) sans tenir compte de la sémantique, du contexte métier ni des métadonnées.
Le risque majeur est que modifier la colonne temporelle par défaut d’un jeu de données affecte tous les graphiques et tableaux de bord qui l’utilisent, même s’ils concernent logiquement des axes temporels différents. Par exemple :
- Le graphique « Activité du bot » devrait être filtré par ts (le moment de l’événement) ;
- Le graphique « Mises à jour du profil » devrait être filtré par bot_profile__updated (le moment où l’entité a été mise à jour) ;
- Les deux utilisent le même jeu de données « messages ».
Si un administrateur change la colonne temporelle par défaut en ts, le second graphique commencera à afficher les données sur le mauvais axe temporel — sans erreurs, journaux ni avertissements. Une notification jaune dans l’interface rappelle simplement cet incident, mais ne bloque pas l’opération.
Filtre de colonne temporelle : une solution fonctionnelle aux limites systémiques
À partir de la version 3.0, Superset a introduit le filtre « Colonne temporelle », qui affiche une liste déroulante de toutes les colonnes temporelles du jeu de données et permet à l’utilisateur d’en sélectionner une. Toutefois, son implémentation n’est pas une solution, mais plutôt une abstraction de la faille existante :
- La valeur sélectionnée dans le filtre « Colonne temporelle » remplace globalement la default_time_column pour tous les filtres de date de ce tableau de bord ;
- Il est impossible d’ajouter deux filtres de date indépendants (par exemple « période de l’événement » et « période de traitement ») — les deux utiliseront la même valeur sélectionnée ;
- Le filtre ne prend pas en charge les expressions conditionnelles (WHERE ts BETWEEN ... AND ... AND updated_at > ...) ;
- Il n’affecte que le filtrage via WHERE, pas les agrégations dans les requêtes SQL.
Cela conduit à un schéma de « proxy de filtre », où les développeurs sont obligés de dupliquer les jeux de données avec des default_time_columns différentes afin d’isoler la logique. Cette approche viole le principe DRY, complique la maintenance et augmente la charge sur les métadonnées.
Solutions techniques pratiques pour les développeurs intermédiaires et seniors
Pour garantir un fonctionnement stable de Superset en production, les approches suivantes sont recommandées :
- Création de jeux de données virtuels via SQL Lab
- Pour chaque contexte temporel unique, créer un jeu de données SQL séparé avec un SELECT ... AS time_dimension FROM ... explicite ;
- Fixer le nom time_dimension comme seule colonne temporelle afin d’éviter toute ambiguïté ;
- Exemple :
SELECT
ts AS time_dimension,
user_id,
event_type,
payload
FROM messages
WHERE ts IS NOT NULL
- Utilisation de extra_json pour une liaison forcée
- Dans l’éditeur de jeu de données, spécifier ce qui suit dans le champ Extra JSON :
{"default_time_column": "ts"}
- Cela ne fonctionne que si le champ correspondant existe dans columns.extra et nécessite des mises à jour manuelles lorsque le schéma change ;
- Patch de Dataset.get_default_time_column() dans une image personnalisée
- Ajouter la prise en charge des annotations via des commentaires de base de données (COMMENT ON COLUMN messages.ts IS 'time_dimension:primary') ;
- Parser ces commentaires dans get_default_time_column() ;
- Nécessite une intégration CI/CD et des tests de compatibilité avec les nouvelles versions.
- Abandon des filtres intégrés au profit de graphiques SQL paramétrés
- Transférer tous les filtres temporels dans les conditions WHERE du graphique en utilisant {{ filter_values('date_range') }} ;
- Cela permet d’avoir plusieurs filtres indépendants et des conditions complexes ;
- L’inconvénient est de perdre l’interface visuelle de filtrage dans l’UI du tableau de bord.
Ce qui compte
- Superset ne fait pas la distinction entre la finalité sémantique des colonnes temporelles : ts, created_at et updated_at sont traités comme des chaînes équivalentes pour le tri.
- Changer la default_time_column d’un jeu de données n’est pas une opération sûre — cela affecte instantanément tous les graphiques dépendants sans aucun retour d’information.
- Le filtre « Colonne temporelle » n’est pas un mécanisme de liaison à une colonne spécifique ; c’est un commutateur temporel global pour l’ensemble du tableau de bord.
- Les versions 5.x et 6.x ne résolvent pas le problème fondamental : la logique de sélection de la colonne temporelle reste dans models.py, sans refactoring de l’architecture de filtrage.
- La seule manière fiable d’obtenir une isolation est de séparer physiquement les jeux de données ou de passer à des visualisations SQL paramétrées.
Dans Apache Superset, le filtrage par date demeure l’un des points faibles de l’architecture. L’absence de prise en charge de multiples axes temporels au niveau du jeu de données, la dépendance rigide à l’ordre lexicographique des noms de champs et l’absence de mécanisme d’annotation des colonnes rendent impossible la modélisation correcte de flux d’événements avec plusieurs dimensions temporelles. Cela est particulièrement critique pour l’analyse IoT, les transactions financières et les logs de microservices, où chaque enregistrement contient au moins trois horodatages : event_time, ingestion_time et processing_time. La communauté a proposé une correction via le ticket #32496, mais il n’existe toujours pas de pull request l’implémentant. Pour l’instant, la meilleure pratique consiste à concevoir les jeux de données de manière à ce qu’ils contiennent chacun exactement une colonne temporelle significative, ou à abandonner les filtres intégrés au profit de solutions contrôlées basées sur SQL.
— Editorial Team
Aucun commentaire pour le moment.