Skip to content

Commit 8a714bb

Browse files
authored
feat: Override the udf name when provided as input to an on demand transformation (feast-dev#5094)
* allow setting name w/ udf Signed-off-by: Blake <[email protected]> * refactor based on PR review Signed-off-by: Blake <[email protected]> * removed comments Signed-off-by: Blake <[email protected]> * pr comments Signed-off-by: Blake <[email protected]> --------- Signed-off-by: Blake <[email protected]>
1 parent 872ca31 commit 8a714bb

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ The list below contains the functionality that contributors are planning to deve
202202
* [x] Python Client
203203
* [x] [Python feature server](https://docs.feast.dev/reference/feature-servers/python-feature-server)
204204
* [x] [Java feature server (alpha)](https://github.com/feast-dev/feast/blob/master/infra/charts/feast/README.md)
205-
* [x] [Go feature server (alpha)](https://github.com/feast-dev/feast/blob/master/go/README.md)
205+
* [x] [Go feature server (alpha)](https://docs.feast.dev/reference/feature-servers/go-feature-server)
206206
* **Data Quality Management (See [RFC](https://docs.google.com/document/d/110F72d4NTv80p35wDSONxhhPBqWRwbZXG4f9mNEMd98/edit))**
207207
* [x] Data profiling and validation (Great Expectations)
208208
* **Feature Discovery and Governance**
@@ -249,4 +249,4 @@ Thanks goes to these incredible people:
249249

250250
<a href="https://github.com/feast-dev/feast/graphs/contributors">
251251
<img src="https://contrib.rocks/image?repo=feast-dev/feast" />
252-
</a>
252+
</a>

sdk/python/feast/on_demand_feature_view.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ def get_requested_odfvs(
722722

723723
def on_demand_feature_view(
724724
*,
725+
name: Optional[str] = None,
725726
entities: Optional[List[Entity]] = None,
726727
schema: list[Field],
727728
sources: list[
@@ -742,6 +743,7 @@ def on_demand_feature_view(
742743
Creates an OnDemandFeatureView object with the given user function as udf.
743744
744745
Args:
746+
name (optional): The name of the on demand feature view. If not provided, the name will be the name of the user function.
745747
entities (Optional): The list of names of entities that this feature view is associated with.
746748
schema: The list of features in the output of the on demand feature view, after
747749
the transformation has been applied.
@@ -791,7 +793,7 @@ def decorator(user_function):
791793
transformation = SubstraitTransformation.from_ibis(user_function, sources)
792794

793795
on_demand_feature_view_obj = OnDemandFeatureView(
794-
name=user_function.__name__,
796+
name=name if name is not None else user_function.__name__,
795797
sources=sources,
796798
schema=schema,
797799
feature_transformation=transformation,

sdk/python/tests/unit/test_on_demand_feature_view.py

+63
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
OnDemandFeatureView,
2525
PandasTransformation,
2626
PythonTransformation,
27+
on_demand_feature_view,
2728
)
2829
from feast.types import Float32
2930

@@ -356,3 +357,65 @@ def test_on_demand_feature_view_stored_writes():
356357
assert transformed_output["output3"] is not None and isinstance(
357358
transformed_output["output3"], datetime.datetime
358359
)
360+
361+
362+
def test_function_call_syntax():
363+
CUSTOM_FUNCTION_NAME = "custom-function-name"
364+
file_source = FileSource(name="my-file-source", path="test.parquet")
365+
feature_view = FeatureView(
366+
name="my-feature-view",
367+
entities=[],
368+
schema=[
369+
Field(name="feature1", dtype=Float32),
370+
Field(name="feature2", dtype=Float32),
371+
],
372+
source=file_source,
373+
)
374+
sources = [feature_view]
375+
376+
def transform_features(features_df: pd.DataFrame) -> pd.DataFrame:
377+
df = pd.DataFrame()
378+
df["output1"] = features_df["feature1"]
379+
df["output2"] = features_df["feature2"]
380+
return df
381+
382+
odfv = on_demand_feature_view(
383+
sources=sources,
384+
schema=[
385+
Field(name="output1", dtype=Float32),
386+
Field(name="output2", dtype=Float32),
387+
],
388+
)(transform_features)
389+
390+
assert odfv.name == transform_features.__name__
391+
assert isinstance(odfv, OnDemandFeatureView)
392+
393+
proto = odfv.to_proto()
394+
assert proto.spec.name == transform_features.__name__
395+
396+
deserialized = OnDemandFeatureView.from_proto(proto)
397+
assert deserialized.name == transform_features.__name__
398+
399+
def another_transform(features_df: pd.DataFrame) -> pd.DataFrame:
400+
df = pd.DataFrame()
401+
df["output1"] = features_df["feature1"]
402+
df["output2"] = features_df["feature2"]
403+
return df
404+
405+
odfv_custom = on_demand_feature_view(
406+
name=CUSTOM_FUNCTION_NAME,
407+
sources=sources,
408+
schema=[
409+
Field(name="output1", dtype=Float32),
410+
Field(name="output2", dtype=Float32),
411+
],
412+
)(another_transform)
413+
414+
assert odfv_custom.name == CUSTOM_FUNCTION_NAME
415+
assert isinstance(odfv_custom, OnDemandFeatureView)
416+
417+
proto = odfv_custom.to_proto()
418+
assert proto.spec.name == CUSTOM_FUNCTION_NAME
419+
420+
deserialized = OnDemandFeatureView.from_proto(proto)
421+
assert deserialized.name == CUSTOM_FUNCTION_NAME

0 commit comments

Comments
 (0)