Feature stores

After this lesson you will explain why machine-learning teams keep their features in a store of their own — one definition, an offline store for training, an online store for serving — and build a training set that never looks into the future.

In September 2017 Uber's engineering blog described Michelangelo, the platform behind the company's machine-learning models. One of its parts, a feature store, held about 10,000 features — the input columns of the models — computed every day, shared across teams by name and kept in two systems: a Hive/HDFS data lake for training and Cassandra for online predictions. The History slide of the lecture starts right there: "First Experience in Uber, with Michelangelo platform" (p. 739). Its timeline adds Airbnb, Gojek, Tecton, AWS, Databricks and Google by 2021.

Here is the puzzle. A feature such as "what this customer spent in the last 30 days" is one short query. Why did so many companies build a whole system — two stores, a catalog, monitoring — around numbers that one query computes?

Because a one-line feature can go wrong in two ways that no query will ever report: it gets computed twice, and it gets read at the wrong moment. By the end of the lesson you will name both, watch each one break a model in a widget, and know why Uber's "store" was not a new database at all.

Features and the MLOps loop

Start with the usage example of p. 738, a credit-scoring application. To decide on a loan, a model reads a few numbers about each customer: "Customer demographics (age, income, etc.)", "Historical credit behavior (loan repayments, defaults)" and "Real-time transaction data (recent purchases, account balance changes)". Each of these numbers is a feature.

Feature — "the input variables or attributes that describe (data) objects used by machine learning models to make predictions, such as customer age, transaction history, or weather conditions" (p. 720).

Feature store — "a centralized repository used to store, manage, and serve features for machine learning (ML) tasks". Its goal: "to streamline the process of creating, sharing, and using these features across various ML models" (p. 720).

In the notation of statistics a feature is a column of the design matrix \(X\); a feature store keeps those columns — named, dated and shared — outside any single model.

The same slide says where the store belongs: "It's a key asset in ML-Ops". MLOps (Machine Learning Operations) is "a set of practices and tools that aim to streamline the development, deployment, and maintenance of machine learning (ML) models in production environments"; it "extends the principles of DevOps (Development and Operations) to the ML domain" and "brings together data scientists, machine learning engineers, and operations teams" (p. 722). Page 723 draws it as a loop with no end.

Dev Ops Develop Data prep EDA Review Deploy Inference Monitor (Re)-Train the same features, needed twice
Fig. 1. The loop of p. 723, redrawn as two joined circles — development on the left, operations on the right — with the slide's eight stations read as one cycle. Highlighted: the two stations that consume features, (Re)-Train and Inference.

Page 724 tells the same loop in five phases, each with what MLOps promises for it:

  1. Development — experiments with "models, algorithms, and feature sets"; code, models and datasets are versioned.
  2. Training and Validation — the model is trained and "validated using a test dataset", in a way that "can be reproduced".
  3. Deployment — automated with CI/CD practices.
  4. Monitoring — "real-time insights into how the model is performing, and whether data or concept drift is affecting its accuracy".
  5. Retraining — "When the model's performance drops or when new data becomes available".

Page 725, titled "ML-Ops – focus on data and features", draws the same lifecycle as four interlocking rings — Data, ML, Dev and Ops — and the first ring is pure data work: collect, curate, transform, validate. That ring is where a feature store works.

Fix the two drifts of phase 4 now; the slides use them without defining them. Data drift: the distribution of the inputs changes — this year's applicants are younger. Concept drift: the relation between inputs and target changes — the same spending pattern no longer means the same risk. In statistical terms \(P(X)\) moves, or \(P(Y \mid X)\) moves.

Pages 726–728 list eight components of MLOps: version control for models and data ("datasets, features, models, and hyperparameters"); CI/CD for ML; model training and retraining; monitoring and model performance tracking ("accuracy, precision, recall, and business-specific KPIs"); data and feature management; automation and orchestration ("Kubernetes, Airflow, or Kubeflow"); collaboration between teams; model governance and compliance. Page 729 adds five benefits: faster time to market, improved collaboration, increased model reliability, reusability "of code, pipelines, and features", better model governance.

The fifth component is the door to this lesson: "MLOps integrates with feature stores to ensure that the same data transformations applied during training are applied in production, avoiding issues like 'training-serving skew.'" (p. 727).

MLOps is a loop, and the features are needed at two of its stations: training and inference.

The biggest problem: one feature, computed twice

Page 743 is titled "The biggest problem to face": "Features for a machine learning model are required in both the modelling and production (deployment) phases of the lifecycle. This implies duplication of code and risk of inconsistency".

Here is what that looks like. A data scientist writes spend_l30d, a customer's spending over the last 30 days, in a notebook: purchases minus refunds, computed over the history to build the training set. The model goes live, and an engineer rewrites the same feature inside the production service — another language, a deadline, and no refunds. On 14 June customer C2, who returned an item of 220.00 the day before, has 275.00 in the training data and 495.00 in production. Both programs run without a single error.

Training-serving skew — the situation "where a model performs poorly because the features used in production differ from the ones used during training" (p. 734). Page 743 calls it "online/offline skew".

raw events notebook code service code training inference 275.00 495.00 ≠ two programs

Before: two programs, two values

raw events feature store one definition training inference 275.00 275.00 = same value

After: one definition, one value

Fig. 2. Customer C2 on 14 June, as in the widget of section 3. Left: the notebook subtracts the returned item, the service does not, and the model trained on 275.00 is fed 495.00. Right: the drawing of p. 742 — raw data into one feature store, out to "Features used for model training" and "Features used for model inference".

