Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set created_timestamp and last_updated_timestamp fields #2266

Merged
merged 6 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions protos/feast/core/OnDemandFeatureView.proto
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ message OnDemandFeatureViewSpec {
message OnDemandFeatureViewMeta {
// Time where this Feature View is created
google.protobuf.Timestamp created_timestamp = 1;

// Time where this Feature View is last updated
google.protobuf.Timestamp last_updated_timestamp = 2;
}

message OnDemandInput {
Expand Down
4 changes: 4 additions & 0 deletions sdk/python/feast/base_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@
class BaseFeatureView(ABC):
"""A FeatureView defines a logical grouping of features to be served."""

created_timestamp: Optional[datetime]
last_updated_timestamp: Optional[datetime]

@abstractmethod
def __init__(self, name: str, features: List[Feature]):
self._name = name
self._features = features
self._projection = FeatureViewProjection.from_definition(self)
self.created_timestamp: Optional[datetime] = None
self.last_updated_timestamp: Optional[datetime] = None

@property
def name(self) -> str:
Expand Down
6 changes: 1 addition & 5 deletions sdk/python/feast/feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ class FeatureView(BaseFeatureView):
online: bool
input: DataSource
batch_source: DataSource
stream_source: Optional[DataSource] = None
last_updated_timestamp: Optional[datetime] = None
stream_source: Optional[DataSource]
materialization_intervals: List[Tuple[datetime, datetime]]

@log_exceptions
Expand Down Expand Up @@ -136,9 +135,6 @@ def __init__(

self.materialization_intervals = []

self.created_timestamp: Optional[datetime] = None
self.last_updated_timestamp: Optional[datetime] = None

# Note: Python requires redefining hash in child classes that override __eq__
def __hash__(self):
return super().__hash__()
Expand Down
6 changes: 6 additions & 0 deletions sdk/python/feast/on_demand_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ def to_proto(self) -> OnDemandFeatureViewProto:
meta = OnDemandFeatureViewMeta()
if self.created_timestamp:
meta.created_timestamp.FromDatetime(self.created_timestamp)
if self.last_updated_timestamp:
meta.last_updated_timestamp.FromDatetime(self.last_updated_timestamp)
inputs = {}
for input_ref, fv_projection in self.input_feature_view_projections.items():
inputs[input_ref] = OnDemandInput(
Expand Down Expand Up @@ -194,6 +196,10 @@ def from_proto(cls, on_demand_feature_view_proto: OnDemandFeatureViewProto):
on_demand_feature_view_obj.created_timestamp = (
on_demand_feature_view_proto.meta.created_timestamp.ToDatetime()
)
if on_demand_feature_view_proto.meta.HasField("last_updated_timestamp"):
on_demand_feature_view_obj.last_updated_timestamp = (
on_demand_feature_view_proto.meta.last_updated_timestamp.ToDatetime()
)

return on_demand_feature_view_obj

Expand Down
23 changes: 22 additions & 1 deletion sdk/python/feast/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ def apply_entity(self, entity: Entity, project: str, commit: bool = True):
commit: Whether the change should be persisted immediately
"""
entity.is_valid()

now = datetime.utcnow()
if not entity.created_timestamp:
entity._created_timestamp = now
entity._last_updated_timestamp = now

entity_proto = entity.to_proto()
entity_proto.spec.project = project
self._prepare_registry_for_changes()
Expand Down Expand Up @@ -278,6 +284,11 @@ def apply_feature_service(
feature_service: A feature service that will be registered
project: Feast project that this entity belongs to
"""
now = datetime.utcnow()
if not feature_service.created_timestamp:
feature_service.created_timestamp = now
feature_service.last_updated_timestamp = now

feature_service_proto = feature_service.to_proto()
feature_service_proto.spec.project = project

Expand Down Expand Up @@ -373,8 +384,12 @@ def apply_feature_view(
commit: Whether the change should be persisted immediately
"""
feature_view.ensure_valid()

now = datetime.utcnow()
if not feature_view.created_timestamp:
feature_view.created_timestamp = datetime.utcnow()
feature_view.created_timestamp = now
feature_view.last_updated_timestamp = now

feature_view_proto = feature_view.to_proto()
feature_view_proto.spec.project = project
self._prepare_registry_for_changes()
Expand Down Expand Up @@ -498,6 +513,7 @@ def apply_materialization(
existing_feature_view.materialization_intervals.append(
(start_date, end_date)
)
existing_feature_view.last_updated_timestamp = datetime.utcnow()
feature_view_proto = existing_feature_view.to_proto()
feature_view_proto.spec.project = project
del self.cached_registry_proto.feature_views[idx]
Expand Down Expand Up @@ -686,6 +702,11 @@ def apply_saved_dataset(
project: Feast project that this dataset belongs to
commit: Whether the change should be persisted immediately
"""
now = datetime.utcnow()
if not saved_dataset.created_timestamp:
saved_dataset.created_timestamp = now
saved_dataset.last_updated_timestamp = now

saved_dataset_proto = saved_dataset.to_proto()
saved_dataset_proto.spec.project = project
self._prepare_registry_for_changes()
Expand Down