Skip to content

Entity and feature view record layout

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

This page explains how the Aerospike online store maps Feast entities and feature views to records, and what that layout means for writes, reads, and TTL.

On the overview page, you saw that Feast copies feature values from an offline store into an online store through materialization, and reads them back with get_online_features. The Aerospike online store maps every feature view for one entity to a single Aerospike record.

In the logistics example, driver_stats holds recent delivery statistics and pricing holds the demand adjustment. The two teams update their views independently, while the assignment request reads both for the same driver.

You do not configure this layout directly. Your feature view definitions and feast materialize calls stay the same no matter how many feature views share an entity.

Benefits and boundaries

Collocating feature views on one record per entity reduces the number of record keys and primary index (PI) entries you maintain as feature views grow. That is the main storage benefit of this layout.

The tradeoff is that independently updated feature views share one write target. A write that replaced the entire features map could replace another feature view’s values. The integration avoids that by using Map CDT operations that update only the targeted feature view’s map entries.

Collocated feature views also share a record-level time to live (TTL). Every write applies ttl_seconds in feature_store.yaml to the entire Aerospike record, not to an individual feature view. In this implementation, feature views on the same record do not expire independently at the storage layer.

FeatureView.ttl does not provide a separate expiry for standard Aerospike online reads. It controls Feast materialization lookback and historical point-in-time retrieval.

Feast still issues one online_read call per feature view. Each call reads from the shared entity record key, but collocation does not reduce the number of read calls.

What the record holds

Each feature view gets its own key inside a shared map in the features and event_ts bins. A write to driver_stats touches only the driver_stats key and leaves pricing untouched. Understanding this structure explains what you see when you inspect a record directly in the verify step.

In Aerospike, data is organized as:

  • Namespaces contain sets. A namespace is the top-level data container with its own storage policy (memory, flash, or hybrid).
  • Sets contain records, similar to a table. Sets are optional, and records can exist without one.
  • Records contain bins. Each record is identified by a key.
  • Bins are named fields on a record, similar to columns. A bin can hold a scalar value or a collection type like a Map CDT.

Feast stores feature data in key-ordered Map CDT bins (MAP_KEY_ORDERED).

Bin nameContents
featuresA Map CDT keyed by feature view name. Each value is a map of feature name to its stored value.
event_tsA Map CDT keyed by feature view name. Each value is the event timestamp, in milliseconds since the Unix epoch, for that feature view’s most recently materialized row.
created_tsA single write timestamp, present only when the offline source row includes a created_timestamp column. Not written on every record.

All records for one Feast project live in the same Aerospike set by default, named <project>_latest. The Aerospike user key for each record is the entity’s join key serialized as a byte array by Feast (controlled by entity_key_serialization_version). If you inspect the key directly with aql or the Python client you see binary bytes, not the raw driver_id value. For a given driver_id, every feature view serializes the same join key to the same byte array, so the views write to the same record.

For example, a record holding features from driver_stats and pricing for one driver looks like this:

bins:
features:
driver_stats:
rating: 4.91
trips_last_7d: 132
pricing:
surge_multiplier: 1.2
event_ts:
driver_stats: 1737374400000
pricing: 1737447000000
created_ts: 1737460805000 # only when offline rows include created_timestamp

For the full Aerospike-to-Feast mapping (namespace, set, key, and bins), see Data model in the Aerospike online store reference.

How materialization writes work

Each feast materialize or feast materialize-incremental run writes only the feature view, or views, you specify. Because feature views share a record, the online store uses a partial upsert: an Aerospike Map CDT operation that updates only that feature view’s key inside the features and event_ts maps. Two materialization jobs writing different feature views for the same entity each mutate only their own map key.

How reads work with a shared record

Feast calls online_read once per feature view when handling a get_online_features request. For requests containing at most batch_max_records entities (1,000 by default), each online_read issues one batch_operate that reads the requested feature view’s map key. Larger requests issue one batch_operate per entity chunk. Collocation does not combine the feature-view calls.

If you isolate a feature view onto its own Aerospike set using set_overrides, that view’s reads go to a different set. Reads spanning the isolated set and others then target multiple sets instead of one shared record.

Namespace overrides and collocation

Collocation applies only within one namespace and set.

Feast can route feature views to different namespaces through namespace_overrides in feature_store.yaml. Once two feature views land on different namespaces, their records live in separate Aerospike namespaces. Feast still issues one online_read per feature view, with one or more batch_operate calls depending on entity count. Each call goes to the namespace where that view is stored. A FeatureService that spans namespaces is more resource-intensive than one limited to a single namespace.

See Tutorial: Route hot and cold Feast features to memory and flash for how to configure and reason about namespace routing.

On the next page, you define a driver entity with two feature views and materialize them into Aerospike.