The fix is to stop having two programs. On p. 742 the feature store is "An interface between the raw data and the models. It takes raw data and then transforms it into features subsequently used for model training and inference", and it "ensures that the features used across both models (and possibly many models) are consistent". The same slide calls it "a centralised repository that stores curated features" and "a data management layer that allows data scientists, machine learning engineers, and data engineers to collaborate, share, and discover features".

"Skew is just another word for drift." No. Skew happens while the world stands still: one raw input, two computations. Drift is the world changing, with one computation. A feature store removes skew by construction; drift it can only detect, by monitoring the features (p. 736) — the cure for drift is retraining.

What a feature store "grants", in the words of p. 743: "Consistency between model training and inference leads to better model accuracy", "eliminating online/offline skew", "Share and reuse features across models and teams, ensuring faster model development", "Provide feature versioning, lineage, provenance, and regulatory compliance". Page 737 sums it up in four benefits: Consistency (the same transformations in training and production), Efficiency (no redundant feature engineering), Scalability (batch and real-time features at large scale) and Version Control (models trained on older versions of features "can still be reproduced").

Two benefit lists sit a few pages apart and a closed question can mix them. MLOps (p. 729): faster time to market, improved collaboration, increased model reliability, reusability, better model governance. Feature store (p. 737): consistency, efficiency, scalability, version control.

Page 733 shows who talks to the store, and when. Data engineers, data scientists and ML engineers "Define and iterate on new features" and "Load feature data for training" and "for testing"; the prediction service in production receives the feature values computed for inference and writes back to the store ("Log served features, prediction, outcomes", "Track feature stats to identify issues"); the engineers read those back to "Monitor for drift & quality issues". Every phase of the loop reads from the store or writes to it.

Is it always worth it? Feature stores "are a must-have when working on a project where the intention is to deploy models at scale and in production"; "However, if you are working within a small team and on a small project or a POC, you may not need it" (p. 744). A proof of concept has one model and no production: nothing is computed twice.

A feature store replaces two programs that compute the same feature with one definition that feeds both training and serving.

Two stores: the history for training, the latest value for serving

One definition does not mean one database. Back to the credit score of p. 738: "For training, the offline store would provide historical data, while for real-time predictions, the online store would supply the latest transaction data." Two stores, because training and serving ask two different questions.

The offline store "Contains batch features used for model training. These are typically updated at regular intervals (e.g., daily or weekly) and stored in large-scale data storage systems like Hadoop or cloud-based data lakes" (p. 735). It keeps "months' or years' worth of feature data", "often stored in data warehouses or data lakes like S3, BigQuery, Snowflake, Redshift" (p. 765). Its question is a scan: every customer's value on every day of the last two years. That is the workload of a warehouse (lesson 23).

The online store "Contains real-time features used for serving live predictions. These features need to be served with low latency for real-time inference and are typically stored in low-latency databases like Redis" (p. 735). It persists "feature values for low-latency lookup during inference", and "They typically only store the latest feature values for each entity" (p. 765). Its question is a lookup: the current values of customer C2, now, in milliseconds — a GET on a key, exactly what Redis is built for (lesson 17).

Page 765 adds: "Online stores are usually eventually consistent." Why is that acceptable? The article the slides follow explains that most ML uses have no strict consistency requirement: a fraud check computed on a balance a few seconds old is still a sensible check, while a check that arrives after the payment has gone through is useless. Latency and availability win — the BASE side of the trade-off of lesson 5.

"Cassandra is a key-value store: p. 765 says so." Read the sentence again: "They are usually implemented with key-value stores like DynamoDB, Redis, or Cassandra" describes how an online store uses Cassandra — one lookup by partition key. As a family, the course files Cassandra under columnar databases: the exam-guideline deck lists "Key-value DB (Redis)" and "columnar DB (Cassandra)", and the course notes call it "a columnar database with some key-value features" (lesson 20). Asked for Cassandra's family, answer columnar.

Serving: one API, two answers

Reading from the two stores is the task the slides call Serving: "An easy and canonical way to access all features in a company consistently across all environments" (p. 764). Offline, "feature values are commonly accessed through notebook-friendly feature store SDKs"; online, "a feature store delivers a single vector of features at a time made up of the freshest feature values, through a high-performance API backed by a low-latency database". The figure of p. 764 asks for the same three features both ways (l7d and l30d mean "last 7 days" and "last 30 days"):

"Request feature vector for inference", answered through a REST API:

.get_feature_vector (
    features=["item_clicks_l7d",
              "item_price",
              "user_spend_l30d"],
    entities={"user_id":3,
              "item_id":62}
)

The answer, "Feature Vector (latest values, low-latency)":

{
  "item_clicks_l7d":6,
  "item_price":"$25.12",
  "user_spend_l30d":"$12.10"
}

"Request training data", answered through the Python SDK:

.get_training_data (
    features=["item_clicks_l7d",
              "item_price",
              "user_spend_l30d"],
    entities=entities_df
)

The answer, "Training Dataframe (historical values)":

user_id  item_id  time   item_clicks_l7d  item_price  user_spend_l30d
1        54       7485   6                $23.2       $0
2        35       46854  5                $41.54      $8.41

The same three names, two very different answers: one vector of the latest values for one key, or one row per (entity, time) with the values as they were then. That time column comes back in section 5.

