Chapter 3. Defining machine learning features


As part of the Feature Store workflow, machine learning (ML) engineers or data scientists are responsible for identifying data sources and defining features of interest.

3.1. Setting up your working environment

You must set up your Red Hat OpenShift AI working environment so that you can use features in your machine learning workflow.

Prerequisites

  • You have access to the OpenShift AI project in which your cluster administrator has set up the Feature Store instance.

Procedure

  1. From the OpenShift AI dashboard, click Projects.
  2. Click the name of the project in which your cluster administrator has set up the Feature Store instance.
  3. In the project in which the cluster administrator set up Feature Store, create a workbench, as described in Creating a workbench.
  4. To open the IDE (for example, JuypterLab), in a new window, click the open icon ( The open icon ) next to the workbench.
  5. Add a feature_store.yaml file to your notebook environment. For example, upload a local file or clone a Git repo that contains the file, as described in Uploading an existing notebook file to JupyterLab from a Git repository by using the CLI.
  6. Open a new Python notebook.
  7. In a cell, run the following command to install the feast CLI:

    ! pip install feast

Verification

  1. Run the following command to list the available features:

    ! feast features list

    The output should show a list of features, Feature View and data type similar to the following:

    Feature	Feature         View          Data Type
    credit_card_due	        credit_history			Int64
    mortgage_due	        credit_history			Int64
    student_loan_due	    credit_history			Int64
    vehicle_loan_due	    credit_history			Int64
    city			        zipcode_features		String
    state			        zipcode_features		String
    location_type		    zipcode_features		String
  2. Optionally, run the following commands to list the registered feast projects, feature views, and entities.

    ! feast projects list
    
    ! feast feature-views list
    
    ! feast entities list

3.2. About feature definitions

A machine learning feature is a measurable property or field within a data set that a machine learning model can analyze to learn patterns and make decisions. In Feature Store, you define a feature by defining the name and data type of a field.

A feature definition is a schema that includes the field name and data type, as shown in the following example:

from feast import Field
from feast.types import Int64

credit_card_amount_due = Field(
    name="credit_card_amount_due",
    dtype=Int64
)

For a list of supported data types for fields in Feature Store, see the feast.types module in the Feast documentation.

In addition to field name and data type, a feature definition can include additional metadata, specified as descriptions of features, as shown in the following example:

from feast import Field
from feast.types import Int64


credit_card_amount_due = Field(
    name="credit_card_amount_due",
    dtype=Int64,
    description="Credit card amount due for user",
    tags={"team": "loan_department"},
)

3.3. Understanding Feature Store data types

Feature Store supports multiple data types for building features for real-time model serving and maintaining compliance with data handling regulations.

3.3.1. Data type categories

Feature Store organizes data types into six categories:

Primitive types
Basic scalar values such as integers, floats, strings, booleans, timestamps, and UUIDs.
Array types
Ordered lists of values for any primitive type.
JSON types
Opaque JSON data stored as strings at the protocol buffer level, with native JSON support in compatible backends.
Map types
Dictionary-like structures with string keys and values of any supported Feature Store type, including nested maps.
Set types
Collections of unique values for any primitive type. Duplicates are automatically removed.
Struct types
Schema-aware structured types with named, typed fields. Unlike maps, structs declare field names and types for schema validation.

3.3.2. Choosing data types

Consider backend compatibility and performance when selecting data types. Different backends provide varying levels of native support for complex types such as JSON, Map, and Struct. For complete type specifications, backend support tables, and usage examples, see Feature Store data type reference.

Additional resources

3.4. Feature Store data type reference

You can reference the data type specifications, backend support tables, and usage examples for Feature Store.

3.4.1. Primitive data types

The following table represents all the primitive data types that Feature Store supports:

Expand
Feature Store TypePython TypeDescription

Int32

int

32-bit signed integer

Int64

int

64-bit signed integer

Float32

float

32-bit floating point

Float64

float

64-bit floating point

