Feature Store y Gestión de Features

1. Introducción: El Problema Fundamental del Feature Engineering

Uno de los problemas más comunes al desplegar modelos de machine learning en producción es el training-serving skew: la degradación del rendimiento del modelo porque las características (features) usadas durante el entrenamiento difieren de las usadas durante la inferencia en tiempo real.

Este problema surge cuando dos equipos diferentes implementan la misma feature lógica con código ligeramente distinto, o cuando el código de entrenamiento calcula features en SQL mientras que el servicio online las calcula en Python. Las sutiles discrepancias en el manejo de fechas, valores nulos o límites temporales provocan que el rendimiento offline no se reproduzca en producción.

Un feature store no es solo una base de datos. Es un sistema de corrección y rendimiento que cierra la brecha entre el entrenamiento offline y el servicio online.


2. ¿Qué es un Feature Store? El Desglose de sus Tres Responsabilidades

Un feature store no es una cosa única, sino tres responsabilidades en una misma caja:

Componente Propósito Ejemplo de Implementación
Registro de features Metadatos sobre quién posee una feature, de qué fuente proviene, qué transformación la produjo y qué tipo tiene. Feast Feature Registry
Materialización offline Unir valores históricos de features en el momento correcto para construir datasets de entrenamiento. Offline store con BigQuery
Servicio online Búsqueda clave-valor con latencia de milisegundos que devuelve el feature más fresco en tiempo de inferencia. Online store con Redis

Estas tres capas son separables (por ejemplo, dbt + Snowflake pueden hacer registro y materialización, Redis puede hacer servicio online).
Lo que añaden soluciones como Feast, Tecton o Hopsworks es empaquetar las tres bajo una misma API y garantizar consistencia entre ellas, especialmente contra el training-serving skew.


3. Arquitectura de un Feature Store Profesional

3.1. Online vs Offline Store

Un feature store tiene casi siempre dos motores de almacenamiento:

Característica Offline Store Online Store
Propósito Generación de datasets de entrenamiento y scoring batch Inferencia en tiempo real
Latencia Segundos a minutos 1–10 ms (p99)
Datos que contiene Históricos completos (petabytes) Solo los valores más recientes por entidad
Ejemplos BigQuery, Snowflake, Redshift, Delta Lake Redis, DynamoDB, Cassandra, ScyllaDB
Patrón de consulta SQL, DataFrames Key-value lookup
Escala TB–PB GB
Consistencia Fuerte Eventual

La misma feature vive en ambos lugares con diferente frescura. El almacenamiento offline guarda cada valor histórico; el online guarda "la fila más reciente" por entidad.

3.2. Frescura de Features: Batch, Streaming y Real-time

La frescura de un feature indica cuán recientemente refleja el estado actual. En función de la ventana de agregación, encontramos tres tipos:

Tipo Frecuencia de actualización Ejemplo
Batch Por hora a diaria "Número de compras en los últimos 30 días"
Streaming Segundos a minutos "Monto de transacciones en los últimos 5 minutos"
Real-time En tiempo de solicitud "Número de clics en la sesión actual"

3.3. Registro de Features: El Catálogo Central

El registro de features es el componente central que almacena las definiciones, esquemas y metadatos de todas las features. Funciona como un catálogo vivo donde los equipos pueden:

  • Descubrir qué features ya existen — evitando recalcular lo mismo una y otra vez.
  • Entender quién las posee, de qué fuente provienen y cómo se transformaron.
  • Rastrear qué modelos downstream dependen de cada feature (linaje bidireccional).

3.4. Feature Server

El feature server es un servicio HTTP/gRPC sin estado que lee features del online store y las sirve a los modelos en producción. Feast lo implementa sobre FastAPI, y puede escalarse horizontalmente en Kubernetes.


4. Point-in-Time Correctness: El Mecanismo que Previene la Fuga de Datos

El point-in-time correctness (PIT) es probablemente la funcionalidad más importante (y menos comprendida) de un feature store. Resuelve un problema crítico: cómo construir un dataset de entrenamiento que use exclusivamente información que existía en el momento real en que ocurrió el evento a predecir.

4.1. El Problema de las LEFT JOIN tradicionales

Considera un modelo que predice si un usuario comprará en los próximos 7 días. Un enfoque naive sería:

-- ESTO ESTÁ MAL: Fuga de datos futuros
SELECT
    u.user_id,
    u.age,
    SUM(t.amount) as total_spent,
    CASE WHEN o.order_date > u.prediction_date THEN 1 ELSE 0 END AS label
