Le Databricks Feature Store en pratique

Ce que nous dirions à une équipe qui commence aujourd’hui.

Par: Praveen Sundaresan Ramesh et Gayathri Lekshmi Sadasivan.

Introduction

Une grande entreprise fait rarement fonctionner un seul modèle de Machine Learning (ML). Elle en fait fonctionner des dizaines, construits par différentes équipes dans différents espaces de travail (workspaces). Plusieurs de ces modèles dépendent des mêmes données sous-jacentes et de la même logique de calcul. Par exemple, un modèle de détection de fraude, un modèle de désabonnement de la clientèle (churn) et un modèle de valeur à vie du client pourraient chacun avoir besoin de card_txn_count_30d, le nombre de transactions effectuées par une carte au cours des trente derniers jours. Sans espace partagé, la caractéristique (feature) se retrouve reconstruite trois fois, et parfois de trois façons légèrement différentes.

Les pipelines ML en production dans une entreprise reposent typiquement sur une pratique MLOps robuste, dont une des étapes fondamentales est la préparation des données et l’ingénierie des caractéristiques (feature engineering). Il s’agit du processus de transformation et d’agrégation des données provenant de tables silver et/ou gold pour en tirer des colonnes raffinées, appelées caractéristiques (features), que les modèles ML consomment. Il peut être tentant de traiter cela comme un exercice ponctuel qui se termine une fois l’entraînement complété. À moins que la logique de transformation ne soit suivie et gouvernée, les caractéristiques calculées à l’inférence pourraient dériver de celles calculées à l’entraînement. Cela peut être dû soit au code de transformation qui a divergé entre le pipeline d’entraînement et celui d’inférence, soit aux valeurs utilisées à l’entraînement qui n’étaient en fait jamais disponibles au moment où l’étiquette (label) a été enregistrée. Les deux cas constituent un écart entraînement/service (training/serving skew) qui dégrade les modèles en production.

Ce que l’on souhaite à la place, c’est un endroit unique pour définir, découvrir, gouverner et réutiliser les caractéristiques, appuyé par un pipeline de transformation cohérent. La solution de Databricks pour cela est le feature store, construit sur Unity Catalog (UC). Nous souhaitons que cet article soit davantage un rapport de terrain qu’une paraphrase de la documentation. Nous commencerons par une brève introduction au feature store, nous parlerons des différentes façons de définir des caractéristiques, puis nous partagerons les leçons apprises tout au long de notre implémentation.

Qu’est-ce qu’un feature store Databricks?

Dans Databricks, un feature store est un registre central qui gère la définition, le calcul, le stockage et le service des caractéristiques de machine learning à titre d’objets gouvernés.

Le feature store intègre les capacités suivantes:

  • gouvernance et traçabilité (lineage),
  • jointures point-in-time,
  • récupération automatique des caractéristiques (lookups),
  • caractéristiques à la demande (on-demand) via des UDF,
  • découverte et partage des caractéristiques entre espaces de travail.

Feature table vs feature view

Databricks offre deux voies pour définir des caractéristiques : les Feature Tables et les Feature Views.

Les feature tables ont été la norme de référence jusqu’en juillet 2026, moment où Databricks a annoncé la disponibilité en préversion publique (public preview) des feature views. La différence clé entre les deux réside dans qui possède le pipeline qui alimente et rafraîchit la table. Avec les feature tables, c’est vous qui possédez le pipeline, tandis qu’avec les feature views, vous déclarez la caractéristique comme un objet natif de UC et Databricks construit et gère le pipeline pour vous.

Une feature table est une table Delta dans UC avec une clé primaire. Toute table Delta UC munie d’une contrainte de clé primaire peut agir comme feature table, ce qui signifie que vos tables gold, tables de diffusion en continu (streaming) et tables matérialisées existantes sont dès aujourd’hui des candidates. Il n’y a aucun format propriétaire ni aucune importation ou exportation. Cela réduit considérablement le risque de démarrer avec les feature tables, et l’adoption est réversible.

Remarque: les contraintes de clé primaire dans Unity Catalog sont informatives seulement et ne sont pas appliquées (enforced). Le client de feature engineering rejettera les clés primaires en double au moment où il crée une table pour vous, mais une contrainte de clé primaire que vous ajoutez à une table gold existante n’est pas appliquée. Si vous intégrez une table Delta existante dans le feature store, vous devez appliquer une vérification d’unicité au pipeline vous-même.