String

str

string/text value

Bytes

bytes

Binary data

Bool

bool

Boolean value

UnixTimestamp

datetime

Unix timestamp (nullable)

Uuid

uuid.UUID

UUID (any version)

TimeUuid

uuid.UUID

Time-based UUID (version 1)

Decimal

decimal.Decimal

Arbitrary-precision decimal number

3.4.2. Array data types

All primitive types have corresponding array types for storing lists of values. The following table shows the available array data types:

Expand
Feature Store typePython typeDescription

Array(Int32)

List[int]

A list of 32-bit integers.

Array(Int64)

List[int]

List of 64-bit integers

Array(Float32)

List[float]

List of 32-bit floats

Array(Float64)

List[float]

List of 64-bit floats

Array(String)

List[str]

List of strings

Array(Bytes)

List[bytes]

List of binary data

Array(Bool)

List[bool]

List of booleans

Array(UnixTimestamp)

List[datetime]

List of timestamps

Array(Uuid)

List[uuid.UUID]

A list of UUIDs.

Array(TimeUuid)

List[uuid.UUID]

List of time-based UUIDs

Array(Decimal)

List[decimal.Decimal]

List of arbitrary-precision decimals

3.4.3. JSON data types

The JSON type represents opaque JSON data. Unlike a Map, which provides schema-free key-value storage, the system stores JSON as a string at the protobuf level. However, backends use native JSON types when available. The following table provides the type, Python type and description:

Expand
Feature Store TypePython TypeDescription

JSON

str (JSON-encoded)

JSON data stored as a string in protocol buffers.

Array(Json)

List[str]

A list of JSON-encoded strings.

3.4.3.1. Backend support for JSON data types

The following table shows the native types that each backend uses to support JSON data types:

Expand
BackendNative type

PostgreSQL

jsonb

Snowflake

JSON / VARIANT

Redshift

json

BigQuery

JSON

Spark

Not natively distinguished from String

MSSQL

nvarchar(max)

Note

If the native type of a backend is ambiguous, such as when PostgreSQL jsonb could be Map or JSON, the schema-declared Feature Store type takes precedence. Feature Store uses the backend-to-Feast mappings only during schema inference when you do not provide an explicit type.

3.4.4. Map data types

You can store dictionary-like data structures using map data types. The following table shows the available map data types:

Expand
Feature Store TypePython TypeDescription

Map

Dict[str, Any]

A dictionary with string keys and values of any supported Feature Store type, including nested maps.

Array(Map)

List[Dict[str, Any]]

A list of dictionaries.

Note

You must use strings for map keys, but you can use any supported Feature Store type for map values, such as primitives, arrays, or nested maps.

3.4.4.1. Backend support for map data types

The following table shows the native types that each backend uses to support map data types:

Expand
BackendNative TypeNotes

PostgreSQL

jsonb, jsonb[]

jsonb Map, jsonb[] Array(Map)

Snowflake

VARIANT, OBJECT

Inferred as Map

Redshift

SUPER

Inferred as Map

Spark

map<string,string>

map<> Map, array<map<>> Array(Map)

Athena

map

Inferred as Map

MSSQL

nvarchar(max)

Serialized as string

DynamoDB / Redis

Proto bytes

Full proto Map support

3.4.4.2. Map type usage examples

You can use maps to store complex nested data structures. The following table shows several map options:

# Simple map
user_preferences = {
    "theme": "dark",
    "language": "en",
    "notifications_enabled": True,
    "font_size": 14
}

# Nested map
metadata = {
    "profile": {
        "bio": "Software engineer",
        "location": "San Francisco"
    },
    "stats": {
        "followers": 1000,
        "posts": 250
    }
}

# List of maps
activity_log = [
    {"action": "login", "timestamp": "2024-01-01T10:00:00", "ip": "192.168.1.1"},
    {"action": "purchase", "timestamp": "2024-01-01T11:30:00", "amount": 99.99},
    {"action": "logout", "timestamp": "2024-01-01T12:00:00"}
]

