Skip to content

Commit 47e25d8

Browse files
authored
[FSTORE-1606][4.1] Allow ´entries´ to be None while retrieving feature vectors from a feature view with only on-demand features (#450)
* allow entries to be None when feature view contains only on-demand features * adddressing review comments
1 parent 1ae7737 commit 47e25d8

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

python/hsfs/core/vector_server.py

+36-2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ def __init__(
149149
self._feature_to_handle_if_sql: Optional[Set[str]] = None
150150
self._valid_serving_keys: Set[str] = set()
151151
self._serving_initialized: bool = False
152+
self.__all_features_on_demand: Optional[bool] = None
152153

153154
def init_serving(
154155
self,
@@ -415,14 +416,23 @@ def get_feature_vectors(
415416
request_parameters is None
416417
or len(request_parameters) == 0
417418
or isinstance(request_parameters, dict)
419+
or not entries
418420
or len(request_parameters) == len(entries)
419-
), "Request Parameters should be a Dictionary, None, empty or have the same length as the entries"
421+
), "Request Parameters should be a Dictionary, None, empty or have the same length as the entries if they are not None or empty."
420422

421423
online_client_choice = self.which_client_and_ensure_initialised(
422424
force_rest_client=force_rest_client, force_sql_client=force_sql_client
423425
)
424426
rondb_entries = []
425427
skipped_empty_entries = []
428+
429+
if not entries:
430+
entries = (
431+
[[] * len(request_parameters)]
432+
if isinstance(request_parameters, list)
433+
else [[]]
434+
)
435+
426436
for (idx, entry), passed, vector_features in itertools.zip_longest(
427437
enumerate(entries),
428438
passed_features,
@@ -547,7 +557,11 @@ def assemble_feature_vector(
547557
# for backward compatibility, before 3.4, if result is empty,
548558
# instead of throwing error, it skips the result
549559
# Maybe we drop this behaviour for 4.0
550-
if len(result_dict) == 0 and not allow_missing:
560+
if (
561+
len(result_dict) == 0
562+
and not allow_missing
563+
and not self._all_features_on_demand
564+
):
551565
return None
552566

553567
if not allow_missing and len(missing_features) > 0:
@@ -1255,6 +1269,17 @@ def validate_entry(
12551269
12561270
Keys relevant to vector_db are filtered out.
12571271
"""
1272+
_logger.debug(
1273+
"Checking if entry is None and all features in the feature view are on-demand."
1274+
)
1275+
if not entry:
1276+
if self._all_features_on_demand:
1277+
return {}
1278+
else:
1279+
raise exceptions.FeatureStoreException(
1280+
"The required argument `entries` is missing. If the feature view includes only on-demand features, entries may be left empty or set to None."
1281+
)
1282+
12581283
_logger.debug("Checking keys in entry are valid serving keys.")
12591284
for key in entry.keys():
12601285
if key not in self.valid_serving_keys:
@@ -1584,3 +1609,12 @@ def transformed_feature_vector_col_name(self):
15841609
]
15851610
self._transformed_feature_vector_col_name.extend(output_column_names)
15861611
return self._transformed_feature_vector_col_name
1612+
1613+
@property
1614+
def _all_features_on_demand(self) -> bool:
1615+
"""True if all features in the feature view are on-demand."""
1616+
if self.__all_features_on_demand is None:
1617+
self.__all_features_on_demand = all(
1618+
feature.on_demand_transformation_function for feature in self._features
1619+
)
1620+
return self.__all_features_on_demand

python/hsfs/feature_view.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ def get_batch_query(
520520

521521
def get_feature_vector(
522522
self,
523-
entry: Dict[str, Any],
523+
entry: Optional[Dict[str, Any]] = None,
524524
passed_features: Optional[Dict[str, Any]] = None,
525525
external: Optional[bool] = None,
526526
return_type: Literal["list", "polars", "numpy", "pandas"] = "list",
@@ -635,7 +635,7 @@ def get_feature_vector(
635635

636636
def get_feature_vectors(
637637
self,
638-
entry: List[Dict[str, Any]],
638+
entry: Optional[List[Dict[str, Any]]] = None,
639639
passed_features: Optional[List[Dict[str, Any]]] = None,
640640
external: Optional[bool] = None,
641641
return_type: Literal["list", "polars", "numpy", "pandas"] = "list",

0 commit comments

Comments
 (0)