Skip to content

Commit d520584

Browse files
vidigoatclaudeshuchu
authored
fix: Keep entity columns out of StreamFeatureView proto features (#7033)
StreamFeatureView.to_proto() built spec.features from self.schema, which includes the entity (join key) columns, while FeatureView.to_proto_spec() uses self.features. A stream feature view read back from the registry therefore listed its join key as a feature, and a FeatureService built from it failed historical retrieval with a duplicate join key column. Serialize self.features, matching FeatureView. Entity columns are still stored in spec.entity_columns and restored by from_proto. Signed-off-by: Vidit Patankar <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]> Co-authored-by: Shuchu Han <[email protected]>
1 parent 0c845a1 commit d520584

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

‎sdk/python/feast/stream_feature_view.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def to_proto(self):
311311
name=self.name,
312312
entities=self.entities,
313313
entity_columns=[field.to_proto() for field in self.entity_columns],
314-
features=[field.to_proto() for field in self.schema],
314+
features=[field.to_proto() for field in self.features],
315315
user_defined_function=udf_proto,
316316
feature_transformation=feature_transformation,
317317
description=self.description,

‎sdk/python/tests/unit/test_stream_feature_view.py‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
StreamFeatureView as StreamFeatureViewProto,
1414
)
1515
from feast.stream_feature_view import StreamFeatureView, stream_feature_view
16-
from feast.types import Float32
16+
from feast.types import Float32, Int64
1717
from feast.utils import _utc_now, make_tzaware
1818

1919

@@ -112,6 +112,41 @@ def test_stream_feature_view_serialization():
112112
)
113113

114114

115+
def test_stream_feature_view_serialization_excludes_entity_columns_from_features():
116+
entity = Entity(name="driver_entity", join_keys=["driver_id"])
117+
stream_source = KafkaSource(
118+
name="kafka",
119+
timestamp_field="event_timestamp",
120+
kafka_bootstrap_servers="",
121+
message_format=AvroFormat(""),
122+
topic="topic",
123+
batch_source=FileSource(path="some path"),
124+
)
125+
126+
sfv = StreamFeatureView(
127+
name="test kafka stream feature view",
128+
entities=[entity],
129+
ttl=timedelta(days=30),
130+
schema=[
131+
Field(name="driver_id", dtype=Int64),
132+
Field(name="dummy_field", dtype=Float32),
133+
],
134+
timestamp_field="event_timestamp",
135+
source=stream_source,
136+
)
137+
assert [f.name for f in sfv.features] == ["dummy_field"]
138+
assert [f.name for f in sfv.entity_columns] == ["driver_id"]
139+
140+
sfv_proto = sfv.to_proto()
141+
assert [f.name for f in sfv_proto.spec.features] == ["dummy_field"]
142+
assert [f.name for f in sfv_proto.spec.entity_columns] == ["driver_id"]
143+
144+
new_sfv = StreamFeatureView.from_proto(sfv_proto=sfv_proto)
145+
assert new_sfv.features == sfv.features
146+
assert new_sfv.entity_columns == sfv.entity_columns
147+
assert new_sfv == sfv
148+
149+
115150
def test_stream_feature_view_udfs():
116151
entity = Entity(name="driver_entity", join_keys=["test_key"])
117152
stream_source = KafkaSource(

0 commit comments

Comments
 (0)