"get_feature_vector is Feast's API." No: pp. 763–769 reproduce a general article on feature stores (the Tecton article of the resources below), and the method names of p. 764 belong to that article's illustration, not to Feast. Feast's real calls are the ones of p. 762, get_historical_features and get_online_features — quote those when a question names Feast.

Three use cases and the Feast call for each (p. 762). Two of the three are offline: what matters is batch versus per-request, not training versus prediction.
Use caseExampleAPI
Training data generationFetching user and item features for (user, item) pairs when training a production recommendation modelget_historical_features
Offline feature retrieval for batch predictionsPredicting user churn for all users on a daily basisget_historical_features
Online feature retrieval for real-time model predictionsFetching pre-computed features to predict whether a real-time credit card transaction is fraudulentget_online_features

How do values reach the online store? Page 757, about Feast: "For offline use cases that only rely on batch data, Feast does not need to ingest data and can query your existing data", while "For online use cases, Feast supports ingesting features from batch sources to make them available online (through a process called materialization), and pushing streaming features to make them available both offline / online". The offline store can be the warehouse you already have, queried in place; materialization copies the latest value of each key into the online store; a stream pushes to both.

The widget puts the two stores, and the two programs of section 2, side by side. Its one insight: skew is silent — it appears, hides and reappears with the data and the calendar, and only one shared definition removes it.

One feature, two stores: where the skew comes from

Four customers of a credit-scoring app, their purchases and refunds from 1 May to 30 June, and one feature: spend_l30d, purchases minus refunds over the last 30 days. The notebook computes it for the offline store (one row per customer per day); the online store holds one key per customer, the value served to the model on the lookup day. Choose who fills the online store and which mistakes the hand-written service makes. The data are invented for the widget; every value is computed from them.

  1. Choose "a feature store". Before you look at the readouts: how many rows does the offline store hold on 30 June, and how many keys does the online store hold? Why so different?
    What you should see

    244 rows (4 customers × 61 days) against 4 keys. The offline store keeps "months' or years' worth of feature data for training purposes"; online stores "typically only store the latest feature values for each entity" (p. 765) — on 14 June it is still 4 keys, while the offline store has 180 rows. The model in production needs one key, now; training needs the whole history.

  2. Choose "two programs" with only "forgets refunds" on, and move the day from 1 to 30 June. Predict when the skew counter first leaves zero, and for whom.
    What you should see

    On 13 June, for C2: 275.00 in the training rows, 495.00 served — C2 returned an item of 220.00 that day. From 16 June C1 joins (a refund of 12.00: 160.70 against 172.70). For twelve days the two programs agreed perfectly: a skew test run in early June would have passed.

  3. Only "calendar month" on: on which day of June does the skew disappear? And what does the service send on 1 June?
    What you should see

    It disappears on 30 June, the one day when "this month" and "the last 30 days" are the same window. On 1 June the service sends 0.00 for C1, C2 and C3, who spent 215.50, 215.00 and 195.00 in the previous 30 days. The bug comes and goes with the calendar: 83 of the 120 lookups of June are wrong.

  4. Turn on all three bugs (105 skewed lookups in June), then switch to "a feature store". What happens, and why can no toggle bring the skew back?
    What you should see

    The counters drop to 0 of 4 and 0 of 120. There is no second program left for a bug to live in: the online store is filled by materializing the latest offline value of each key, so the value served on any day is the very number a training row of that day contains. That is the "Consistency" of p. 737 — the same feature transformations in training and production.

The offline store answers "what was the value then?" for training; the online store answers "what is the value now?" for one key, in milliseconds.

Inside the box: five tasks

Page 763 opens the box (Fig. 3). Data enter from a stream source and a batch source and leave towards model serving and model training. Three tasks sit on the data path — transform, storage, serving, with an on-demand transform inside serving — and two span all of them: operational monitoring above, the registry below. The slides number them 1 Serving, 2 Storage, 3 Transform, 4 Monitoring, 5 Registry; you have met the first two.

sources stream batch Feature Store Operational monitoring Transform Storage Serving stream batch online offline on-demand Registry model serving model training
Fig. 3. The five tasks of p. 763, with the transforms of p. 766 inside. A stream transform (magenta) and a batch transform (teal) both feed both stores — streaming features are pushed to both, batch values are materialized into the online store (p. 757); the online store reaches model serving through serving, where an on-demand transform (orange) adds what only the request knows; the offline store feeds model training. Operational monitoring and the registry span everything.

Transform: where feature engineering runs

Page 741 defines what the transform task runs. Feature engineering: "DEF: a machine learning approach that extracts features from a raw dataset, resulting in new features". It "ranges from basic transformations such as aggregations to more advanced feature transformations such as word embeddings produced by machine learning algorithms", and its goal is "to essentially create a better dataset to improve the performance of machine learning algorithms". Page 734 names the everyday steps: "aggregations, normalization, one-hot encoding".

The jobs "are executed on data processing engines (e.g. Spark or Pandas) to which the feature store is connected" (p. 766): the store orchestrates them, it does not replace Spark (lesson 38). Page 767 sorts them into three kinds, by when their input exists:

The three transform types of p. 767. The slide prints the fourth header as "Common input data source"; read it as "Example" (see the red pen below).
Feature typeDefinitionCommon input data sourceExample
Batch TransformTransformations that are applied only to data at restData warehouse, data lake, databaseUser country, product category
Streaming TransformTransformations that are applied to streaming sourcesKafka, Kinesis, PubSub# of clicks per vertical per user in last 30 minutes, # of views per listing in past hour
On-demand transformTransformations that are used to produce features based on data that is only available at the time of the prediction. These features cannot be pre-computed.User-facing applicationIs the user currently in a supported location? Similarity score between listing and search query