FROM users u
LEFT JOIN transactions t ON u.user_id = t.user_id
LEFT JOIN orders o ON u.user_id = o.user_id

Esta consulta usa todas las transacciones históricas, incluyendo aquellas que ocurrieron después de la fecha de predicción. El modelo aprende con información del futuro y rendirá pobremente en producción.

4.2. La Solución: Point-in-Time Joins

Un feature store implementa joins temporales que garantizan que, para una entidad en un timestamp t_s dado, solo se incluyan features con timestamps ≤ t_s:

# (fragmento ilustrativo, no ejecutable)
# Feast: Construcción de training dataset sin fugas
training_df = fs.get_historical_features(
    entity_df=entity_df,  # user_id, event_timestamp, label
    features=[
        "user_transaction_features:total_purchases",
        "user_transaction_features:avg_order_value",
        "user_profile:age"
    ]
)       

Internamente, Feast ejecuta un point-in-time join que por cada fila del entity DataFrame (user_id, event_timestamp) recupera los valores de feature que estaban disponibles en ese momento preciso, ni antes ni después.

4.3. Datos Offline vs Feature Values

Una distinción crucial que se debe establecer es: los datos raw (crudos) no son features. Las features son valores transformados derivados de datos raw, listos para consumo directo por un modelo.

Nivel de abstracción Ejemplo Quién lo gestiona
Datos raw Tabla transactions con amount, timestamp, user_id Data Lake / Warehouse
Features brutas user_transaction_features como feature view Feature Store (offline store)
Features transformadas avg_order_value_30d Feature Store (capa de transformación)
Vector de features Conjunto de features para un modelo específico Feature Service

5. Feast en Acción: El Feature Store Open Source de Referencia

Feast es el feature store de código abierto más ampliamente utilizado, con soporte para caminos offline (batch training) y online (real-time serving).

5.1. Estructura de un Feature Repository

feature_repo/
├── feature_store.yaml      # Configuración del proyecto
├── entities.py             # Definición de entidades (user_id, item_id, etc.)
├── data_sources.py         # Fuentes de datos (Parquet, BigQuery, Redshift)
├── features/
│   ├── user_features.py    # Features de usuario
│   ├── transaction_features.py
│   └── session_features.py
└── tests/
    └── test_feature_views.py
5.2. Configuración de feature_store.yaml para Producción
yaml
project: fraud_detection
registry:
  registry_type: sql
  path: postgresql://user:pass@host:5432/feast_registry
provider: local  # local | gcp | aws
online_store:
  type: redis
  connection_string: "redis-cluster.internal:6379"
  redis_type: redis_cluster
offline_store:
  type: bigquery
  dataset: feature_store
entity_key_serialization_version: 2

5.3. Definiendo Entidades y Features

# (ejemplo ejecutable)
# features/user_features.py
from datetime import timedelta
from feast import Entity, FeatureView, Field, FileSource
from feast.types import Float32, Int64, String

# 1. Definir la entidad (clave por la que se agrupan las features)
user = Entity(
    name="user_id",
    join_keys=["user_id"],
    description="Identificador único del usuario"
)

# 2. Definir la fuente de datos
user_transactions_source = FileSource(
    path="data/user_transactions.parquet",
    timestamp_field="event_timestamp",
    created_timestamp_column="created_timestamp",
)

# 3. Definir el Feature View (la feature propiamente dicha)
user_transaction_features = FeatureView(
    name="user_transaction_features",
    entities=[user],
    ttl=timedelta(days=7),           # Caduca después de 7 días en online store
    schema=[
        Field(name="total_purchases", dtype=Int64),
        Field(name="avg_order_value", dtype=Float32),
        Field(name="days_since_last_purchase", dtype=Int64),
        Field(name="purchase_frequency", dtype=Float32)
    ],
    source=user_transactions_source,
)

5.4. Materialización: Sincronizando Offline → Online

La materialización es el proceso que copia features del offline store al online store, ejecutándose típicamente en un horario programado (ej. cada hora con Airflow).

# (fragmento ilustrativo, no ejecutable)
# DAG en Airflow
from airflow.decorators import dag, task
from feast import FeatureStore
from datetime import datetime, timedelta

