Skip to content

Commit

Permalink
Add FeatureService proto definition (#1676)
Browse files Browse the repository at this point in the history
* Add FeatureService protos

Signed-off-by: Achal Shah <achals@gmail.com>

* Add python classes

Signed-off-by: Achal Shah <achals@gmail.com>

* remove import

Signed-off-by: Achal Shah <achals@gmail.com>

* Remove entities

Signed-off-by: Achal Shah <achals@gmail.com>

* Rename to FeatureViewProjection

Signed-off-by: Achal Shah <achals@gmail.com>

* Update imports after renaming

Signed-off-by: Achal Shah <achals@gmail.com>
  • Loading branch information
achals authored Jul 6, 2021
1 parent cb1e7d7 commit 4d0ea72
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 3 deletions.
42 changes: 42 additions & 0 deletions protos/feast/core/FeatureService.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
syntax = "proto3";
package feast.core;

option go_package = "github.com/feast-dev/feast/sdk/go/protos/feast/core";
option java_outer_classname = "FeatureServiceProto";
option java_package = "feast.proto.core";

import "google/protobuf/timestamp.proto";
import "feast/core/FeatureViewProjection.proto";

message FeatureService {
// User-specified specifications of this feature service.
FeatureServiceSpec spec = 1;

// System-populated metadata for this feature service.
FeatureServiceMeta meta = 2;
}

message FeatureServiceSpec {
// Name of the Feature Service. Must be unique. Not updated.
string name = 1;

// Name of Feast project that this Feature Service belongs to.
string project = 2;

// List of features that this feature service encapsulates.
// Stored as a list of references to other features views and the features from those views.
repeated FeatureViewProjection features = 3;

// User defined metadata
map<string,string> tags = 4;
}


message FeatureServiceMeta {
// Time where this Feature Service is created
google.protobuf.Timestamp created_timestamp = 1;

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

}
18 changes: 18 additions & 0 deletions protos/feast/core/FeatureViewProjection.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";
package feast.core;

option go_package = "github.com/feast-dev/feast/sdk/go/protos/feast/core";
option java_outer_classname = "FeatureReferenceProto";
option java_package = "feast.proto.core";

import "feast/core/Feature.proto";


// A reference to features in a feature view
message FeatureViewProjection {
// The feature view name
string feature_view_name = 1;

// The features of the feature view that are a part of the feature reference.
repeated FeatureSpecV2 feature_columns = 2;
}
84 changes: 84 additions & 0 deletions sdk/python/feast/feature_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from datetime import datetime
from typing import List, Optional, Union

from feast.feature_table import FeatureTable
from feast.feature_view import FeatureView
from feast.feature_view_projection import FeatureViewProjection
from feast.protos.feast.core.FeatureService_pb2 import (
FeatureService as FeatureServiceProto,
)
from feast.protos.feast.core.FeatureService_pb2 import (
FeatureServiceMeta,
FeatureServiceSpec,
)


class FeatureService:
name: str
features: List[FeatureViewProjection]
created_timestamp: Optional[datetime] = None
last_updated_timestamp: Optional[datetime] = None

def __init__(
self,
name: str,
features: List[Union[FeatureTable, FeatureView, FeatureViewProjection]],
):
self.name = name
self.features = []
for feature in features:
if isinstance(feature, FeatureTable) or isinstance(feature, FeatureView):
self.features.append(FeatureViewProjection.from_definition(feature))
elif isinstance(feature, FeatureViewProjection):
self.features.append(feature)
else:
raise ValueError(f"Unexpected type: {type(feature)}")

def __eq__(self, other):
pass

@staticmethod
def from_proto(feature_service_proto: FeatureServiceProto):
fs = FeatureService(
name=feature_service_proto.spec.name,
features=[
FeatureViewProjection.from_proto(fp)
for fp in feature_service_proto.spec.features
],
)

if feature_service_proto.meta.HasField("created_timestamp"):
fs.created_timestamp = (
feature_service_proto.meta.created_timestamp.ToDatetime()
)
if feature_service_proto.meta.HasField("last_updated_timestamp"):
fs.last_updated_timestamp = (
feature_service_proto.meta.last_updated_timestamp.ToDatetime()
)

return fs

def to_proto(self):
meta = FeatureServiceMeta()
if self.created_timestamp:
meta.created_timestamp.FromDatetime(self.created_timestamp)

spec = FeatureServiceSpec()
spec.name = self.name
for definition in self.features:
if isinstance(definition, FeatureTable) or isinstance(
definition, FeatureView
):
feature_ref = FeatureViewProjection(
definition.name, definition.features
)
else:
feature_ref = definition

spec.features.append(feature_ref.to_proto())

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

def validate(self):
pass
11 changes: 11 additions & 0 deletions sdk/python/feast/feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from feast.data_source import DataSource
from feast.errors import RegistryInferenceFailure
from feast.feature import Feature
from feast.feature_view_projection import FeatureViewProjection
from feast.protos.feast.core.FeatureView_pb2 import FeatureView as FeatureViewProto
from feast.protos.feast.core.FeatureView_pb2 import (
FeatureViewMeta as FeatureViewMetaProto,
Expand Down Expand Up @@ -110,6 +111,16 @@ def __str__(self):
def __hash__(self):
return hash(self.name)

def __getitem__(self, item) -> FeatureViewProjection:
assert isinstance(item, list)

referenced_features = []
for feature in self.features:
if feature.name in item:
referenced_features.append(feature)

return FeatureViewProjection(self.name, referenced_features)

def __eq__(self, other):
if not isinstance(other, FeatureView):
raise TypeError(
Expand Down
37 changes: 37 additions & 0 deletions sdk/python/feast/feature_view_projection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import List

from attr import dataclass

from feast.feature import Feature
from feast.protos.feast.core.FeatureViewProjection_pb2 import (
FeatureViewProjection as FeatureViewProjectionProto,
)


@dataclass
class FeatureViewProjection:
name: str
features: List[Feature]

def to_proto(self):
feature_reference_proto = FeatureViewProjectionProto(
feature_view_name=self.name
)
for feature in self.features:
feature_reference_proto.feature_columns.append(feature.to_proto())

return feature_reference_proto

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

return ref

@staticmethod
def from_definition(feature_definition):
return FeatureViewProjection(
name=feature_definition.name, features=feature_definition.features
)
2 changes: 1 addition & 1 deletion sdk/python/tensorflow_metadata/proto/v0/path_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/python/tensorflow_metadata/proto/v0/schema_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/python/tensorflow_metadata/proto/v0/statistics_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4d0ea72

Please # to comment.