The vector served on p. 766 mixes all three, colour-coded on the slide: "item_clicks_last_5_mins":6 comes from a stream transform, "user_spend_last_30_days":"$1.10" from a batch transform, and "user_current_location":"US_NY" from an on-demand transform fed with the request's application data, {user_ip: "x.x.x.x"}. Why can't the third be precomputed? Its input — where the user is right now — exists only when the request arrives.

Monitoring and the registry

Monitoring (p. 768) tracks "operational metrics relating to core functionality": for storage "availability, capacity, utilization, staleness", for serving "throughput, latency, error rates". Keep it apart from the key component "Monitoring and Validation" (p. 736), which checks the feature values themselves so that "data drifts or anomalies are detected early". One watches the machine, the other the data.

The registry "is a central interface for user interactions with the feature store. Teams use the registry as a common catalog to explore, develop, collaborate on, and publish new definitions. The registry allows for important metadata to be attached to feature definitions" (p. 769). It holds definitions, not values. It is what makes reuse real: the "catalog or search functionality" of p. 736 lets the next data scientist find spend_l30d instead of writing it a third time.

Pages 734–736 list eight "Key Components". Each lives in one of the five tasks (the mapping is ours):

The eight key components of pp. 734–736 and the task of p. 763 that carries each.
Key componentIn the slide's wordsTask
1 Feature Storage"historical features (used for training models) and real-time features (used for serving live predictions)"Storage
2 Feature Engineering Pipeline"aggregations, normalization, one-hot encoding"Transform
3 Feature Versioning"critical in avoiding 'training-serving skew'"Registry
4 Online and Offline Storesbatch features for training; real-time features "with low latency"Storage
5 Feature Serving"training environments (batch mode) and production environments (real-time)"Serving
6 Data Governance & Access Control"who can create, access, or update certain features"Registry
7 Feature Discoverability and Reusability"a catalog or search functionality"Registry
8 Monitoring and Validation"data drifts or anomalies are detected early"Monitoring

Three tasks on the data path — transform, storage, serving — and two over all of them: monitoring and the registry.

Feast: entities, feature views and the point-in-time join

The deck ends with one technology in detail: Feast, "Feature Store for Machine Learning", "Type: Open-source" (p. 746). It was born at the ride-hailing company Gojek with Google Cloud and announced in January 2019 (Google Cloud blog) — the "Go-jek 2019" dot of p. 739. Its objects form a small tree (Fig. 4).

registry: the definitions Project Feature View driver_stats Feature Entity Data Source rating driver_id BigQuery table
Fig. 4. The project structure of p. 756: a project holds feature views, and each feature view binds its features, its entity and its data source. All of these are definitions kept in the registry (dashed); the data source only points to raw data that stays where you keep it (p. 759). The names driver_stats, rating and driver_id are the example of the next table.

Project — "Projects provide complete isolation of feature stores at the infrastructure level. This is accomplished through resource namespacing" (p. 757).

Entity — "a collection of semantically related features. Users define entities to map to the domain of their use case" (p. 758): a driver, a customer.

Feature view — "a collection of features" (p. 758), bound to its entities and to one data source.

Data source — "raw underlying data that users own (e.g. in a table in BigQuery). Feast does not manage any of the raw underlying data" (p. 759).

Registry — "Feast uses a registry to store all applied Feast objects (e.g. Feature views, entities, etc). The registry exposes methods to apply, list, retrieve and delete these objects" (p. 759).

A feature view maps to "0 or more entities" (p. 758): zero for a global feature ("num_daily_global_transactions"), one for a user feature ("user_age or last_5_bought_items"), several — "aka a composite key" — for a feature of a pair ("num_user_purchases_in_merchant_category", a user and a merchant category). "A collection of entities for a feature view is called an entity key", and "Entities should be reused across feature views", so that features about the same thing are found, and joined, on the same key.

Then the sentence the rest of this section unpacks: "Feast uses a time-series data model to represent data. This data model is used to interpret feature data in data sources in order to build training datasets or materialize features into an online store" (p. 759). Pages 760–761 show what its rows look like:

The time-series data model of pp. 760–761. Every row has a timestamp; each column is an entity or a feature, each cell an entity value or a feature value. The outlined pair is the entity key of row 1. (Page 760 is the same table without customer_id.)
rowtimestampcustomer_iddriver_idtrips_todayrating
timestampentityentityfeaturefeature
15/22/2021 0:00:00customer_Adriver_100154.8
25/22/2021 0:00:00customer_Bdriver_100204.2
35/22/2021 0:00:00customer_Cdriver_100384.5
45/22/2021 0:00:00customer_Ddriver_100434.2

The slides use "entity key" in two senses: the set of entities of a feature view (p. 758), and the pair of values that identifies one row, (customer_A, driver_1001) in the red frame of p. 761. Both are Feast's usage. In Feast's Python SDK the driver view of p. 760 is declared like this (adapted from the Feast documentation; not on the slides):

# a feature view: two features of the entity "driver",
# read from a BigQuery table
from datetime import timedelta
from feast import BigQuerySource, Entity, FeatureView, Field
from feast.types import Float32, Int64

driver = Entity(name="driver", join_keys=["driver_id"])