Les feature views, quant à elles, constituent une abstraction simple où vous définissez les caractéristiques de façon déclarative. À partir de la logique de caractéristique définie, le feature store de Databricks générera des données précises point-in-time pour l’entraînement. Une fois prête à être servie, vous pouvez matérialiser les caractéristiques vers des magasins hors ligne (offline) et en ligne (online), et Databricks exécutera les pipelines pour rafraîchir les valeurs des caractéristiques pour l’inférence. La même définition peut être utilisée autant pour des sources par lot (batch) que par diffusion en continu (streaming).

Feature Table Feature View 
Ce qu’est l’objetUne table Delta UC ou une table de diffusion en continu avec une clé primaireUn objet natif UC « Feature » contenant la définition de la caractéristique
Qui possède le pipelineVous. Vous écrivez les valeurs des caractéristiques dans la table et possédez le pipeline qui l’alimente et la rafraîchitDatabricks. Vous pouvez matérialiser les caractéristiques et la plateforme crée et exécute des pipelines Lakeflow serverless
Logique de la caractéristiqueFlexible. Spark, SQL et pipelines multi-étapes arbitraires. Vous pouvez calculer n’importe quoiDéclarative et contrainte. Fonctions d’agrégation fixes plus sélection de colonnes. Les expressions ligne par ligne (row-wise) sont aussi prises en charge 
Valeurs historiques pour l’entraînementLues à partir de la feature table que vous maintenez, en utilisant la sémantique point-in-time de la table lorsque applicableLes valeurs point-in-time exactes sont calculées à la demande à partir des données sources. Là où une matérialisation hors ligne existe, les données précalculées sont utilisées à la place
Service en ligne (online serving)Vous maintenez et publiez une table hors ligne synchronisée en ligne selon trois modes de publication (déclenché, instantané, continu)Matérialisation gérée. Les caractéristiques de sélection de colonnes et les caractéristiques de diffusion en continu sont en ligne seulement. Les caractéristiques d’agrégation pour l’en ligne exigent aussi un magasin hors ligne
Fraîcheur en diffusion en continuPossible, mais vous construisez et exploitez vous-même le chemin de diffusionMatérialisation de diffusion en continu gérée de première classe, avec contraintes de préversion
Gouvernance et traçabilitéGouvernance UC standard plus métadonnées de feature tableGouvernance UC spécifique aux caractéristiques. Les objets Feature offrent les permissions CREATE FEATURE, READ FEATURE et MANAGE
MaturitéDisponibilité générale (GA)Préversion publique
Tableau 1: feature table vs feature views

En matière de facturation, trois éléments génèrent des frais, et les trois sont optionnels :

  • la matérialisation gérée des caractéristiques par Databricks (seulement si vous utilisez les feature views),
  • Lakebase ou un autre magasin en ligne pris en charge (seulement si vous faites de l’inférence en temps réel),
  • les points de terminaison (endpoints) de service des caractéristiques (typiquement pour des modèles hébergés hors de Databricks).

Par conséquent, pour un cas d’usage purement par lot (batch-only), le feature store ajoute très peu d’infrastructure séparée et, en retour, vous obtenez la récupération de caractéristiques point-in-time, la traçabilité, la découverte et la gouvernance UC.

Leçons apprises

Leçon 1 : concevez le catalogue selon la clé d’entité et la cadence de rafraîchissement, pas selon la famille de caractéristiques

Un réflexe courant consiste à organiser les caractéristiques en tables selon le domaine d’affaires : les caractéristiques de vélocité des transactions dans une table, les caractéristiques de dépenses dans une autre, les données démographiques dans une troisième. Cela peut être utile pour organiser et découvrir les caractéristiques, mais ce n’est pas la bonne approche pour une feature table. Vous devriez plutôt commencer par vous poser deux questions:

  • Quelle entité la caractéristique décrit-elle?
  • Quel niveau de fraîcheur la caractéristique doit-elle avoir?

