@@ -149,6 +149,7 @@ def __init__(
149
149
self ._feature_to_handle_if_sql : Optional [Set [str ]] = None
150
150
self ._valid_serving_keys : Set [str ] = set ()
151
151
self ._serving_initialized : bool = False
152
+ self .__all_features_on_demand : Optional [bool ] = None
152
153
153
154
def init_serving (
154
155
self ,
@@ -415,14 +416,23 @@ def get_feature_vectors(
415
416
request_parameters is None
416
417
or len (request_parameters ) == 0
417
418
or isinstance (request_parameters , dict )
419
+ or not entries
418
420
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. "
420
422
421
423
online_client_choice = self .which_client_and_ensure_initialised (
422
424
force_rest_client = force_rest_client , force_sql_client = force_sql_client
423
425
)
424
426
rondb_entries = []
425
427
skipped_empty_entries = []
428
+
429
+ if not entries :
430
+ entries = (
431
+ [[] * len (request_parameters )]
432
+ if isinstance (request_parameters , list )
433
+ else [[]]
434
+ )
435
+
426
436
for (idx , entry ), passed , vector_features in itertools .zip_longest (
427
437
enumerate (entries ),
428
438
passed_features ,
@@ -547,7 +557,11 @@ def assemble_feature_vector(
547
557
# for backward compatibility, before 3.4, if result is empty,
548
558
# instead of throwing error, it skips the result
549
559
# 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
+ ):
551
565
return None
552
566
553
567
if not allow_missing and len (missing_features ) > 0 :
@@ -1255,6 +1269,17 @@ def validate_entry(
1255
1269
1256
1270
Keys relevant to vector_db are filtered out.
1257
1271
"""
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
+
1258
1283
_logger .debug ("Checking keys in entry are valid serving keys." )
1259
1284
for key in entry .keys ():
1260
1285
if key not in self .valid_serving_keys :
@@ -1584,3 +1609,12 @@ def transformed_feature_vector_col_name(self):
1584
1609
]
1585
1610
self ._transformed_feature_vector_col_name .extend (output_column_names )
1586
1611
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
0 commit comments