Acumatica · Feature-store

Feature Store Patterns — A Field Guide

Feature Store Patterns — A Field Guide is the work that turns raw data into decisions. The pipeline from "we have data" to "we have a model that runs in production" is the same in.

John Kihiu12 min read

A feature store is often described as "a database for ML features," which undersells the actual problem it solves: keeping the feature values a model sees in training identical in derivation to the ones it sees in production, while serving the production path fast enough for real-time inference. These are the patterns that hold up once a team has more than one model consuming shared features.

The dual-write path: offline and online

Every mature feature store pattern splits into two paths that must stay consistent: an offline path optimized for throughput (building large historical training sets via batch joins) and an online path optimized for latency (single-entity lookups in milliseconds for live inference). The pattern that fails is building only the offline path and bolting a cache in front of production application code later — the two implementations drift apart, silently, the moment someone tweaks one without the other.

Entity-centric feature modeling

Features are modeled around an entity and a join key — customer, product, session — not around a specific model. This is what makes reuse possible: a "days since last purchase" feature computed once for the customer entity should serve a churn model, a recommendation model, and a fraud model without three separate implementations. Model features against the entity, not the use case, and reuse follows naturally.

Reuse is the return on investment

A feature store pays for its operational overhead only when features get reused across multiple models or pipelines. If every model has its own bespoke features with no overlap, a shared registry adds cost without the corresponding benefit — a well-organized feature library in code may be enough.

Point-in-time joins for training data

Building a training set means, for every labeled example, pulling the feature values as they existed at that example's timestamp — not the latest values. Naive joins on entity ID alone leak future information into training rows. The pattern is an as-of join: for each (entity, timestamp) pair in the label set, retrieve the most recent feature value at or before that timestamp. This is the single hardest correctness property to get right by hand, which is why dedicated tooling (Feast, Tecton, or a homegrown as-of join in Spark/SQL) exists.

SQL · AS-OF JOIN PATTERN
SELECT l.entity_id, l.label, l.event_timestamp, f.feature_value
FROM labels l
LEFT JOIN LATERAL (
  SELECT feature_value
  FROM features f
  WHERE f.entity_id = l.entity_id
    AND f.feature_timestamp <= l.event_timestamp
  ORDER BY f.feature_timestamp DESC
  LIMIT 1
) f ON true;

Freshness and materialization trade-offs

Online stores are populated by materializing feature values from the offline store on a schedule, or by streaming updates directly. Batch materialization (hourly or daily) is cheap and sufficient for slowly changing features like lifetime purchase count. Streaming materialization is expensive to build and operate but necessary for features that must reflect events from seconds ago — current session activity, live inventory. Match the materialization strategy to how stale the feature is allowed to be, not to what's technically impressive.

Schema drift breaks both paths silently

If the offline source table adds a column or changes a type without updating the feature view definition, the online store can serve a different shape of data than training saw. Version feature definitions and validate schema on materialization, not just at model training time.

When not to build one

A single-model team with one training pipeline and one serving path does not have a training/serving skew problem yet — a shared feature computation library, tested once and imported in both places, solves the same consistency issue with far less infrastructure. Reach for a feature store pattern when a second model or a second consumer shows up and duplicated feature logic starts drifting.

Wrapping up

The patterns that matter are entity-centric modeling for reuse, point-in-time-correct joins for training data, and a materialization strategy matched to actual freshness needs — not the specific tool. Build or adopt this machinery once duplicated feature logic across models becomes a real, observed source of drift, not before.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.