La première question n’est pas optionnelle. Dans UC, comme mentionné précédemment, toute table Delta avec une contrainte de clé primaire peut servir de feature table, et les recherches de caractéristiques (feature lookups) se résolvent sur cette clé. L’entité est donc cruciale dans la conception du catalogue.

Le tableau 2 présente un exemple de caractéristiques pour un système de détection de fraude en temps réel. Il est tentant de regrouper toutes les caractéristiques de dépenses ensemble, mais avg_transaction_amount_30d, par exemple, se rafraîchit quotidiennement, tandis que transaction_amount_last_15min se rafraîchit en continu. En les regroupant, la table entière devrait être rafraîchie en continu. Cela exigerait de faire fonctionner un pipeline Lakeflow en mode continu pour recalculer un nombre qui ne change presque jamais d’une journée à l’autre. Cela se propagerait aussi en aval. Publier cette table vers le magasin en ligne resynchroniserait les colonnes lentes à chaque mise à jour rapide.

CaractéristiqueEntitéCadence Domaine 
avg_transaction_amount_30dcustomer_idquotidienneDépenses
transaction_count_90dcustomer_idquotidienneVélocité
customer_risk_scorecustomer_idquotidienneRisque
transaction_count_last_5mincustomer_iddiffusion en continuVélocité
transaction_amount_last_15mincustomer_iddiffusion en continuDépenses
merchant_decline_count_last_10minmerchant_iddiffusion en continuRisque
merchant_avg_transaction_amount_1hmerchant_idhoraireDépenses
merchant_transaction_count_1hmerchant_idhoraireVélocité
merchant_risk_score_1hmerchant_idhoraireRisque
customer_income_bandcustomer_iddéclenchée par la sourceDémographie
merchant_zipcodemerchant_iddéclenchée par la sourceDémographie
Tableau 2: exemples de caractéristiques avec entité, cadence et domaine

Cela s’applique autant aux feature tables qu’aux feature views. Pour les feature views, regroupez les caractéristiques dans des pipelines de matérialisation partagés. Les caractéristiques qui partagent une même destination hors ligne et en ligne, ainsi qu’un même déclencheur, peuvent être matérialisées ensemble afin de réduire le nombre de pipelines.

Ce que nous recommandons :

  • Tracez d’abord la frontière physique selon la clé d’entité, puis selon la cadence de rafraîchissement.
  • Lorsque la fraîcheur d’une caractéristique est incertaine, optez par défaut pour une cadence plus lente.
  • Utilisez les tags et commentaires UC pour préserver le domaine que les gens utilisent réellement pour rechercher et découvrir les caractéristiques.
  • Nommez les objets en fonction de ce qui les distingue. Exemple: customer_features_daily, customer_features_streaming.

Leçon 2 : ne présumez pas que le service en ligne reproduit la sémantique sur laquelle vous avez entraîné le modèle

La sémantique point-in-time s’applique à la fois à l’entraînement et à l’inférence par lot (batch) de Databricks. L’inférence en ligne est différente: elle récupère la valeur courante de la caractéristique disponible dans le magasin en ligne.

CheminSémantiqueComportement
EntraînementJointure AS-OFPour une feature table de type série temporelle, Databricks récupère la dernière valeur de la caractéristique disponible au moment ou avant l’horodatage de recherche
Inférence par lotJointure AS-OFscore_batch utilise les métadonnées de caractéristiques stockées avec le modèle journalisé pour effectuer une recherche de caractéristique point-in-time
Inférence en ligneDernière valeurLa recherche de caractéristique en ligne n’effectue pas de jointure AS-OF; le chemin de service utilise la valeur de caractéristique actuellement disponible dans le magasin en ligne
Tableau 3: sémantique point-in-time selon les différents chemins

L’exactitude point-in-time dépend de la déclaration correcte de la sémantique temporelle. Databricks n’infère pas qu’une colonne d’horodatage doit être traitée comme une recherche temporelle simplement parce que son type est TIMESTAMP ou DATE. Une feature table de type série temporelle doit être créée ou déclarée de façon appropriée, ce qui, en pratique, signifie qu’il faut passer timeseries_columns au moment de la création.

Databricks applique la sémantique point-in-time que vous configurez, mais ne valide pas si votre configuration reflète correctement la disponibilité réelle de la caractéristique dans le monde réel. Par exemple, une caractéristique pourrait avoir un event_time qui indique le moment où une transaction a eu lieu, alors que le modèle devrait en réalité utiliser le moment où cette transaction est devenue observable dans le système de production.

