Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
cleaned up and have tests behaving
Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
  • Loading branch information
franciscojavierarceo committed Sep 21, 2024
commit 2837c1c3a8d7d8d0c8859b798f4736702331cbd4
5 changes: 4 additions & 1 deletion sdk/python/feast/base_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,11 @@ def __eq__(self, other):
or self.description != other.description
or self.tags != other.tags
or self.owner != other.owner
or self.source != other.source
):
# This is meant to ignore the File Source change to Push Source
if isinstance(type(self.source), type(other.source)):
if self.source != other.source:
return False
return False

return True
Expand Down
8 changes: 4 additions & 4 deletions sdk/python/feast/feature_view_projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,13 @@ def from_definition(base_feature_view: "BaseFeatureView"):
name_alias=None,
features=base_feature_view.features,
desired_features=[],
timestamp_field=base_feature_view.batch_source.created_timestamp_column
timestamp_field=base_feature_view.batch_source.created_timestamp_column # type:ignore[attr-defined]
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is admittedly a hack and I don't like it but this should be refactored in 1.0.0

My overall learning from this is that FeatureViews should be really derived from the same object with the same class parameters and make them optionally instantiated.

This should be described more thoroughly for 1.0.0

or None,
created_timestamp_column=base_feature_view.batch_source.created_timestamp_column
created_timestamp_column=base_feature_view.batch_source.created_timestamp_column # type:ignore[attr-defined]
or None,
date_partition_column=base_feature_view.batch_source.date_partition_column
date_partition_column=base_feature_view.batch_source.date_partition_column # type:ignore[attr-defined]
or None,
batch_source=base_feature_view.batch_source or None,
batch_source=base_feature_view.batch_source or None, # type:ignore[attr-defined]
)
else:
return FeatureViewProjection(
Expand Down
101 changes: 54 additions & 47 deletions sdk/python/feast/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def update_feature_views_with_inferred_features_and_entities(
join_keys = set(
[
entity_name_to_join_key_map.get(entity_name)
for entity_name in fv.entities
for entity_name in getattr(fv, "entities", [])
]
)

Expand All @@ -141,7 +141,8 @@ def update_feature_views_with_inferred_features_and_entities(
fv.features.append(field)

# Respect the `value_type` attribute of the entity, if it is specified.
for entity_name in fv.entities:
fv_entities = getattr(fv, "entities", [])
for entity_name in fv_entities:
entity = entity_name_to_entity_map.get(entity_name)
# pass when entity does not exist. Entityless feature view case
if entity is None:
Expand All @@ -160,8 +161,8 @@ def update_feature_views_with_inferred_features_and_entities(

# Infer a dummy entity column for entityless feature views.
if (
len(fv.entities) == 1
and fv.entities[0] == DUMMY_ENTITY_NAME
len(fv_entities) == 1
and fv_entities[0] == DUMMY_ENTITY_NAME
and not entity_columns
):
entity_columns.append(Field(name=DUMMY_ENTITY_ID, dtype=String))
Expand Down Expand Up @@ -189,7 +190,7 @@ def update_feature_views_with_inferred_features_and_entities(


def _infer_features_and_entities(
fv: FeatureView,
fv: Union[FeatureView, OnDemandFeatureView],
join_keys: Set[Optional[str]],
run_inference_for_features,
config,
Expand All @@ -203,7 +204,7 @@ def _infer_features_and_entities(
run_inference_for_features: Whether to run inference for features.
config: The config for the current feature store.
"""
entity_columns: list[str] = []
entity_columns: list[Field] = []
if isinstance(fv, OnDemandFeatureView):
columns_to_exclude = set()
for (
Expand All @@ -213,57 +214,60 @@ def _infer_features_and_entities(
columns_to_exclude.add(source_feature_view.timestamp_field)
columns_to_exclude.add(source_feature_view.created_timestamp_column)

for (
original_col,
mapped_col,
) in source_feature_view.batch_source.field_mapping.items():
if mapped_col in columns_to_exclude:
columns_to_exclude.remove(mapped_col)
columns_to_exclude.add(original_col)
batch_source = getattr(source_feature_view, "batch_source")
batch_field_mapping = getattr(batch_source or None, "field_mapping")
if batch_field_mapping:
for (
original_col,
mapped_col,
) in batch_field_mapping.items():
if mapped_col in columns_to_exclude:
columns_to_exclude.remove(mapped_col)
columns_to_exclude.add(original_col)

table_column_names_and_types = (
source_feature_view.batch_source.get_table_column_names_and_types(
config
table_column_names_and_types = (
batch_source.get_table_column_names_and_types(config)
)
)

for col_name, col_datatype in table_column_names_and_types:
if col_name in columns_to_exclude:
continue
elif col_name in join_keys:
field = Field(
name=col_name,
dtype=from_value_type(
source_feature_view.batch_source.source_datatype_to_feast_value_type()(
col_datatype
)
),
)
if field.name not in [
entity_column.name for entity_column in entity_columns
]:
entity_columns.append(field)
elif not re.match(
"^__|__$", col_name
): # double underscores often signal an internal-use column
if run_inference_for_features:
feature_name = (
source_feature_view.batch_source.field_mapping[col_name]
if col_name in source_feature_view.batch_source.field_mapping
else col_name
)
for col_name, col_datatype in table_column_names_and_types:
if col_name in columns_to_exclude:
continue
elif col_name in join_keys:
field = Field(
name=feature_name,
name=col_name,
dtype=from_value_type(
source_feature_view.batch_source.source_datatype_to_feast_value_type()(
batch_source.source_datatype_to_feast_value_type()(
col_datatype
)
),
)
if field.name not in [
feature.name for feature in source_feature_view.features
entity_column.name
for entity_column in entity_columns
if hasattr(entity_column, "name")
]:
source_feature_view.features.append(field)
entity_columns.append(field)
elif not re.match(
"^__|__$", col_name
): # double underscores often signal an internal-use column
if run_inference_for_features:
feature_name = (
batch_field_mapping[col_name]
if col_name in batch_field_mapping
else col_name
)
field = Field(
name=feature_name,
dtype=from_value_type(
batch_source.source_datatype_to_feast_value_type()(
col_datatype
)
),
)
if field.name not in [
feature.name for feature in source_feature_view.features
]:
source_feature_view.features.append(field)

else:
columns_to_exclude = {
Expand Down Expand Up @@ -292,7 +296,10 @@ def _infer_features_and_entities(
),
)
if field.name not in [
entity_column.name for entity_column in entity_columns
entity_column.name
if not isinstance(entity_column, str)
else entity_column
for entity_column in entity_columns
]:
entity_columns.append(field)
elif not re.match(
Expand Down
7 changes: 4 additions & 3 deletions sdk/python/feast/on_demand_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def __eq__(self, other):
if (
self.source_feature_view_projections
!= other.source_feature_view_projections
or self.description != other.description
or self.source_request_sources != other.source_request_sources
or self.mode != other.mode
or self.feature_transformation != other.feature_transformation
Expand Down Expand Up @@ -423,9 +424,9 @@ def from_proto(
else:
write_to_online_store = False
if hasattr(on_demand_feature_view_proto.spec, "entities"):
entities = on_demand_feature_view_proto.spec.entities
entities = list(on_demand_feature_view_proto.spec.entities)
else:
entities = None
entities = []
if hasattr(on_demand_feature_view_proto.spec, "entity_columns"):
entity_columns = [
Field.from_proto(field_proto)
Expand All @@ -452,7 +453,7 @@ def from_proto(
write_to_online_store=write_to_online_store,
)

on_demand_feature_view_obj.entities = list(entities)
on_demand_feature_view_obj.entities = entities
on_demand_feature_view_obj.entity_columns = entity_columns

# FeatureViewProjections are not saved in the OnDemandFeatureView proto.
Expand Down