Skip to content

Commit

Permalink
Set created_timestamp and last_updated_timestamp fields (#2266)
Browse files Browse the repository at this point in the history
* Add `last_updated_timestamp` field to ODFV

Signed-off-by: Judah Rand <17158624+judahrand@users.noreply.github.com>

* Add missing fields to FeatureView classes

Signed-off-by: Judah Rand <17158624+judahrand@users.noreply.github.com>

* Set `last_updated_timestamp` when applying FeatureView

Signed-off-by: Judah Rand <17158624+judahrand@users.noreply.github.com>

* Correctly set created and updated fields

Signed-off-by: Judah Rand <17158624+judahrand@users.noreply.github.com>

* Remove logic duplicated by parent class

Signed-off-by: Judah Rand <17158624+judahrand@users.noreply.github.com>
  • Loading branch information
judahrand authored Feb 2, 2022
1 parent 6e30457 commit a3073ec
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 6 deletions.
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

0 comments on commit a3073ec

Please sign in to comment.