Databricks documente que le magasin en ligne prend en charge la recherche par clé primaire plutôt que la recherche point-in-time. Cela crée une incohérence potentielle entre la façon dont le modèle a été entraîné et la façon dont il est utilisé en ligne. Pendant l’entraînement, le modèle voit la valeur de caractéristique qui était disponible à l’horodatage historique d’entraînement. Pendant l’inférence en ligne, le modèle reçoit la dernière valeur de caractéristique disponible dans le magasin en ligne au moment où la requête est servie.

Ces valeurs ne sont pas nécessairement les mêmes. Si une caractéristique change entre l’horodatage historique d’entraînement et le moment de l’inférence en ligne, le modèle pourrait recevoir une valeur dont les caractéristiques de fraîcheur ou de distribution diffèrent de celles observées à l’entraînement.

De même, lookback_window sur la recherche de caractéristique exclut les valeurs de caractéristiques plus anciennes que la fenêtre spécifiée. Cela s’applique à l’entraînement et à l’inférence par lot, mais est ignoré lors de l’inférence en ligne, où la dernière valeur est utilisée peu importe l’ancienneté. Il s’agit d’une asymétrie similaire à celle décrite plus haut, mais encore plus marquée, puisque vous avez explicitement déclaré une tolérance à l’obsolescence que le service en ligne ne respecte pas.

Ce que nous recommandons pour les modèles servis en ligne :

  • Concevez l’horodatage d’entraînement en fonction de la cadence opérationnelle de la caractéristique. Si une caractéristique est rafraîchie opérationnellement chaque heure, une grille d’entraînement horaire pourrait produire une approximation plus représentative de ce que le modèle voit en ligne.
  • Utilisez des caractéristiques rafraîchies en continu ou en diffusion en continu lorsque l’exigence est une fraîcheur à faible latence. Databricks prend en charge les caractéristiques de diffusion en continu spécifiquement pour les cas où les valeurs doivent se mettre à jour en continu. Cela peut réduire considérablement le décalage de fraîcheur, mais ne change pas la distinction fondamentale entre la recherche en ligne actuelle et la recherche AS-OF hors ligne.
  • Surveillez les distributions des caractéristiques en production. Comparez ce qui est servi avec les distributions observées à l’entraînement et à la validation.
  • Traitez l’âge de la caractéristique comme un concept explicite de modélisation et de surveillance. Une nouvelle caractéristique telle que inference_time – feature_timestamp peut révéler à quel point une entrée est désuète et, le cas échéant, permettre au modèle d’apprendre que cette désuétude a de l’importance.

Leçon 3 : les caractéristiques à la demande exigent une attention particulière

Certaines caractéristiques ne peuvent pas être précalculées. La distance entre l’emplacement d’une transaction et l’adresse résidentielle du client, par exemple, dépend de l’emplacement de la transaction, qui n’est disponible qu’au moment de la requête. Celles-ci deviennent des caractéristiques à la demande (on-demand), où des fonctions Python ordinaires, enregistrées dans UC, peuvent être utilisées pour les évaluer à l’intérieur du conteneur de service au moment de la requête.

Remarque: le modèle doit être journalisé à l’aide de fe.log_model pour s’assurer que le modèle calcule automatiquement les caractéristiques à la demande au moment de l’inférence.

Elles sont extrêmement utiles pour les cas d’usage en temps réel, mais une attention particulière est requise pour les points suivants :

  1. La sémantique des valeurs manquantes diffère entre le mode par lot et le mode en ligne. Vous devez gérer les valeurs nulles vous-même, car la plateforme ne le fera pas. Lorsqu’une recherche de caractéristique ne retourne aucune valeur, l’inférence par lot retourne None, tandis que l’inférence en ligne retourne float("nan").
  2. Un modèle peut utiliser jusqu’à 100 caractéristiques à la demande. Séparément, UC permet au maximum cinq appels d’UDF par requête, une limite du plan de requête Spark qui déclenche UDF_MAX_COUNT_EXCEEDED. Cette limite compte les instances d’UDF dans le plan, et non les fonctions distinctes.
  3. Il existe une correspondance un-à-un entre l’UDF et la caractéristique, et les types de sortie sont restreints. FeatureFunction lie une UDF à un seul nom de sortie, et les UDF UC retournent une valeur scalaire. Pour les points de terminaison de service de caractéristiques, il existe des restrictions sur les types de données de sortie : ArrayType, MapType et StructType ne sont pas pris en charge comme types de sortie.

