Skip to content

Commit

Permalink
Adding python classes for new Feature View type SortedFeatureView
Browse files Browse the repository at this point in the history
  • Loading branch information
Manisha4 committed Feb 14, 2025
1 parent edda840 commit 76c29da
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 35 deletions.
7 changes: 5 additions & 2 deletions sdk/python/feast/base_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
from feast.protos.feast.core.StreamFeatureView_pb2 import (
StreamFeatureView as StreamFeatureViewProto,
)
from feast.protos.feast.core.SortedFeatureView_pb2 import (
SortedFeatureView as SortedFeatureViewProto,
)


class BaseFeatureView(ABC):
Expand Down Expand Up @@ -98,7 +101,7 @@ def proto_class(self) -> Type[Message]:
@abstractmethod
def to_proto(
self,
) -> Union[FeatureViewProto, OnDemandFeatureViewProto, StreamFeatureViewProto]:
) -> Union[FeatureViewProto, OnDemandFeatureViewProto, StreamFeatureViewProto, SortedFeatureViewProto]:
pass

@classmethod
Expand Down Expand Up @@ -237,4 +240,4 @@ def with_projection(self, feature_view_projection: FeatureViewProjection):
cp = self.__copy__()
cp.projection = feature_view_projection

return cp
return cp
36 changes: 25 additions & 11 deletions sdk/python/feast/sort_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from feast.entity import Entity
from feast.protos.feast.core.SortedFeatureView_pb2 import (
SortKey as SortKeyProto,
)
from feast.protos.feast.core.SortedFeatureView_pb2 import (
SortOrder,
)
from feast.value_type import ValueType
Expand All @@ -28,26 +30,40 @@ class SortKey:
"""
A helper class representing a sorting key for a SortedFeatureView.
"""

name: str
value_type: ValueType
default_sort_order: int # Using the integer values from the SortOrder enum
default_sort_order: int
tags: Dict[str, str]
description: str

def __init__(
self,
name: str,
value_type: ValueType,
default_sort_order: int = SortOrder.ASC,
tags: Optional[Dict[str, str]] = None,
description: str = "",
self,
name: str,
value_type: ValueType,
default_sort_order: int = int(SortOrder.Enum.ASC),
tags: Optional[Dict[str, str]] = None,
description: str = "",
):
self.name = name
self.value_type = value_type
self.default_sort_order = default_sort_order
self.tags = tags or {}
self.description = description

def ensure_valid(self):
"""
Validates that the SortKey has the required fields.
"""
if not self.name:
raise ValueError("SortKey must have a non-empty name.")
if not isinstance(self.value_type, ValueType):
raise ValueError("SortKey must have a valid value_type of type ValueType.")
if self.default_sort_order not in (SortOrder.ASC, SortOrder.DESC):
raise ValueError(
"SortKey default_sort_order must be either SortOrder.ASC or SortOrder.DESC."
)

def to_proto(self) -> SortKeyProto:
proto = SortKeyProto(
name=self.name,
Expand All @@ -60,12 +76,10 @@ def to_proto(self) -> SortKeyProto:

@classmethod
def from_proto(cls, proto: SortKeyProto) -> "SortKey":
# Assuming ValueType.from_proto exists.
vt = ValueType.from_proto(proto.value_type)
return cls(
name=proto.name,
value_type=vt,
default_sort_order=proto.default_sort_order,
value_type=ValueType(proto.value_type),
default_sort_order=int(proto.default_sort_order),
tags=dict(proto.tags),
description=proto.description,
)
58 changes: 36 additions & 22 deletions sdk/python/feast/sorted_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
from datetime import timedelta
from typing import Dict, List, Optional, Type

from typeguard import typechecked
from google.protobuf.message import Message
from typeguard import typechecked

from feast import utils, FeatureView
from feast import FeatureView, utils
from feast.data_source import DataSource
from feast.entity import Entity
from feast.feature_view_projection import FeatureViewProjection
from feast.field import Field
from feast.protos.feast.core.SortedFeatureView_pb2 import (
SortedFeatureView as SortedFeatureViewProto,
)
from feast.protos.feast.core.SortedFeatureView_pb2 import (
SortedFeatureViewSpec as SortedFeatureViewSpecProto,
)
from feast.sort_key import SortKey
Expand All @@ -36,21 +38,22 @@ class SortedFeatureView(FeatureView):
SortedFeatureView extends FeatureView by adding support for range queries
via sort keys.
"""

sort_keys: List[SortKey]

def __init__(
self,
*,
name: str,
source: DataSource,
schema: Optional[List[Field]] = None,
entities: Optional[List[Entity]] = None,
ttl: Optional[timedelta] = timedelta(days=0),
online: bool = True,
description: str = "",
tags: Optional[Dict[str, str]] = None,
owner: str = "",
sort_keys: Optional[List[SortKey]] = None,
self,
*,
name: str,
source: DataSource,
schema: Optional[List[Field]] = None,
entities: Optional[List[Entity]] = None,
ttl: Optional[timedelta] = timedelta(days=0),
online: bool = True,
description: str = "",
tags: Optional[Dict[str, str]] = None,
owner: str = "",
sort_keys: Optional[List[SortKey]] = None,
):
super().__init__(
name=name,
Expand Down Expand Up @@ -84,11 +87,24 @@ def __copy__(self):
sfv.projection = copy.copy(self.projection)
return sfv

def ensure_valid(self):
"""
Validates the state of this SortedFeatureView.
This includes the base FeatureView validations and ensures that at least one sort key is defined.
"""
super().ensure_valid()

# Check that sort_keys is not empty.
if not self.sort_keys:
raise ValueError(
"SortedFeatureView must have at least one sort key defined."
)

@property
def proto_class(self) -> Type[Message]:
return SortedFeatureViewProto

def to_proto(self) -> SortedFeatureViewProto:
def to_proto(self):
"""
Converts this SortedFeatureView to its protobuf representation.
"""
Expand Down Expand Up @@ -131,7 +147,7 @@ def to_proto(self) -> SortedFeatureViewProto:
return SortedFeatureViewProto(spec=spec, meta=meta)

@classmethod
def from_proto(cls, sfv_proto: SortedFeatureViewProto) -> "SortedFeatureView":
def from_proto(cls, sfv_proto):
"""
Creates a SortedFeatureView from its protobuf representation.
"""
Expand All @@ -157,8 +173,8 @@ def from_proto(cls, sfv_proto: SortedFeatureViewProto) -> "SortedFeatureView":
else spec.ttl.ToTimedelta()
),
source=batch_source,
schema=None, # schema will be inferred from the fields below
entities=None, # will be set below
schema=None,
entities=None,
sort_keys=[SortKey.from_proto(sk) for sk in spec.sort_keys],
)

Expand All @@ -169,14 +185,12 @@ def from_proto(cls, sfv_proto: SortedFeatureViewProto) -> "SortedFeatureView":
sorted_feature_view.original_entities = [
Entity.from_proto(e) for e in spec.original_entities
]
sorted_feature_view.features = [
Field.from_proto(f) for f in spec.features
]
sorted_feature_view.features = [Field.from_proto(f) for f in spec.features]
sorted_feature_view.entity_columns = [
Field.from_proto(f) for f in spec.entity_columns
]
sorted_feature_view.original_schema = (
sorted_feature_view.entity_columns + sorted_feature_view.features
sorted_feature_view.entity_columns + sorted_feature_view.features
)

sorted_feature_view.projection = FeatureViewProjection.from_definition(
Expand Down

0 comments on commit 76c29da

Please sign in to comment.