driver_stats = FeatureView(
    name="driver_stats",
    entities=[driver],
    ttl=timedelta(days=1),
    schema=[
        Field(name="trips_today", dtype=Int64),
        Field(name="rating", dtype=Float32),
    ],
    source=BigQuerySource(table="my-project.rides.driver_stats"),
)

Why the timestamp matters: the point-in-time join

Why insist on time? Build a training set for "will this trip end in a complaint?". The labels arrive as rows — driver, time of the trip, complaint yes or no — called the entity dataframe. To each row you must attach the driver's rating. A plain join on driver_id with today's table gives every row today's rating, including ratings computed after the trip, perhaps because of that very complaint. The model trains on information it will never have in production: data leakage. Its symptom is an offline score far better than anything production delivers.

Feast's documentation names the cure — the slides do not: "Feast performs a point-in-time join (also called a 'last known good value' temporal join): for each entity row, it retrieves the latest feature values with a timestamp at or before the entity row's event_timestamp." Without that rule, "features generated after the prediction time could leak into training data — effectively letting the model 'see the future'". In symbols:

\[ \tau^{*} = \max\,\{\, \tau_i : \tau_i \le t \,\} \] \[ \text{joined value} = v(k, \tau^{*}) \] \[ \text{null if}\ \ t - \tau^{*} \gt \text{ttl} \]
\(k,\ t\)
the entity key and the timestamp of one training row
\(\tau_i\)
the timestamps of the feature rows with the same key \(k\)
\(v(k, \tau)\)
the feature value of the row with key \(k\) and timestamp \(\tau\)
ttl
time to live of the feature view: how old a value may be and still count
  1. Take one row of the entity dataframe: key driver_1001, timestamp 5/22 10:00.

  2. Keep the feature rows with the same key: 4.6 (5/20), 4.7 (5/21), 4.8 (5/22), 4.9 (5/23), 4.9 (5/24), all at 0:00.

  3. Drop every row dated after 10:00 on 5/22: the two values 4.9 did not exist yet when the trip took place.

  4. Take the latest of what remains: \(\tau^{*}\) = 5/22 0:00, value 4.8 — the rating p. 760 prints for that day.

  5. Check its age against the ttl: 10 hours, inside a ttl of one day, so 4.8 is joined. Older than the ttl, the feature would be null — and null too if no rating were dated at or before 10:00.

The same rule explains the online store: materialization is the point-in-time join evaluated at "now" for every key — "the latest feature values for each entity" (p. 765). The widget builds the training set both ways. Its one insight: a training row may only see the past of its own timestamp, and a plain join quietly hands it the future.

Join the labels to the feature history

Three drivers and their daily rating (dots, values above them; 5/22 is the day of p. 760). Six labelled trips (crosses): did the trip end in a complaint? Each curved arrow shows which rating the join attaches to a trip, and the value it attaches is written under the trip. The table below is the training set. Ratings other than those of 5/22 and the trips are invented for the widget.

  1. With the naive join, predict how many of the six trips get a rating from their own future. Which trip, if any, is safe?
    What you should see

    Five of six. The naive join takes today's table, one value per driver — the ratings of 5/24 — and only the trip of driver_1003 on 5/25 at 20:00 happens after that update. A plain join is right only for rows newer than the last feature update, which in a training set is almost never.

  2. Switch to the point-in-time join. What does driver_1001's trip of 5/22 at 10:00 get, and why not 4.9?
    What you should see

    4.8, dated 5/22 0:00: the latest value at or before 10:00. The 4.9 values are dated 5/23 and 5/24 — they did not exist at 10:00 on 5/22. Leaks drop from 5 to 0.

  3. Look at the only complaint, driver_1002 on 5/22 at 20:00, in both modes. Which rating does each join give it, and why is the naive one dangerous?
    What you should see

    Naive: 3.8, computed on 5/24, after the complaint and possibly because of it. Point-in-time: 4.2, the rating the driver had when the trip began. A model trained on the 3.8 learns that low ratings come with complaints from numbers the complaint itself pushed down — and in production it only ever sees the rating before the trip. The offline score looks great; the live one does not.

  4. Point-in-time, set the ttl to 24 hours, then to 12. Which rows turn null each time?
    What you should see

    At 24 hours only the trip of 5/25 at 20:00: its latest rating is 44 hours old. At 12 hours five of six are null; only the trip of 5/22 at 10:00 keeps its value (10 hours old). A ttl trades coverage for freshness: an old value is not silently passed off as current.

In Feast the whole join is one call, and the online lookup another (Feast documentation; store is the FeatureStore of your project):

# the training set: one row per labelled trip,
# each row joined point-in-time
import pandas as pd

entity_df = pd.DataFrame({
    "driver_id": ["driver_1001", "driver_1002"],
    "event_timestamp": pd.to_datetime(
        ["2021-05-22 10:00", "2021-05-22 20:00"]),
    "complaint": [0, 1],
})
training_df = store.get_historical_features(
    entity_df=entity_df,
    features=["driver_stats:rating", "driver_stats:trips_today"],
).to_df()
# one vector of the latest values for one key, for a prediction now
features = store.get_online_features(
    features=["driver_stats:rating", "driver_stats:trips_today"],
    entity_rows=[{"driver_id": "driver_1001"}],
).to_dict()

A training row may only see feature values dated at or before its own timestamp; the online store is the same join, taken at "now".

Nine products, one history, five dimensions

Page 739 says where it all began: "First Experience in Uber, with Michelangelo platform." Fig. 5 redraws its timeline.