@dag(schedule_interval="0 * * * *", start_date=datetime(2026, 1, 1))
def feast_materialization():
    store = FeatureStore(repo_path="feature_repo/")

    @task
    def materialize():
        store.materialize(
            start_date=datetime.utcnow() - timedelta(hours=1),
            end_date=datetime.utcnow()
        )

5.5. Entrenamiento Offline vs Servicio Online

# (fragmento ilustrativo, no ejecutable)
# Entrenamiento: get_historical_features() usa offline store
training_df = store.get_historical_features(
    entity_df=entity_df,        # user_id, event_timestamp, label
    features=[
        "user_transaction_features:total_purchases",
        "user_transaction_features:avg_order_value",
        "user_profile:age"
    ]
).to_df()

# Inferencia: get_online_features() usa online store
features = store.get_online_features(
    features=[
        "user_transaction_features:total_purchases",
        "user_transaction_features:avg_order_value"
    ],
    entity_rows=[{"user_id": "user_123"}]
).to_dict()

5.6. Cuándo Introducir un Feature Store

La decisión de introducir Feast debe basarse en umbrales prácticos:

Escenario Valor de Feast Justificación
1 modelo, 1 equipo, 1 fuente de datos Bajo — omitir El costo operativo supera el beneficio
Múltiples modelos compartiendo features Alto — elimina cómputo duplicado La reutilización de features paga la infraestructura
Training-serving skew observado en producción Crítico — función principal de Feast Feast garantiza la misma lógica en entrenamiento e inferencia
Features en tiempo real con latencia < 10 ms Alto — el patrón online store brilla Redis + feature server resuelven la latencia
Batch-only, sin inferencia real-time Moderado — el registro ayuda El catálogo de features ya aporta valor

Recomendación práctica: introducir Feast a partir del umbral de 3 modelos o 2 equipos. Antes de ese punto, el costo operativo excede el valor obtenido.

6. El Ecosistema de Herramientas en 2026

El mercado de feature stores ha madurado. La era dorada 2020–2022 terminó, y en mayo de 2026 el mercado se ha dividido en dos grandes vertientes:

6.1. Plataformas Dedicadas (Enterprise)

Herramienta Origen Fortalezas Consideraciones
Tecton Empresarial Automatiza pipelines de features; soporta streaming con latencia <100 ms; auditoría avanzada y compliance SOC 2; abstrae la complejidad de data engineering Comercial; costo elevado; ideal para organizaciones grandes
Hopsworks Académico/Empresarial Plataforma completa que incluye feature store, MLOps y cómputo; utiliza Apache Hudi y Spark Alta latencia para volúmenes pequeños; curva de aprendizaje pronunciada
Chalk Moderno Enfoque en simplicidad y developer experience Menos maduro que Tecton

6.2. Integraciones Nativas (Lakehouse/Warehouse)

Herramienta Estrategia Ventaja Principal
Databricks Feature Store Parte de Unity Catalog "Ya vive en tu plataforma de datos" — sin infraestructura adicional
Snowflake Feature Store Nativo en Snowpark Mismo modelo de gobernanza que el resto de los datos
Vertex AI Feature Store (Google) Gestionado Integración nativa con el ecosistema GCP
SageMaker Feature Store (AWS) Gestionado Integración nativa con ecosistema AWS

6.3. Feast como Opción Open Source

Para organizaciones que prefieren mantener el control de su infraestructura sin vendor lock-in, Feast sigue siendo la opción más sólida del ecosistema open source. Su arquitectura probada, comunidad activa y capacidad de desplegarse en Kubernetes lo convierten en la base ideal sobre la cual construir una plataforma de features propia..

7. Integración con MLflow: El Flujo Completo

7.1. Roles Complementarios

Feast y MLflow no son competidores — resuelven problemas fundamentalmente diferentes en el ciclo de vida del ML.

Capacidad Feast MLflow Kubeflow
Definir y versionar esquemas de features ✅ Sí ❌ No ❌ No
Almacenar y servir features (online + offline) ✅ Sí ❌ No ❌ No
Point-in-time correctness para features ✅ Sí ❌ No ❌ No
Linaje y registro de features ✅ Sí ❌ No ❌ No
Validación de calidad de datos en features ✅ Sí ❌ No ❌ No
Registrar experimentos, métricas y parámetros ❌ No ✅ Sí ❌ No
Model registry (promover modelos, alias) ❌ No ✅ Sí ❌ No
Orquestar pipelines multi-step ❌ No ❌ No ✅ Sí

