Visitar URL original
feat: Add optional 'org' in feature view (#6288) by nquinn408 · Pull Request #6301 · feast-dev/feast · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Adding optional org to stream feature view
Signed-off-by: Nick Quinn <nicholas_quinn@apple.com>
  • Loading branch information
nickquinn408 committed Apr 28, 2026
commit 63db9d59a01e00e7d6c554f12fd735b8780187ad
3 changes: 2 additions & 1 deletion docs/getting-started/concepts/feature-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def transformed_conv_rate(features_df: pd.DataFrame) -> pd.DataFrame:

A stream feature view is an extension of a normal feature view. The primary difference is that stream feature views have both stream and batch data sources, whereas a normal feature view only has a batch data source.

Stream feature views should be used instead of normal feature views when there are stream data sources (e.g. Kafka and Kinesis) available to provide fresh features in an online setting. Here is an example definition of a stream feature view with an attached transformation:
Stream feature views should be used instead of normal feature views when there are stream data sources (e.g. Kafka and Kinesis) available to provide fresh features in an online setting. Like regular feature views, stream feature views support the optional `org` field for grouping by organizational unit. Here is an example definition of a stream feature view with an attached transformation:

```python
from datetime import timedelta
Expand Down Expand Up @@ -310,6 +310,7 @@ driver_stats_stream_source = KafkaSource(
timestamp_field="event_timestamp",
online=True,
source=driver_stats_stream_source,
org="ads", # optional
)
def driver_hourly_stats_stream(df: DataFrame):
from pyspark.sql.functions import col
Expand Down
5 changes: 4 additions & 1 deletion protos/feast/core/StreamFeatureView.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ message StreamFeatureView {
FeatureViewMeta meta = 2;
}

// Next available id: 22
// Next available id: 23
message StreamFeatureViewSpec {
// Name of the feature view. Must be unique. Not updated.
string name = 1;
Expand Down Expand Up @@ -105,5 +105,8 @@ message StreamFeatureViewSpec {

// User-specified version pin (e.g. "latest", "v2", "version2")
string version = 21;

// Organizational unit that owns this stream feature view (e.g. "ads", "search").
string org = 22;
}

711 changes: 381 additions & 330 deletions sdk/python/feast/protos/feast/core/DataSource_pb2.pyi

Large diffs are not rendered by default.

181 changes: 99 additions & 82 deletions sdk/python/feast/protos/feast/core/Entity_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,130 +16,147 @@ isort:skip_file
* See the License for the specific language governing permissions and
* limitations under the License.
"""
import builtins
import collections.abc
from feast.protos.feast.types import Value_pb2 as _feast_types_Value_pb2
import google.protobuf.descriptor
import google.protobuf.internal.containers
import google.protobuf.message
import google.protobuf.timestamp_pb2

from collections import abc as _abc
from feast.protos.feast.types import Value_pb2 as _Value_pb2
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import timestamp_pb2 as _timestamp_pb2
from google.protobuf.internal import containers as _containers
import builtins as _builtins
import sys
import typing as _typing

if sys.version_info >= (3, 8):
import typing as typing_extensions
if sys.version_info >= (3, 10):
from typing import TypeAlias as _TypeAlias
else:
import typing_extensions
from typing_extensions import TypeAlias as _TypeAlias

DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
DESCRIPTOR: _descriptor.FileDescriptor

class Entity(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class Entity(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

SPEC_FIELD_NUMBER: builtins.int
META_FIELD_NUMBER: builtins.int
@property
def spec(self) -> global___EntitySpecV2:
SPEC_FIELD_NUMBER: _builtins.int
META_FIELD_NUMBER: _builtins.int
@_builtins.property
def spec(self) -> Global___EntitySpecV2:
"""User-specified specifications of this entity."""
@property
def meta(self) -> global___EntityMeta:

@_builtins.property
def meta(self) -> Global___EntityMeta:
"""System-populated metadata for this entity."""

def __init__(
self,
*,
spec: global___EntitySpecV2 | None = ...,
meta: global___EntityMeta | None = ...,
spec: Global___EntitySpecV2 | None = ...,
meta: Global___EntityMeta | None = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["meta", b"meta", "spec", b"spec"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["meta", b"meta", "spec", b"spec"]) -> None: ...
_HasFieldArgType: _TypeAlias = _typing.Literal["meta", b"meta", "spec", b"spec"] # noqa: Y015
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
_ClearFieldArgType: _TypeAlias = _typing.Literal["meta", b"meta", "spec", b"spec"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

global___Entity = Entity
Global___Entity: _TypeAlias = Entity # noqa: Y015

class EntitySpecV2(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class EntitySpecV2(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

class TagsEntry(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class TagsEntry(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

KEY_FIELD_NUMBER: builtins.int
VALUE_FIELD_NUMBER: builtins.int
key: builtins.str
value: builtins.str
KEY_FIELD_NUMBER: _builtins.int
VALUE_FIELD_NUMBER: _builtins.int
key: _builtins.str
value: _builtins.str
def __init__(
self,
*,
key: builtins.str = ...,
value: builtins.str = ...,
key: _builtins.str = ...,
value: _builtins.str = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ...

NAME_FIELD_NUMBER: builtins.int
PROJECT_FIELD_NUMBER: builtins.int
VALUE_TYPE_FIELD_NUMBER: builtins.int
DESCRIPTION_FIELD_NUMBER: builtins.int
JOIN_KEY_FIELD_NUMBER: builtins.int
TAGS_FIELD_NUMBER: builtins.int
OWNER_FIELD_NUMBER: builtins.int
name: builtins.str
_ClearFieldArgType: _TypeAlias = _typing.Literal["key", b"key", "value", b"value"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

NAME_FIELD_NUMBER: _builtins.int
PROJECT_FIELD_NUMBER: _builtins.int
VALUE_TYPE_FIELD_NUMBER: _builtins.int
DESCRIPTION_FIELD_NUMBER: _builtins.int
JOIN_KEY_FIELD_NUMBER: _builtins.int
TAGS_FIELD_NUMBER: _builtins.int
OWNER_FIELD_NUMBER: _builtins.int
name: _builtins.str
"""Name of the entity."""
project: builtins.str
project: _builtins.str
"""Name of Feast project that this feature table belongs to."""
value_type: _feast_types_Value_pb2.ValueType.Enum.ValueType
value_type: _Value_pb2.ValueType.Enum.ValueType
"""Type of the entity."""
description: builtins.str
description: _builtins.str
"""Description of the entity."""
join_key: builtins.str
join_key: _builtins.str
"""Join key for the entity (i.e. name of the column the entity maps to)."""
@property
def tags(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
"""User defined metadata"""
owner: builtins.str
owner: _builtins.str
"""Owner of the entity."""
@_builtins.property
def tags(self) -> _containers.ScalarMap[_builtins.str, _builtins.str]:
"""User defined metadata"""

def __init__(
self,
*,
name: builtins.str = ...,
project: builtins.str = ...,
value_type: _feast_types_Value_pb2.ValueType.Enum.ValueType = ...,
description: builtins.str = ...,
join_key: builtins.str = ...,
tags: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
owner: builtins.str = ...,
name: _builtins.str = ...,
project: _builtins.str = ...,
value_type: _Value_pb2.ValueType.Enum.ValueType = ...,
description: _builtins.str = ...,
join_key: _builtins.str = ...,
tags: _abc.Mapping[_builtins.str, _builtins.str] | None = ...,
owner: _builtins.str = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["description", b"description", "join_key", b"join_key", "name", b"name", "owner", b"owner", "project", b"project", "tags", b"tags", "value_type", b"value_type"]) -> None: ...
_ClearFieldArgType: _TypeAlias = _typing.Literal["description", b"description", "join_key", b"join_key", "name", b"name", "owner", b"owner", "project", b"project", "tags", b"tags", "value_type", b"value_type"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

global___EntitySpecV2 = EntitySpecV2
Global___EntitySpecV2: _TypeAlias = EntitySpecV2 # noqa: Y015

class EntityMeta(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class EntityMeta(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

CREATED_TIMESTAMP_FIELD_NUMBER: builtins.int
LAST_UPDATED_TIMESTAMP_FIELD_NUMBER: builtins.int
@property
def created_timestamp(self) -> google.protobuf.timestamp_pb2.Timestamp: ...
@property
def last_updated_timestamp(self) -> google.protobuf.timestamp_pb2.Timestamp: ...
CREATED_TIMESTAMP_FIELD_NUMBER: _builtins.int
LAST_UPDATED_TIMESTAMP_FIELD_NUMBER: _builtins.int
@_builtins.property
def created_timestamp(self) -> _timestamp_pb2.Timestamp: ...
@_builtins.property
def last_updated_timestamp(self) -> _timestamp_pb2.Timestamp: ...
def __init__(
self,
*,
created_timestamp: google.protobuf.timestamp_pb2.Timestamp | None = ...,
last_updated_timestamp: google.protobuf.timestamp_pb2.Timestamp | None = ...,
created_timestamp: _timestamp_pb2.Timestamp | None = ...,
last_updated_timestamp: _timestamp_pb2.Timestamp | None = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["created_timestamp", b"created_timestamp", "last_updated_timestamp", b"last_updated_timestamp"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["created_timestamp", b"created_timestamp", "last_updated_timestamp", b"last_updated_timestamp"]) -> None: ...
_HasFieldArgType: _TypeAlias = _typing.Literal["created_timestamp", b"created_timestamp", "last_updated_timestamp", b"last_updated_timestamp"] # noqa: Y015
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
_ClearFieldArgType: _TypeAlias = _typing.Literal["created_timestamp", b"created_timestamp", "last_updated_timestamp", b"last_updated_timestamp"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

global___EntityMeta = EntityMeta
Global___EntityMeta: _TypeAlias = EntityMeta # noqa: Y015

class EntityList(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class EntityList(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

ENTITIES_FIELD_NUMBER: builtins.int
@property
def entities(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Entity]: ...
ENTITIES_FIELD_NUMBER: _builtins.int
@_builtins.property
def entities(self) -> _containers.RepeatedCompositeFieldContainer[Global___Entity]: ...
def __init__(
self,
*,
entities: collections.abc.Iterable[global___Entity] | None = ...,
entities: _abc.Iterable[Global___Entity] | None = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["entities", b"entities"]) -> None: ...
_ClearFieldArgType: _TypeAlias = _typing.Literal["entities", b"entities"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

global___EntityList = EntityList
Global___EntityList: _TypeAlias = EntityList # noqa: Y015
99 changes: 53 additions & 46 deletions sdk/python/feast/protos/feast/core/Feature_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,72 +16,79 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import builtins
import collections.abc
from feast.protos.feast.types import Value_pb2 as _feast_types_Value_pb2
import google.protobuf.descriptor
import google.protobuf.internal.containers
import google.protobuf.message

from collections import abc as _abc
from feast.protos.feast.types import Value_pb2 as _Value_pb2
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf.internal import containers as _containers
import builtins as _builtins
import sys
import typing as _typing

if sys.version_info >= (3, 8):
import typing as typing_extensions
if sys.version_info >= (3, 10):
from typing import TypeAlias as _TypeAlias
else:
import typing_extensions
from typing_extensions import TypeAlias as _TypeAlias

DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
DESCRIPTOR: _descriptor.FileDescriptor

class FeatureSpecV2(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class FeatureSpecV2(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

class TagsEntry(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
@_typing.final
class TagsEntry(_message.Message):
DESCRIPTOR: _descriptor.Descriptor

KEY_FIELD_NUMBER: builtins.int
VALUE_FIELD_NUMBER: builtins.int
key: builtins.str
value: builtins.str
KEY_FIELD_NUMBER: _builtins.int
VALUE_FIELD_NUMBER: _builtins.int
key: _builtins.str
value: _builtins.str
def __init__(
self,
*,
key: builtins.str = ...,
value: builtins.str = ...,
key: _builtins.str = ...,
value: _builtins.str = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"]) -> None: ...
_ClearFieldArgType: _TypeAlias = _typing.Literal["key", b"key", "value", b"value"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

NAME_FIELD_NUMBER: builtins.int
VALUE_TYPE_FIELD_NUMBER: builtins.int
TAGS_FIELD_NUMBER: builtins.int
DESCRIPTION_FIELD_NUMBER: builtins.int
VECTOR_INDEX_FIELD_NUMBER: builtins.int
VECTOR_SEARCH_METRIC_FIELD_NUMBER: builtins.int
VECTOR_LENGTH_FIELD_NUMBER: builtins.int
name: builtins.str
NAME_FIELD_NUMBER: _builtins.int
VALUE_TYPE_FIELD_NUMBER: _builtins.int
TAGS_FIELD_NUMBER: _builtins.int
DESCRIPTION_FIELD_NUMBER: _builtins.int
VECTOR_INDEX_FIELD_NUMBER: _builtins.int
VECTOR_SEARCH_METRIC_FIELD_NUMBER: _builtins.int
VECTOR_LENGTH_FIELD_NUMBER: _builtins.int
name: _builtins.str
"""Name of the feature. Not updatable."""
value_type: _feast_types_Value_pb2.ValueType.Enum.ValueType
value_type: _Value_pb2.ValueType.Enum.ValueType
"""Value type of the feature. Not updatable."""
@property
def tags(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]:
"""Tags for user defined metadata on a feature"""
description: builtins.str
description: _builtins.str
"""Description of the feature."""
vector_index: builtins.bool
vector_index: _builtins.bool
"""Field indicating the vector will be indexed for vector similarity search"""
vector_search_metric: builtins.str
vector_search_metric: _builtins.str
"""Metric used for vector similarity search."""
vector_length: builtins.int
vector_length: _builtins.int
"""Field indicating the vector length"""
@_builtins.property
def tags(self) -> _containers.ScalarMap[_builtins.str, _builtins.str]:
"""Tags for user defined metadata on a feature"""

def __init__(
self,
*,
name: builtins.str = ...,
value_type: _feast_types_Value_pb2.ValueType.Enum.ValueType = ...,
tags: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
description: builtins.str = ...,
vector_index: builtins.bool = ...,
vector_search_metric: builtins.str = ...,
vector_length: builtins.int = ...,
name: _builtins.str = ...,
value_type: _Value_pb2.ValueType.Enum.ValueType = ...,
tags: _abc.Mapping[_builtins.str, _builtins.str] | None = ...,
description: _builtins.str = ...,
vector_index: _builtins.bool = ...,
vector_search_metric: _builtins.str = ...,
vector_length: _builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["description", b"description", "name", b"name", "tags", b"tags", "value_type", b"value_type", "vector_index", b"vector_index", "vector_length", b"vector_length", "vector_search_metric", b"vector_search_metric"]) -> None: ...
_ClearFieldArgType: _TypeAlias = _typing.Literal["description", b"description", "name", b"name", "tags", b"tags", "value_type", b"value_type", "vector_index", b"vector_index", "vector_length", b"vector_length", "vector_search_metric", b"vector_search_metric"] # noqa: Y015
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...

global___FeatureSpecV2 = FeatureSpecV2
Global___FeatureSpecV2: _TypeAlias = FeatureSpecV2 # noqa: Y015
Loading
Loading