Ce que nous recommandons :

  • Protégez chaque UDF contre None et contre NaN, et faites-en une règle de lint qui fait échouer la build. De plus, définissez des valeurs par défaut explicites sur les recherches (lookups) en écrivant FeatureLookup, afin que la fonction ne rencontre idéalement jamais de valeur manquante.
  • Déclarez chaque paquet qu’une UDF importe à la fois dans la clause ENVIRONMENT de l’UDF et dans extra_pip_requirements de fe.log_model.
  • Si plus de cinq caractéristiques à la demande sont requises, augmentez spark.databricks.safespark.externalUDF.plan.limit uniquement sur les clusters d’entraînement et de score par lot, en plus des paramètres de suivi de mémoire que Databricks recommande d’ajuster en parallèle. Gardez en tête que cela introduit le risque de dépassement de mémoire (OOM) que cette limite existe justement pour prévenir.

Leçon 4 : deux éléments sont facturés en continu, et ni l’un ni l’autre ne s’arrête de lui-même

Databricks recommande Lakebase comme magasin en ligne pour les feature tables, et les feature views ne se matérialisent en ligne que par l’entremise de Lakebase. Bien que Lakebase offre une option de mise à l’échelle à zéro (scale-to-zero), le feature store en ligne ne la prend pas en charge. Un magasin en ligne engendre donc des coûts en continu, et cela s’accumule pour chaque magasin dupliqué dans les environnements de développement et de test.

Le mode de publication CONTINUOUS est le deuxième objet toujours actif : un pipeline de diffusion en continu par table en ligne, qui fonctionne en continu, que les données sous-jacentes soient rafraîchies ou non. Databricks offre trois modes de publication, tel que présenté au tableau 4.

Mode Ce qu’il faitProfil de coût
TRIGGERED (par défaut) Mises à jour incrémentielles, à la demande ou selon un horaireBon équilibre coût/décalage; coûteux en deçà d’intervalles de 5 minutes
SNAPSHOTCopie complète à chaque synchronisation; planifiableEnviron 10 fois plus efficace lorsque plus de 10 % des lignes changent par cycle
CONTINUOUSPipeline de diffusion en continu, latence de quelques secondesDécalage le plus faible, coût le plus élevé; minimum de 15 secondes
Tableau 4: différents modes de publication et leur profil de coût

Les modes TRIGGERED et CONTINUOUS exigent tous deux que le Change Data Feed (CDF) soit activé sur la table source, ce qui ajoute une amplification d’écriture à chaque fusion (merge) dans la feature table.

Ce que nous recommandons :

  • Consolidez les magasins en ligne. Pour les environnements de développement, de test et de production, Databricks recommande de partager un seul magasin entre les projets et les utilisateurs plutôt que d’en créer des distincts.
  • Faites correspondre le mode de publication à la cadence, sans recourir à un choix par défaut uniforme. Étiquetez chaque feature table avec update_frequency et dérivez-en le mode. Réservez le mode CONTINUOUS aux caractéristiques dont le modèle ne peut tolérer l’obsolescence.
  • Créez une feature table conçue sur mesure, ou une simple vue de sélection contenant uniquement les colonnes consommées par le point de terminaison, et publiez celle-ci. Les tables synchronisées (synced tables) acceptent les vues et les vues matérialisées comme sources.
  • Supprimez les magasins en ligne inutilisés et leurs tables dans les environnements hors production.
  • Lorsqu’une feature table est publiée vers plusieurs magasins en ligne, les points de terminaison de service se résolvent vers le plus ancien selon l’horodatage de création.

Leçon 5 : les feature views sont l’avenir de la plateforme, et une préversion en révèle déjà les limites aujourd’hui