Un error común es pensar que MLflow puede rastrear features. MLflow puede registrar nombres de features como parámetros, pero no puede definir, almacenar, transformar ni servir features. No tiene concepto de offline store, online store, ni point-in-time joins.

7.2. Arquitectura de Integración

Flujo completo con Feast + MLflow + Kubeflow:

a. Feature Engineering (Feast)
   ├─ Definir features en feature_repo/
   ├─ feast apply → registra en Feature Registry
   └─ Materialización programada (offline → online)

b. Experimentación (MLflow)
   ├─ get_historical_features(Feast) → training_df
   ├─ Entrenar modelo
   └─ mlflow.log_param("features", ["feature1", "feature2"])
       mlflow.log_metric("rhat", max_rhat)
       mlflow.log_artifact("model.pkl")

c. Registro del Modelo (MLflow Model Registry)
   ├─ mlflow.register_model()
   ├─ Promoción: Staging → Production
   └─ Model versioning + aliases

d. Orquestación (Kubeflow)
   ├─ Pipeline: ingest → transform → train → deploy
   └─ Cada paso invoca Feast y MLflow según corresponda

e. Inferencia (Feast Online Store + MLflow Serving)
   ├─ get_online_features(Feast) → feature_vector
   ├─ Modelo servido por MLflow o integración propia
   └─ Predicción retornada

7.3. Integración Práctica

# (fragmento ilustrativo, no ejecutable)
# Ejemplo: flujo de entrenamiento que integra Feast y MLflow
import mlflow
from feast import FeatureStore

# 1. Obtener features desde Feast
store = FeatureStore(repo_path="feature_repo/")
training_df = store.get_historical_features(
    entity_df=entity_df,
    features=["user_features:total_purchases", "user_features:avg_order_value"]
).to_df()

7.4. Iniciar experimento en MLflow

with mlflow.start_run() as run:
    # Log de metadatos del feature store
    mlflow.log_param("feature_store_version", "v2.1")
    mlflow.log_param("features_used", ["total_purchases", "avg_order_value"])

    # Entrenar modelo
    model = train_model(training_df)

    # Calcular métricas
    rhat, ess = compute_diagnostics(model)
    mlflow.log_metric("rhat_max", rhat)
    mlflow.log_metric("ess_min", ess)

    # Registrar el modelo
    mlflow.sklearn.log_model(model, "model")
    mlflow.register_model(f"runs:/{run.info.run_id}/model", "fraud_detection_model")

8. Mejores Prácticas

8.1. Gestión de Features como Activos Versionados

Práctica Implementación Justificación
Versionar definiciones de features Cuando cambias una transformación, crea avg_order_value_v2 en lugar de modificar la existente. Permite reproducir modelos antiguos y migrar gradualmente.
Feature discovery Centralizar todas las features en un catálogo accesible (Feast Registry). Los equipos pueden reutilizar features ya validadas.
Documentación de linaje Cada feature debe tener owner, fuente, transformación y modelos dependientes. Auditoría y comprensión del impacto de cambios.

8.2. Prevención de Fugas de Datos

Práctica Descripción
Usar point-in-time joins siempre Las LEFT JOIN estándar pueden filtrar datos futuros al training set. Usar siempre la funcionalidad PIT del feature store.
Validar la construcción del dataset Verificar que max(event_timestamp) en training_df ≤ max(label_timestamp) — si no, hay fuga.
Test de consistencia Muestrear pequeñas entidades y comparar valores offline vs online; cualquier discrepancia debe investigarse.

8.3. Monitoreo Continuo

Métrica Propósito Herramientas
Feature freshness ¿Los features online están actualizados? Feast metadata + alertas en materialización
Null rate ¿Ha aumentado la tasa de valores nulos? Soda Core, Great Expectations
Distribution drift ¿La distribución de la feature ha cambiado significativamente? Evidently AI, WhyLabs
Training-serving skew ¿Los valores online difieren sistemáticamente de los offline de entrenamiento? Pruebas A/B de features

8.4. Diseño para Consistencia

Práctica Descripción
Entity keys consistentes Usar las mismas claves de entidad en todas las features de un mismo modelo.
Pipelines determinísticos La misma feature pipeline debe producir siempre el mismo resultado para la misma entrada (misma semilla, mismo orden).
TTL y caducidad Definir ttl (time-to-live) apropiado para cada feature view, especialmente para features que no deban persistir indefinidamente en online store.

Referencias

Documentos relacionados