2017 2018 2019 2020 2021 Uber · Michelangelo Airbnb Hopsworks Go-jek Kaskada Tecton DoorDash · Abacus.AI Iguazio · AWS SageMaker Splice Machine · Molecula Databricks · Google · Alteryx Iterative.AI the first one Feast is born here
Fig. 5. The timeline of p. 739, one dot per row, with the years where the slide writes them. The slide spells Hopsworks "Hopworks". The note on Go-jek is ours: Feast was open-sourced by Gojek with Google Cloud in January 2019.

Pages 746–754 review nine products in one template, "Type" plus "Key Characteristics". Most traits repeat on every slide ("Online and Offline Stores", versioning, "real-time and batch"); what tells them apart is the type and one or two traits:

The nine feature stores of pp. 746–754, with the type as printed. Three open-source, one commercial, five proprietary. Tecton was acquired by Databricks in August 2025; at the exam, give the slide's type.
SystemTypeWhat sets it apart on its slide
1 Feast (p. 746)Open-sourcecloud-agnostic or on-premise; "Simple Design: Focuses on feature serving"; "Good for Startups/SMEs"
2 Hopsworks (p. 747)Open-source (with enterprise version)Spark, TensorFlow, Kubernetes; stores "backed by distributed systems like Apache Hive and MySQL"; RBAC and GDPR
3 Tecton (p. 748)Commercial"Built specifically for real-time machine learning"; automated batch and streaming pipelines; drift monitoring
4 AWS SageMaker Feature Store (p. 749)Proprietary (part of AWS SageMaker)S3, Redshift, Glue; IAM for access control
5 Databricks Feature Store (p. 750)Proprietary (part of Databricks)"Unified with Delta Lake"; feature lineage; native Spark
6 Google Vertex AI Feature Store (p. 751)Proprietary (part of Google Cloud)fully managed; BigQuery, Dataflow; drift and anomaly monitoring
7 Azure ML Feature Store (p. 752)Proprietary (part of Microsoft Azure)Data Lake, Azure Synapse; Azure Active Directory
8 Scribble Data Enrich (p. 753)Proprietarycustomizable enrichment pipelines; cloud-agnostic; "SME Focus"
9 Featureform (p. 754)Open-source"Declarative Feature Definitions"; multi-cloud; "Lightweight Design"

The course covers every family of systems "along 5 dimensions" (intro deck, slide 6). The feature-store slides do not fill them in; here is the profile their pages imply (ours):

A feature store along the five dimensions of the course.
DimensionFeature store
(1) data modelan entity-keyed time series: rows of entity key, timestamp and feature values, grouped into feature views and described in a registry (pp. 758–761)
(2) (declarative vs. imperative) query languagesdeclarative feature definitions (Feast's Python objects; Featureform's "Declarative Feature Definitions"), read through two SDK calls, get_historical_features and get_online_features (p. 762): lookups by key and point-in-time joins, no general query language
(3) data distributionthe offline store on a distributed warehouse or lake (S3, BigQuery, Snowflake, Redshift, Hadoop), the online store on a distributed key-value store (Redis, DynamoDB); materialization and push move data between them (pp. 735, 757, 765)
(4) non-functional aspectslow latency and freshness online, volume and history offline; online stores usually eventually consistent; operational metrics for storage and serving (pp. 765, 768)
(5) architectural solutionsfive tasks: transform (batch, streaming, on-demand), storage (offline and online), serving, monitoring, registry (p. 763)

So where does a feature store sit among the systems of this course? Above them:

A feature store is a layer over systems you already know, not a new storage engine.
SystemWhat it holdsHow you read itIts place in a feature store
Data warehouse or lake (lesson 23)historical tablesscans and aggregations over yearsthe offline store
Key-value store such as Redis (lesson 17)one value per keya GET by key, in millisecondsthe online store
Vector database (lessons 27–28)embeddings and an index over themnearest neighbours by similarityan embedding can be a feature, but the store looks it up by entity key, not by similarity
Stream processing (lesson 33)events as they arrivecontinuous transformsthe source of streaming features, pushed to both stores

Back to Uber. Michelangelo's shared features lived in HDFS/Hive for training and in Cassandra for online predictions, and the transformations each model applied to them were written in a small language whose "expressions are part of the model configuration and the same expressions are applied at training time and at prediction time" (Uber Engineering blog, 2017). One definition, so a feature is not computed twice; two stores, one for the history and one for the latest values, read by key. The second danger of the hook, reading a value at the wrong moment, is what the timestamps of the time-series model and the point-in-time join are for. That is why the "store" was never a new database: it is a layer of definitions over a data lake and a low-latency store. The deck's last sentence says the same: "a feature store acts as the backbone of the feature lifecycle in machine learning systems, enabling teams to efficiently manage and serve high-quality features across different stages of the ML pipeline, from model development to deployment" (p. 771).

A feature store is a layer — a registry of definitions over a warehouse for the history and a key-value store for the latest values — not a new kind of database.

Exam-style questions

Feature stores have appeared in no past paper, and the practical part of 2026/27 covers Neo4j, MongoDB, Elasticsearch, Redis and SparkQL: this lesson belongs to the theory part. Its questions come in the forms the readme of the past papers names — open-ended, multiple-choice, true or false — and wrong answers may carry a penalty, announced just before the exam.

Define training-serving skew as presented in the lecture. Explain why it arises in machine-learning systems, how a feature store prevents it, and how it differs from data drift.

Show model answer

Training-serving skew, also called online/offline skew, is the situation in which a model performs poorly because the features used in production differ from the ones used during training. It arises because features are required both in the modelling phase and in the production (deployment) phase of the lifecycle: when each phase has its own feature code, the code is duplicated and the two implementations can silently diverge, for example in the time window, in the handling of refunds or in the default for missing values. A feature store prevents it by keeping one registered and versioned definition per feature and one transformation pipeline, whose results are stored in an offline store, which provides historical values for training, and in an online store, which provides the latest values with low latency for inference, both accessed through one serving API. In this way the same feature transformations are applied in training and in production. Data drift is different: the distribution of the input data changes over time while the computation stays the same; a feature store can detect drift by monitoring the features, but the remedy is retraining.

A complete answer has three parts: the definition in the slide's words (p. 734, with the synonym of p. 743), the cause — two code paths for one feature (p. 743) — and the mechanism: one definition, two stores. The contrast with drift shows understanding rather than memory.

In a feature store, which component typically stores only the latest feature values for each entity and is usually eventually consistent?

  • The offline store It keeps "months' or years' worth of feature data for training purposes" (p. 765): the history, not only the latest values.
  • The registry The registry holds definitions and their metadata (p. 769), not feature values.
  • The online store "They typically only store the latest feature values for each entity" and "Online stores are usually eventually consistent" (p. 765).
  • The data source In Feast it is the raw data the users own; "Feast does not manage any of the raw underlying data" (p. 759).
Show model answer

The online store. It persists the latest feature value of each entity for low-latency lookups during inference, usually in a key-value store such as Redis or DynamoDB, and it is usually eventually consistent. The offline store keeps months or years of history for training.

Every distractor is another component of the same architecture; the two properties in the question are the ones p. 765 gives the online store.

True or false: in Feast, for offline use cases that rely only on batch data, the data must first be ingested into the feature store.

  • True The slide says the opposite: "Feast does not need to ingest data and can query your existing data" (p. 757).
  • False Ingestion is for online use cases: materialization from batch sources and pushing of streaming features (p. 757).
Show model answer

False. For offline use cases that rely only on batch data, Feast does not need to ingest data and queries the existing data in place. Data are ingested only for online use cases: batch features are materialized into the online store, and streaming features are pushed to make them available both offline and online.

A true/false item is easy to build by flipping one slide sentence. With a possible penalty for wrong answers, answer only what the sentence of p. 757 supports.

In Feast, what are an entity, a feature view and an entity key? Give an example of a feature view with zero entities, one with one entity and one with several entities, and explain why Feast uses a time-series data model.

Show model answer

An entity is a collection of semantically related features, defined by the users to map to the domain of their use case, for example a driver or a customer. A feature view is a collection of features, bound to its entities and to a data source; it maps to zero or more entities. A collection of entities for a feature view is called an entity key; in the data, the entity key of a row is the tuple of its entity values, for example (customer_A, driver_1001). Zero entities: a global feature such as num_daily_global_transactions. One entity: a user feature such as user_age or last_5_bought_items. Several entities, a composite key: num_user_purchases_in_merchant_category, for a user and a merchant category. Feast uses a time-series data model, in which every row carries a timestamp, the entity values and the feature values, in order to build training datasets and to materialize features into an online store: the timestamps let a training row receive the latest feature values at or before its own time, without values from the future, and they tell materialization which value is the latest.

The definitions are p. 758 almost word for word, the examples too; the composite key is the part that is easiest to forget. The last sentence goes beyond the slides (point-in-time correctness is in the Feast documentation): it shows why p. 759 insists on time.

Which of the following features can only be produced by an on-demand transformation? Select all that apply.

  • User country Data at rest: a batch transform (p. 767).
  • Number of views per listing in the past hour Computed continuously from a stream (Kafka, Kinesis, PubSub): a streaming transform.
  • Whether the user is currently in a supported location It depends on "data that is only available at the time of the prediction" — where the user is now (p. 767).
  • The similarity score between a listing and the search query The query exists only when the request arrives: "These features cannot be pre-computed" (p. 767).
  • Product category A property of data at rest: a batch transform.
Show model answer

The third and the fourth. On-demand transformations produce features from data that is only available at the time of the prediction, coming from the user-facing application, so they cannot be pre-computed. User country and product category come from batch transformations of data at rest; views per listing in the past hour come from a streaming transformation.

The examples are p. 767's own, so a question can use them verbatim. The test to apply: does the input exist before the request arrives? If it does, the feature can be precomputed.

Consider the ER scenario of the exam of 12 Sep 2025, tracking farmers and their sales at local markets: People (Personal ID, Name, Surname, Age, Address, State) Buy Products (Product ID, Name, Quantity, Expiration Date), with a Buy Date and an Amount; Products are sold at Markets (Name, Location, Opening Time, Closing Time, Size).

A cooperative wants two models: (a) every night, predict for each product the amount that will be bought the next day; (b) at the moment a person pays, decide whether the purchase is fraudulent. Using a feature store, propose for each model its entity key and features of the three transformation types where they fit, say which store serves each prediction, and which Feast retrieval method is used for training and for prediction.

Show model answer

(a) Entity Product, entity key Product ID. Batch features computed from the history of Buy: the total Amount bought in the last 7 days, the number of days to the Expiration Date. Training: get_historical_features with an entity dataframe of (Product ID, date) rows labelled with the amount of the next day, so that each row is joined with the feature values at or before its date. The nightly prediction for all products is a batch prediction: it also uses get_historical_features on the offline store; no low latency is needed.

(b) Entity Person, entity key Personal ID. Batch feature: Age. Streaming feature: the number of purchases of this person in the last 10 minutes, computed from the stream of Buy events and pushed to both stores. On-demand feature: whether the market of the payment is open at the time of the payment, computed at request time from the request data and the market's Opening Time and Closing Time; it cannot be precomputed. Training: get_historical_features on past purchases labelled fraudulent or not. Prediction: get_online_features for the Personal ID, served by the online store with the latest values and low latency, plus the on-demand transformation at request time.

Ours, not a past-paper exercise: the scenario is borrowed to practise the vocabulary in context. The trap is (a): a nightly prediction is offline, exactly as "Predicting user churn for all users on a daily basis" on p. 762, so it uses get_historical_features, not the online store.

According to the lecture, which of these feature stores are open-source? Select all that apply.

  • Feast "Type: Open-source" (p. 746).
  • Tecton "Type: Commercial" (p. 748).
  • Hopsworks "Type: Open-source (with enterprise version)" (p. 747).
  • AWS SageMaker Feature Store "Proprietary (part of AWS SageMaker)" (p. 749).
  • Featureform "Type: Open-source" (p. 754).
  • Databricks Feature Store "Proprietary (part of Databricks)" (p. 750).
Show model answer

Feast, Hopsworks and Featureform. Tecton is commercial; AWS SageMaker, Databricks, Google Vertex AI and Azure ML feature stores are proprietary parts of their platforms, and Scribble Data Enrich is proprietary too.

Pure recall of pp. 746–754: three open-source, one commercial, five proprietary. Hopsworks is the one to hesitate on — the slide types it as open-source with an enterprise version.

Check yourself

A fraud model scores very well on its offline test set and clearly worse in production from its first day. Nothing in the world has changed. What is the most likely cause?

  • Concept drift Drift needs time and a changing world; this gap is there from day one.
  • The online store is only eventually consistent Values a few seconds old explain small differences on a few requests, not a gap from the first day on.
  • The features reach the model in production through different code, or the training set leaked future values Training-serving skew (p. 734) and leakage both make offline scores promise what production cannot deliver — check both.
  • The registry is missing A missing catalog hurts reuse and discovery, not the values a deployed model receives.

driver_1001 has ratings 4.6 (5/20 0:00), 4.7 (5/21 0:00), 4.8 (5/22 0:00) and 4.9 (5/23 0:00). A training row is dated 5/22 10:00. Which rating does a point-in-time join attach?

  • 4.9 Dated 5/23: at 10:00 on 5/22 it did not exist yet. That is the naive join's leak.
  • 4.8 The latest value at or before 5/22 10:00 — the rating p. 760 prints for 5/22.
  • 4.75, the average of the two values around 10:00 A point-in-time join picks one dated value; it does not interpolate.
  • 4.7 Before 10:00, but not the latest: 4.8, dated 5/22 0:00, is later and still in the past.

Which statements about the offline store are true? Select all that apply.

  • It keeps months or years of feature values, for training "months' or years' worth of feature data for training purposes" (p. 765).
  • It answers one lookup by key in milliseconds during inference That is the online store: "low-latency lookup during inference" (p. 765).
  • It is often a data warehouse or data lake such as S3, BigQuery, Snowflake or Redshift The list of p. 765.
  • In Feast, batch data must be ingested into it before it can be queried "Feast does not need to ingest data and can query your existing data" (p. 757).
  • It is typically refreshed at regular intervals, such as daily or weekly "updated at regular intervals (e.g., daily or weekly)" (p. 735).

History and scans offline, the latest value and lookups online: the two stores answer two different questions.

Why can an online store afford to be only eventually consistent?

  • Because every value is also kept in the offline store A copy elsewhere does not make a stale value fresh; the question is whether staleness matters.
  • Because it stores no history, so there is nothing to keep consistent It stores the latest value of every key, and its replicas can still disagree for a moment.
  • Because a single client reads it Every prediction service reads it, often from many machines at once.
  • Because a prediction made on a value a few seconds old is still useful, while a slow answer is not Latency and availability matter more than strict consistency for most ML uses — the BASE side of lesson 5.

A Feast feature view computes num_user_purchases_in_merchant_category. What is its entity key?

  • The pair (user, merchant category): a composite key "multiple entities, aka a composite key" (p. 758).
  • None: it is a global feature Global features such as num_daily_global_transactions have zero entities; this one depends on who buys and where.
  • The user alone A user feature like user_age has one entity; this one also depends on the merchant category.
  • The timestamp Every row has one, but the timestamp is not part of the entity key.

What does materialization do in Feast?

  • It computes on-demand features when a request arrives That is the on-demand transform, inside serving (p. 763).
  • It pushes streaming features to both stores That is pushing, the other half of p. 757.
  • It copies the latest feature values from batch sources into the online store "ingesting features from batch sources to make them available online (through a process called materialization)" (p. 757).
  • It stores the feature definitions in the registry Definitions are applied to the registry (p. 759); materialization moves values, not definitions.

A data scientist is about to write spend_l30d from scratch, although a colleague wrote it last year. Which task of the feature store should have stopped her?

  • Monitoring Operational monitoring watches availability, latency and the like (p. 768), not who writes what.
  • The registry "a common catalog to explore, develop, collaborate on, and publish new definitions" (p. 769) — the discoverability of p. 736.
  • Storage Storage holds the values; finding a definition is the catalog's job.
  • The on-demand transform It computes request-time features; it has nothing to do with reuse.

Key take-aways

What to watch and read