3.4.5. Set data types

All primitive types have corresponding set types to store unique values. The following table shows the available set data types:

Expand
Feature Store typePython typeDescription

Set(Int32)

Set[int]

Set of unique 32-bit integers

Set(Int64)

Set[int]

Set of unique 64-bit integers

Set(Float32)

Set[float]

Set of unique 32-bit floats

Set(Float64)

Set[float]

Set of unique 64-bit floats

Set(String)

Set[str]

Set of unique strings

Set(Bytes)

Set[bytes]

Set of unique binary data

Set(Bool)

Set[bool]

Set of unique booleans

Set(UnixTimestamp)

Set[datetime]

Set of unique timestamps

Set(Uuid)

Set[uuid.UUID]

Set of unique UUIDs

Set(TimeUuid)

Set[uuid.UUID]

Set of unique time-based UUIDs

Set(Decimal)

Set[decimal.Decimal]

Set of unique arbitrary-precision decimals

Note

When you convert lists or other iterables to sets, the set automatically removes duplicate values.

3.4.6. Struct data types

The Struct type provides a data structure with named, typed fields. You must declare field names and their types to enable schema validation. The following table shows the available struct data types:

Expand
Feature Store TypePython TypeDescription

Struct({"field": Type, …​})

Dict[str, Any]

This includes named fields with typed values.

Array(Struct({"field": Type, …​}))

List[Dict[str, Any]]

A list of structs.

Struct data types example

from feast.types import Struct, String, Int32, Array

# Struct with named, typed fields
address_type = Struct({"street": String, "city": String, "zip": Int32})
Field(name="address", dtype=address_type)

# Array of structs
items_type = Array(Struct({"name": String, "quantity": Int32}))
Field(name="order_items", dtype=items_type)

3.4.6.1. Backend support for struct data types

The following table shows the native types that each backend uses to support struct data types:

Expand
BackendNative Type

BigQuery

STRUCT / RECORD

Spark

struct<…​> / array<struct<…​>>

PostgreSQL

jsonb (serialized)

Snowflake

VARIANT (serialized)

MSSQL

nvarchar(max) (serialized)

DynamoDB / Redis

Proto bytes

3.4.7. Complete feature view example

The following example demonstrates a feature view that uses multiple data types:

from datetime import timedelta
from feast import Entity, FeatureView, Field, FileSource
from feast.types import (
    Int32, Int64, Float32, Float64, String, Bytes, Bool, UnixTimestamp,
    Uuid, TimeUuid, Decimal, Json, Array, Set, Map, Struct
)

# Define a data source
user_features_source = FileSource(
    path="data/user_features.parquet",
    timestamp_field="event_timestamp",
)

# Define an entity
user = Entity(
    name="user_id",
    description="User identifier",
)