La recommandation de Databricks est d’utiliser les feature views pour la plupart des nouveaux cas d’usage. Bien que la simplicité et la nature déclarative des feature views soient attrayantes, certaines limitations méritent d’être soulignées.

  1. Une caractéristique calcule exactement une seule agrégation, et rien ne s’exécute après. Le flux est : filter_condition (un WHERE ligne par ligne appliqué à la source de données) → transformation_sql (une projection SELECT ligne par ligne) → un seul opérateur d’agrégation sur une seule fenêtre. Lorsque les deux sont définis, la requête résolue est SELECT {transformation_sql} FROM {table} WHERE {filter_condition}. Seules des expressions ligne par ligne, comme des renommages ou des conversions de type (casts), sont acceptées. La gestion des valeurs nulles et les colonnes dérivées doivent être traitées avant l’agrégation. L’arithmétique post-agrégation est hors de portée : vous ne pouvez pas exprimer un ratio entre deux caractéristiques agrégées, ni fusionner (coalesce) un résultat agrégé, à l’intérieur d’une feature view.
  2. L’ensemble des opérateurs d’agrégation est fixe, et deux d’entre eux sont des approximations: Sum · Avg · Count · Min · Max · First · Last · StddevPop · StddevSamp · VarPop · VarSamp · ApproxCountDistinct · ApproxPercentile · FirstN · LastN · FirstDistinct · LastDistinct. L’API des feature views ne documente aucune prise en charge du mode, des comptes distincts exacts, de la médiane, de la corrélation, ni des agrégations définies par l’utilisateur. Les approximations sont déterministes et ne causent aucun écart (skew), mais elles produisent des chiffres légèrement différents de ce qui pourrait être attendu.
  3. Les feature views et les fonctions à la demande ne peuvent pas être servies ensemble. Un FeatureSpec contenant des feature views ne peut pas contenir d’entrées FeatureLookup ou FeatureFunction. Ainsi, des fonctions à la demande, comme la distance entre une transaction et le domicile du titulaire de la carte, ne peuvent pas être calculées pour un modèle dont les autres caractéristiques sont des feature views.
  4. Les caractéristiques d’agrégation par lot peuvent être matérialisées hors ligne et en ligne, bien que les caractéristiques de fenêtre glissante (rolling-window) par lot ne puissent pas être matérialisées. Les caractéristiques de sélection de colonnes et les caractéristiques de diffusion en continu ne peuvent être matérialisées qu’en ligne. Les caractéristiques provenant de la source de la requête (request-source) ne peuvent pas être matérialisées du tout, et ce, par conception. Puisque les caractéristiques de diffusion en continu n’ont pas de matérialisation hors ligne, leurs valeurs sont recalculées à partir des données sources pendant l’entraînement.
  5. La matérialisation des feature views en diffusion en continu ne rétro-remplit (backfill) pas les enregistrements historiques. La matérialisation débute avec les enregistrements qui arrivent après le démarrage du pipeline, de sorte qu’une caractéristique de fenêtre glissante nouvellement matérialisée est incomplète jusqu’à ce qu’une fenêtre complète de données se soit accumulée. Par exemple, un flux de fenêtre glissante de 30 jours nouvellement démarré ne contiendra pas un historique complet de 30 jours tant que 30 jours de données n’auront pas été traités.
  6. Nous avons vu précédemment que l’inférence en ligne n’effectue pas de recherche point-in-time; elle retourne plutôt la dernière valeur disponible pour une clé primaire. La cadence de rafraîchissement contrôle le moment où une feature view est matérialisée, mais elle ne crée pas de nouvelles observations pour les entités qui n’ont aucun enregistrement source. Si aucune nouvelle donnée n’arrive, le magasin en ligne continue de servir une valeur désuète. Avec les feature tables, il est possible de contourner ce problème en construisant un pipeline « spine » qui écrit des lignes à intervalles réguliers, garantissant ainsi que le calcul de la caractéristique est évalué pour l’entité même en l’absence de tout nouvel événement.

Ce que nous recommandons :

Si l’une de ces limitations s’applique à votre cas d’usage, en tenez-vous aux feature tables. Conservez les feature views comme une couche d’expérimentation jusqu’à ce que les contraintes de la préversion soient levées, et continuez de surveiller la documentation de Databricks pour les dernières mises à jour.


Posted

in

,

by

Tags: