Online store. One row, right now, latency-critical → a low-latency key-value store such as Redis or DynamoDB.
Why: the offline store (Parquet on S3, BigQuery) is built for scanning millions of rows cheaply, not for a single sub-10ms lookup.
Recall Solution L1.2
(b) Training-serving skew. Two code paths (foff and fon) produce different values from the same raw input.
Detectable offline?No — offline metrics only see foff. The model looks fine until it meets fon in production.
Recall Solution L1.3
"Among all feature observations recorded at or before the label time te, pick the most recent one." The ti≤te part forbids the future; the argmax part picks the freshest survivor.
Step 1 (filter, ti≤te): keep 08:00 and 09:15. Drop 11:40 — it is in the future of the event (using $500 would be Data leakage).
Step 2 (argmax): of {08:00, 09:15}, the largest is 09:15.
Answer: $50.
Recall Solution L2.2
Allowed window: te−τ≤ti≤te, i.e. 09:30≤ti≤10:00.
Check each survivor from L2.1: 09:15 is 45 min old >30; 08:00 is 120 min old. Neither is inside the window.Answer: null / default. The model must explicitly handle "no fresh feature," rather than trusting a stale $50.
Recall Solution L2.3
The filter is ti≤te — the ≤ is inclusive, so ti=teis allowed (it was known at the instant of the event). The 12:00 value is rejected.
With two equal timestamps at 10:00, ties are broken by an ingestion order / row id chosen by the feature store; both are equally "freshest," so implementations pick a deterministic one (e.g. last-written). Answer: one of the 10:00 values (not 12:00).
Apply filter-then-argmax per event. See the step-function figure below — the served value is a staircase that only ever steps at an observation time and holds flat until the next one.
13:00: window [11:30,13:00] → 12:00 is 60 min old, valid → $90 (unchanged).
Trick answer: none change at τ=90. Now push TTL to τ=30:
13:00: 12:00 is 60 min old >30 → null. This is the one that flips.
Recall Solution L3.3
Access pattern mismatch. Training scans millions of rows of history (throughput-bound); serving needs one key, <10 ms (latency-bound). No single engine is best at both — see Batch vs streaming pipelines.
Cost / storage shape. Offline keeps full history cheaply (columnar Parquet/BigQuery); online keeps only the latest value per entity in memory-fast KV (Redis/DynamoDB). Storing full history in Redis is wasteful; scanning Parquet per request is too slow.
What syncs them:materialization — the job that copies computed feature values from offline into online, so both derive from one definition.
Zero skew ⟺foff(x)=fon(x)∀x.
A feature store enforces this by registering a single feature definition and either (a) running that one definition in both paths, or (b) materializing the offline result straight into the online store so serving is a pure lookup, not a recomputation. Equality then holds structurally — you never rely on two hand-written implementations happening to agree.
Recall Solution L4.2
Define the entityuser with join key user_id.
Register each feature (e.g. 7d_login_count) inside a feature view with a data source and TTL — one definition, so Feature engineering logic isn't duplicated.
Build the training set with a point-in-time join: for each churn label at te, attach features with ti≤te (freshest). This blocks future leakage.
Materialize the same definitions' latest values into the online store.
Bundle the model's features into a feature service; at inference, look them up — no recompute → offline path = online path, so skew =0. Ties into Model deployment.
Recall Solution L4.3
In-memory KV store (Redis) for <5 ms at high QPS (DynamoDB also viable at scale). Because the streaming source updates continuously, a gap (upstream outage) can leave the last value stale — set a TTL so a value older than τ returns null instead of silently serving a frozen click rate.
With ti<11:00: allowed = {09:00, 10:30}. Freshest = 10:30 → $40.
But 10:30 is after the event at 10:00 — that observation did not exist at prediction time. The correct value is $100 (the 09:00 one).
Failure: future leakage / Data leakage. Widening the upper bound past tealways risks pulling in post-event observations. The upper bound must be exactly te (≤), never te+ε.
Recall Solution L5.3
No — the 12:20 value hasn't been materialized (next batch run is 13:00), so serving returns the pre-12:20 value. This is materialization lag.
Lever: switch that feature to a streaming materialization path (Batch vs streaming pipelines) so writes to the online store happen near-real-time.
Trade-off: streaming adds infrastructure complexity and cost, and can reintroduce skew if the streaming transform differs from the offline one — so the streaming path must reuse the same registered definition.
Recall Self-test checklist
The filter uses which comparison, strict or inclusive? ::: Inclusive, ti≤te — a value known at the event instant is allowed.
After filtering, which observation do you keep? ::: The freshest, i.e. the one maximising ti (argmax).
What makes zero skew structural rather than tested? ::: One registered definition + materialization, so foff=fon by construction.
When does TTL return null? ::: When even the freshest allowed observation is older than τ (i.e. te−ti>τ).