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

Add owner field to FeatureService #2321

Merged
merged 3 commits into from
Feb 19, 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/FeatureService.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ message FeatureServiceSpec {

// Description of the feature service.
string description = 5;

// Owner of the feature service.
string owner = 6;
}


Expand Down
99 changes: 59 additions & 40 deletions sdk/python/feast/feature_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,36 @@
FeatureService as FeatureServiceProto,
)
from feast.protos.feast.core.FeatureService_pb2 import (
FeatureServiceMeta,
FeatureServiceSpec,
FeatureServiceMeta as FeatureServiceMetaProto,
)
from feast.protos.feast.core.FeatureService_pb2 import (
FeatureServiceSpec as FeatureServiceSpecProto,
)
from feast.usage import log_exceptions


class FeatureService:
"""
A feature service is a logical grouping of features for retrieval (training or serving).
The features grouped by a feature service may come from any number of feature views.

Args:
name: Unique name of the feature service.
features: A list of Features that are grouped as part of this FeatureService.
The list may contain Feature Views, Feature Tables, or a subset of either.
tags (optional): A dictionary of key-value pairs used for organizing Feature
Services.
A feature service defines a logical group of features from one or more feature views.
This group of features can be retrieved together during training or serving.

Attributes:
name: The unique name of the feature service.
feature_view_projections: A list containing feature views and feature view
projections, representing the features in the feature service.
description: A human-readable description.
tags: A dictionary of key-value pairs to store arbitrary metadata.
owner: The owner of the feature service, typically the email of the primary
maintainer.
created_timestamp: The time when the feature service was created.
last_updated_timestamp: The time when the feature service was last updated.
"""

_name: str
_feature_view_projections: List[FeatureViewProjection]
_description: str
_tags: Dict[str, str]
_description: Optional[str] = None
_owner: str
_created_timestamp: Optional[datetime] = None
_last_updated_timestamp: Optional[datetime] = None

Expand All @@ -42,8 +49,9 @@ def __init__(
self,
name: str,
features: List[Union[FeatureView, OnDemandFeatureView]],
tags: Optional[Dict[str, str]] = None,
description: Optional[str] = None,
tags: Dict[str, str] = None,
description: str = "",
owner: str = "",
):
"""
Creates a FeatureService object.
Expand All @@ -59,12 +67,13 @@ def __init__(
self._feature_view_projections.append(feature_grouping.projection)
else:
raise ValueError(
"The FeatureService {fs_name} has been provided with an invalid type"
f"The feature service {name} has been provided with an invalid type "
f'{type(feature_grouping)} as part of the "features" argument.)'
)

self._tags = tags or {}
self._description = description
self._tags = tags or {}
self._owner = owner
self._created_timestamp = None
self._last_updated_timestamp = None

Expand All @@ -83,7 +92,13 @@ def __eq__(self, other):
raise TypeError(
"Comparisons should only involve FeatureService class objects."
)
if self.tags != other.tags or self.name != other.name:

if (
self.name != other.name
or self.description != other.description
or self.tags != other.tags
or self.owner != other.owner
):
return False

if sorted(self.feature_view_projections) != sorted(
Expand Down Expand Up @@ -111,6 +126,14 @@ def feature_view_projections(
):
self._feature_view_projections = feature_view_projections

@property
def description(self) -> str:
return self._description

@description.setter
def description(self, description: str):
self._description = description

@property
def tags(self) -> Dict[str, str]:
return self._tags
Expand All @@ -120,12 +143,12 @@ def tags(self, tags: Dict[str, str]):
self._tags = tags

@property
def description(self) -> Optional[str]:
return self._description
def owner(self) -> str:
return self._owner

@description.setter
def description(self, description: str):
self._description = description
@owner.setter
def owner(self, owner: str):
self._owner = owner

@property
def created_timestamp(self) -> Optional[datetime]:
Expand All @@ -143,23 +166,20 @@ def last_updated_timestamp(self) -> Optional[datetime]:
def last_updated_timestamp(self, last_updated_timestamp: datetime):
self._last_updated_timestamp = last_updated_timestamp

@staticmethod
def from_proto(feature_service_proto: FeatureServiceProto):
@classmethod
def from_proto(cls, feature_service_proto: FeatureServiceProto):
"""
Converts a FeatureServiceProto to a FeatureService object.

Args:
feature_service_proto: A protobuf representation of a FeatureService.
"""
fs = FeatureService(
fs = cls(
name=feature_service_proto.spec.name,
features=[],
tags=dict(feature_service_proto.spec.tags),
description=(
feature_service_proto.spec.description
if feature_service_proto.spec.description != ""
else None
),
description=feature_service_proto.spec.description,
owner=feature_service_proto.spec.owner,
)
fs.feature_view_projections.extend(
[
Expand All @@ -181,29 +201,28 @@ def from_proto(feature_service_proto: FeatureServiceProto):

def to_proto(self) -> FeatureServiceProto:
"""
Converts a FeatureService to its protobuf representation.
Converts a feature service to its protobuf representation.

Returns:
A FeatureServiceProto protobuf.
"""
meta = FeatureServiceMeta()
meta = FeatureServiceMetaProto()
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)

spec = FeatureServiceSpec(
spec = FeatureServiceSpecProto(
name=self.name,
features=[
projection.to_proto() for projection in self.feature_view_projections
],
tags=self.tags,
description=self.description,
owner=self.owner,
)

if self.tags:
spec.tags.update(self.tags)
if self.description:
spec.description = self.description

feature_service_proto = FeatureServiceProto(spec=spec, meta=meta)
return feature_service_proto
return FeatureServiceProto(spec=spec, meta=meta)

def validate(self):
pass
22 changes: 17 additions & 5 deletions sdk/python/feast/feature_view_projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@

@dataclass
class FeatureViewProjection:
"""
A feature view projection represents a selection of one or more features from a
single feature view.

Attributes:
name: The unique name of the feature view from which this projection is created.
name_alias: An optional alias for the name.
features: The list of features represented by the feature view projection.
join_key_map: A map to modify join key columns during retrieval of this feature
view projection.
"""

name: str
name_alias: Optional[str]
features: List[Feature]
Expand All @@ -18,10 +30,10 @@ class FeatureViewProjection:
def name_to_use(self):
return self.name_alias or self.name

def to_proto(self):
def to_proto(self) -> FeatureViewProjectionProto:
feature_reference_proto = FeatureViewProjectionProto(
feature_view_name=self.name,
feature_view_name_alias=self.name_alias,
feature_view_name_alias=self.name_alias or "",
join_key_map=self.join_key_map,
)
for feature in self.features:
Expand All @@ -31,16 +43,16 @@ def to_proto(self):

@staticmethod
def from_proto(proto: FeatureViewProjectionProto):
ref = FeatureViewProjection(
feature_view_projection = FeatureViewProjection(
name=proto.feature_view_name,
name_alias=proto.feature_view_name_alias,
features=[],
join_key_map=dict(proto.join_key_map),
)
for feature_column in proto.feature_columns:
ref.features.append(Feature.from_proto(feature_column))
feature_view_projection.features.append(Feature.from_proto(feature_column))

return ref
return feature_view_projection

@staticmethod
def from_definition(feature_grouping):
Expand Down