From b8a8ab68077a2d3c25b35c49649fde8d97b66dfa Mon Sep 17 00:00:00 2001 From: Aniket Paluskar Date: Tue, 21 Oct 2025 17:41:35 +0530 Subject: [PATCH 1/5] Added start_date & end_date range for historical data retrieval from RemoteOfflineStore Signed-off-by: Aniket Paluskar --- sdk/python/feast/infra/offline_stores/remote.py | 10 ++++++++++ sdk/python/feast/offline_server.py | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/sdk/python/feast/infra/offline_stores/remote.py b/sdk/python/feast/infra/offline_stores/remote.py index a5f50c7b45c..33b1c1e570f 100644 --- a/sdk/python/feast/infra/offline_stores/remote.py +++ b/sdk/python/feast/infra/offline_stores/remote.py @@ -197,6 +197,7 @@ def get_historical_features( registry: BaseRegistry, project: str, full_feature_names: bool = False, + **kwargs, ) -> RemoteRetrievalJob: assert isinstance(config.offline_store, RemoteOfflineStoreConfig) @@ -218,6 +219,15 @@ def get_historical_features( "full_feature_names": full_feature_names, "name_aliases": name_aliases, } + + # Extract and serialize start_date/end_date for remote transmission + start_date = kwargs.get("start_date", None) + end_date = kwargs.get("end_date", None) + + if start_date is not None: + api_parameters["start_date"] = start_date.isoformat() + if end_date is not None: + api_parameters["end_date"] = end_date.isoformat() return RemoteRetrievalJob( client=client, diff --git a/sdk/python/feast/offline_server.py b/sdk/python/feast/offline_server.py index 776a0dfb96d..5ce940b417a 100644 --- a/sdk/python/feast/offline_server.py +++ b/sdk/python/feast/offline_server.py @@ -449,6 +449,17 @@ def get_historical_features(self, command: dict, key: Optional[str] = None): resource=feature_view, actions=[AuthzedAction.READ_OFFLINE] ) + # Extract and deserialize start_date/end_date if present + kwargs = {} + if "start_date" in command and command["start_date"] is not None: + kwargs["start_date"] = utils.make_tzaware( + datetime.fromisoformat(command["start_date"]) + ) + if "end_date" in command and command["end_date"] is not None: + kwargs["end_date"] = utils.make_tzaware( + datetime.fromisoformat(command["end_date"]) + ) + retJob = self.offline_store.get_historical_features( config=self.store.config, feature_views=feature_views, @@ -457,6 +468,7 @@ def get_historical_features(self, command: dict, key: Optional[str] = None): registry=self.store.registry, project=project, full_feature_names=full_feature_names, + **kwargs, ) return retJob From d6bb7730c7be75761585373fbe3eee2c6991860a Mon Sep 17 00:00:00 2001 From: Aniket Paluskar Date: Tue, 21 Oct 2025 17:44:51 +0530 Subject: [PATCH 2/5] Minor linting & reformatting changes Signed-off-by: Aniket Paluskar --- sdk/python/feast/infra/offline_stores/remote.py | 2 +- sdk/python/feast/offline_server.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/python/feast/infra/offline_stores/remote.py b/sdk/python/feast/infra/offline_stores/remote.py index 33b1c1e570f..abe75ca57e5 100644 --- a/sdk/python/feast/infra/offline_stores/remote.py +++ b/sdk/python/feast/infra/offline_stores/remote.py @@ -219,7 +219,7 @@ def get_historical_features( "full_feature_names": full_feature_names, "name_aliases": name_aliases, } - + # Extract and serialize start_date/end_date for remote transmission start_date = kwargs.get("start_date", None) end_date = kwargs.get("end_date", None) diff --git a/sdk/python/feast/offline_server.py b/sdk/python/feast/offline_server.py index 5ce940b417a..6bc573888fc 100644 --- a/sdk/python/feast/offline_server.py +++ b/sdk/python/feast/offline_server.py @@ -449,7 +449,7 @@ def get_historical_features(self, command: dict, key: Optional[str] = None): resource=feature_view, actions=[AuthzedAction.READ_OFFLINE] ) - # Extract and deserialize start_date/end_date if present + # Extract and deserialize start_date/end_date if present kwargs = {} if "start_date" in command and command["start_date"] is not None: kwargs["start_date"] = utils.make_tzaware( @@ -459,7 +459,7 @@ def get_historical_features(self, command: dict, key: Optional[str] = None): kwargs["end_date"] = utils.make_tzaware( datetime.fromisoformat(command["end_date"]) ) - + retJob = self.offline_store.get_historical_features( config=self.store.config, feature_views=feature_views, From 0e17fdf42f06451da6a235b7cdf10f22ee499b31 Mon Sep 17 00:00:00 2001 From: Aniket Paluskar Date: Tue, 28 Oct 2025 17:10:02 +0530 Subject: [PATCH 3/5] Fixed minor issue of empty df with only key as column being trated as entity_df in offline server Signed-off-by: Aniket Paluskar --- sdk/python/feast/infra/offline_stores/remote.py | 11 ++++++++++- sdk/python/feast/offline_server.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sdk/python/feast/infra/offline_stores/remote.py b/sdk/python/feast/infra/offline_stores/remote.py index abe75ca57e5..e0a1df573d4 100644 --- a/sdk/python/feast/infra/offline_stores/remote.py +++ b/sdk/python/feast/infra/offline_stores/remote.py @@ -443,7 +443,16 @@ def get_table_column_names_and_types_from_data_source( return zip(table.column("name").to_pylist(), table.column("type").to_pylist()) -def _create_retrieval_metadata(feature_refs: List[str], entity_df: pd.DataFrame): +def _create_retrieval_metadata( + feature_refs: List[str], entity_df: Optional[pd.DataFrame] = None +): + if entity_df is None: + return RetrievalMetadata( + features=feature_refs, + keys=[], # No entity keys when no entity_df provided + min_event_timestamp=None, + max_event_timestamp=None, + ) entity_schema = _get_entity_schema( entity_df=entity_df, ) diff --git a/sdk/python/feast/offline_server.py b/sdk/python/feast/offline_server.py index 6bc573888fc..4a88b0be876 100644 --- a/sdk/python/feast/offline_server.py +++ b/sdk/python/feast/offline_server.py @@ -8,6 +8,7 @@ from typing import Any, Dict, List, Optional, cast import click +import pandas as pd import pyarrow as pa import pyarrow.flight as fl from google.protobuf.json_format import Parse @@ -431,6 +432,20 @@ def get_historical_features(self, command: dict, key: Optional[str] = None): # Extract parameters from the internal flights dictionary entity_df_value = self.flights[key] entity_df = pa.Table.to_pandas(entity_df_value) + # Check if this is a mock/empty table (contains only 'key' column) + if len(entity_df.columns) == 1 and "key" in entity_df.columns: + entity_df = None + + # If no entity_df provided, create minimal one with timestamps + if entity_df is None and "start_date" in command and "end_date" in command: + # Create minimal entity_df with event_timestamp when using start_date/end_date mode + start_date = utils.make_tzaware( + datetime.fromisoformat(command["start_date"]) + ) + end_date = utils.make_tzaware(datetime.fromisoformat(command["end_date"])) + entity_df = pd.DataFrame( + {"event_timestamp": pd.to_datetime([start_date, end_date])} + ) feature_view_names = command["feature_view_names"] name_aliases = command["name_aliases"] From 0d52d17996ab06c449618a390e1b3e8fc79a9494 Mon Sep 17 00:00:00 2001 From: Aniket Paluskar Date: Mon, 3 Nov 2025 12:47:33 +0530 Subject: [PATCH 4/5] Removed unnecessary logic to create mock df Signed-off-by: Aniket Paluskar --- sdk/python/feast/offline_server.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/sdk/python/feast/offline_server.py b/sdk/python/feast/offline_server.py index 4a88b0be876..3eabbcb614a 100644 --- a/sdk/python/feast/offline_server.py +++ b/sdk/python/feast/offline_server.py @@ -436,17 +436,6 @@ def get_historical_features(self, command: dict, key: Optional[str] = None): if len(entity_df.columns) == 1 and "key" in entity_df.columns: entity_df = None - # If no entity_df provided, create minimal one with timestamps - if entity_df is None and "start_date" in command and "end_date" in command: - # Create minimal entity_df with event_timestamp when using start_date/end_date mode - start_date = utils.make_tzaware( - datetime.fromisoformat(command["start_date"]) - ) - end_date = utils.make_tzaware(datetime.fromisoformat(command["end_date"])) - entity_df = pd.DataFrame( - {"event_timestamp": pd.to_datetime([start_date, end_date])} - ) - feature_view_names = command["feature_view_names"] name_aliases = command["name_aliases"] feature_refs = command["feature_refs"] From 4bf7de7a4d41e554a886eba93e2d92326528a85c Mon Sep 17 00:00:00 2001 From: Aniket Paluskar Date: Mon, 3 Nov 2025 13:47:15 +0530 Subject: [PATCH 5/5] Minor linting & formatting changes Signed-off-by: Aniket Paluskar --- sdk/python/feast/offline_server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/python/feast/offline_server.py b/sdk/python/feast/offline_server.py index 3eabbcb614a..bcdf808868b 100644 --- a/sdk/python/feast/offline_server.py +++ b/sdk/python/feast/offline_server.py @@ -8,7 +8,6 @@ from typing import Any, Dict, List, Optional, cast import click -import pandas as pd import pyarrow as pa import pyarrow.flight as fl from google.protobuf.json_format import Parse