# Define a feature view with all supported types
user_features = FeatureView(
    name="user_features",
    entities=[user],
    ttl=timedelta(days=1),
    schema=[
        # Primitive types
        Field(name="age", dtype=Int32),
        Field(name="account_balance", dtype=Int64),
        Field(name="transaction_amount", dtype=Float32),
        Field(name="credit_score", dtype=Float64),
        Field(name="username", dtype=String),
        Field(name="profile_picture", dtype=Bytes),
        Field(name="is_active", dtype=Bool),
        Field(name="last_login", dtype=UnixTimestamp),
        Field(name="session_id", dtype=Uuid),
        Field(name="event_id", dtype=TimeUuid),
        Field(name="price", dtype=Decimal),

        # Array types
        Field(name="daily_steps", dtype=Array(Int32)),
        Field(name="transaction_history", dtype=Array(Int64)),
        Field(name="ratings", dtype=Array(Float32)),
        Field(name="portfolio_values", dtype=Array(Float64)),
        Field(name="favorite_items", dtype=Array(String)),
        Field(name="document_hashes", dtype=Array(Bytes)),
        Field(name="notification_settings", dtype=Array(Bool)),
        Field(name="login_timestamps", dtype=Array(UnixTimestamp)),
        Field(name="related_session_ids", dtype=Array(Uuid)),
        Field(name="event_chain", dtype=Array(TimeUuid)),
        Field(name="historical_prices", dtype=Array(Decimal)),

        # Set types (unique values only)
        Field(name="visited_pages", dtype=Set(String)),
        Field(name="unique_categories", dtype=Set(Int32)),
        Field(name="tag_ids", dtype=Set(Int64)),
        Field(name="preferred_languages", dtype=Set(String)),
        Field(name="unique_device_ids", dtype=Set(Uuid)),
        Field(name="unique_event_ids", dtype=Set(TimeUuid)),
        Field(name="unique_prices", dtype=Set(Decimal)),

        # Map types
        Field(name="user_preferences", dtype=Map),
        Field(name="metadata", dtype=Map),
        Field(name="activity_log", dtype=Array(Map)),

        # Nested collection types
        Field(name="weekly_scores", dtype=Array(Array(Float64))),
        Field(name="unique_tags_per_category", dtype=Array(Set(String))),

        # JSON type
        Field(name="raw_event", dtype=Json),

        # Struct type
        Field(name="address", dtype=Struct({"street": String, "city": String, "zip": Int32})),
        Field(name="order_items", dtype=Array(Struct({"name": String, "qty": Int32}))),
    ],
    source=user_features_source,
)

3.5. Specifying the data source for features

As an ML engineer or a data scientist, you must specify the data source for the features that you want to define.

The data source differs depending on whether you are using an offline store, for batch data and training data sets, or an online store, for model inference. Optionally, you can use a Parquet or a Delta-formatted file as the data source. You can specify a local file or a file in storage, such as Amazon Simple Storage Service (S3).

For offline stores, specify a batch data source. You can specify a data warehouse, such as BigQuery, Snowflake, Redshift, or a data lake, such as Amazon S3 or Google Cloud Platform (GCP). You can use Feature Store to ingest and query data across both types of data sources.

For online stores, specify a database backend, such as Redis, GCP Datastore, or DynamoDB.

Prerequisites

  • You know the location of the data source for your ML workflow.

Procedure

  1. In the editor of your choice, create a new Python file.
  2. At the beginning of the file, specify the data source for the features that you want to define within the file.

    For example, use the following code to specify the data source as a Parquet-formatted file:

    from feast import FileSource
    from feast.data_format import ParquetFormat
    
    parquet_file_source = FileSource(
        file_format=ParquetFormat(),
        path="file:///feast/customer.parquet",
    )
  3. Save the file.

3.6. About organizing features by using entities

Within a feature view, you can group features that share a conceptual link or relationship together to define an entity. You can think of an entity as a primary key that you can use to fetch features. Typically, an entity maps to the domain of your use case. For example, a fraud detection use case could have customers and transactions as their entities, with group-related features that correspond to these customers and transactions.

A feature does not have to be associated with an entity. For example, a feature of a customer entity could be the number of transactions they have made on an average month, while a feature that is not observed on a specific entity could be the total number of transactions made by all users in the last month.

customer = Entity(name='dob_ssn', join_keys=['dob_ssn'])

The entity name uniquely identifies the entity. The join key identifies the physical primary key on which feature values are joined together for feature retrieval.

The following table shows example data with a single entity column (dob_ssn) and two feature columns (credit_card_due and bankruptcies).

Expand
Table 3.1. Example data showing an entity and features
rowtimestampdob_ssncredit_card_duebankruptcies

1

5/22/2025 0:00:00

19530219_5179

833

0

2

5/22/2025 0:00:00

19500806_6783

1297

0

3

5/22/2025 0:00:00

19690214_3370

3912

1

4

5/22/2025 0:00:00

19570513_7405

8840

0

3.7. Creating feature views

You define features within a feature view. A feature view is an object that represents a logical group of time-series feature data in a data source. Feature views indicate to Feature Store where to find your feature values, for example, in a parquet file or a BigQuery table.

By using feature views, you define the existing feature data in a consistent way for both an offline environment, when you train your models, and an online environment, when you want to serve features to models in production.

Feature Store uses feature views during the following tasks:

  • Generating training datasets by querying the data source of feature views to find historical feature values. A single training data set can consist of features from multiple feature views.
  • Loading feature values into an online or offline store. Feature views determine the storage schema in the online or offline store. Feature values can be loaded from batch sources or from stream sources.
  • Retrieving features from the online or offline store. Feature views provide the schema definition for looking up features from the online or offline store.

When you create a feature project, the feature_repo subfolder includes a Python file that includes example feature definitions (for example, example_features.py) .

To define new features, you can edit the code in the example file or add a new file to the feature repository.

Note: Feature views only work with timestamped data. If your data does not contain timestamps, insert dummy timestamps. The following example shows how to create a table with dummy timestamps for PostgreSQL-based data:

CREATE TABLE employee_metadata (
  employee_id INT PRIMARY KEY,
  department TEXT,
  dummy_event_timestamp TIMESTAMP DEFAULT '2024-01-01'
);
INSERT INTO employee_metadata (employee_id, department)
VALUES (1, 'Advanced'), (2, 'New');

Prerequisites

  • You know what data is relevant to your use case.
  • You have identified attributes in your data that you want to use as features in your ML models.

Procedure

  1. In your IDE, such as JupyterLab, open the feature_repo/example_features.py file that contains example feature definitions or create a new Python (.py) file in the feature_repo directory.
  2. Create a feature view that is relevant to your use case based on the structure shown in the following example:

    credit_history_source = FileSource(   
    1
    
    	name="Credit history",
    	path="data/credit_history.parquet",
    	file_format=ParquetFormat(),
    	timestamp_field="event_timestamp",
    	created_timestamp_column="created_timestamp",
    )
    credit_history = FeatureView(       
    2
    
    	name="credit_history",
    	entities=[dob_ssn],             
    3
    
    	ttl=timedelta(days=90),         
    4
    
    	schema=[                        
    5
    
        	Field(name="credit_card_due", dtype=Int64),
        	Field(name="mortgage_due", dtype=Int64),
        	Field(name="student_loan_due", dtype=Int64),
        	Field(name="vehicle_loan_due", dtype=Int64),
        	Field(name="hard_pulls", dtype=Int64),
        	Field(name="missed_payments_2y", dtype=Int64),
        	Field(name="missed_payments_1y", dtype=Int64),
        	Field(name="missed_payments_6m", dtype=Int64),
        	Field(name="bankruptcies", dtype=Int64),
    	],
    	source=credit_history_source,  
    6
    
        tags={"origin": "internet"},   
    7
    
    )
    1
    A data source that provides time-stamped tabular data. A feature view must always have a data source for the generation of training datasets and when materializing feature values into the online store. Possible data sources are batch data sources from data warehouses (BigQuery, Snowflake, Redshift), data lakes (S3, GCS), or stream sources. Users can push features from data sources into Feature Store, and make the features available for training or batch scoring ("offline"), for realtime feature serving ("online"), or both.
    2
    A name that identifies the feature view in the project. Within a feature view, feature names must be unique.
    3
    Zero or more entities. Feature views generally contain features that are properties of a specific object, in which case that object is defined as an entity and included in the feature view. If the features are not related to a specific object, the feature view might not have entities.
    4
    (Optional) Time-to-live (TTL) to limit how far back to look when Feature Store generates historical datasets.
    5
    One or more feature definitions.
    6
    A reference to the data source.
    7
    (Optional) You can add metadata, such as tags that enable filtering of features when viewing them in the UI, listing them by using a CLI command, or by querying the registry directly.
  3. Save the file.
Red Hat logoGithubredditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top