Skip to content

Commit d1f76e5

Browse files
authored
feat: Create stream and batch feature view abstractions (#2559)
* feat: Create stream and batch feature view abstractions Signed-off-by: Achal Shah <[email protected]> * CR Signed-off-by: Achal Shah <[email protected]> * CR Signed-off-by: Achal Shah <[email protected]>
1 parent 54ad3b6 commit d1f76e5

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ The services with containerized replacements currently implemented are:
176176
- Datastore
177177
- DynamoDB
178178
- Redis
179+
- Trino
179180

180181
You can run `make test-python-integration-container` to run tests against the containerized versions of dependencies.
181182

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from datetime import timedelta
2+
from typing import Dict, List, Optional, Union
3+
4+
from feast.data_source import DataSource
5+
from feast.entity import Entity
6+
from feast.feature_view import FeatureView
7+
from feast.field import Field
8+
from feast.protos.feast.core.DataSource_pb2 import DataSource as DataSourceProto
9+
10+
SUPPORTED_BATCH_SOURCES = {
11+
"BigQuerySource",
12+
"FileSource",
13+
"RedshiftSource",
14+
"SnowflakeSource",
15+
"SparkSource",
16+
"TrinoSource",
17+
}
18+
19+
20+
class BatchFeatureView(FeatureView):
21+
def __init__(
22+
self,
23+
*,
24+
name: Optional[str] = None,
25+
entities: Optional[Union[List[Entity], List[str]]] = None,
26+
ttl: Optional[timedelta] = None,
27+
tags: Optional[Dict[str, str]] = None,
28+
online: bool = True,
29+
description: str = "",
30+
owner: str = "",
31+
schema: Optional[List[Field]] = None,
32+
source: Optional[DataSource] = None,
33+
):
34+
35+
if source is None:
36+
raise ValueError("Feature views need a source specified")
37+
if (
38+
type(source).__name__ not in SUPPORTED_BATCH_SOURCES
39+
and source.to_proto().type != DataSourceProto.SourceType.CUSTOM_SOURCE
40+
):
41+
raise ValueError(
42+
f"Batch feature views need a batch source, expected one of {SUPPORTED_BATCH_SOURCES} "
43+
f"or CUSTOM_SOURCE, got {type(source).__name__}: {source.name} instead "
44+
)
45+
46+
super().__init__(
47+
name=name,
48+
entities=entities,
49+
ttl=ttl,
50+
batch_source=None,
51+
stream_source=None,
52+
tags=tags,
53+
online=online,
54+
description=description,
55+
owner=owner,
56+
schema=schema,
57+
source=source,
58+
)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from datetime import timedelta
2+
from typing import Dict, List, Optional, Union
3+
4+
from feast.data_source import DataSource
5+
from feast.entity import Entity
6+
from feast.feature_view import FeatureView
7+
from feast.field import Field
8+
from feast.protos.feast.core.DataSource_pb2 import DataSource as DataSourceProto
9+
10+
SUPPORTED_STREAM_SOURCES = {
11+
"KafkaSource",
12+
"KinesisSource",
13+
}
14+
15+
16+
class StreamFeatureView(FeatureView):
17+
def __init__(
18+
self,
19+
*,
20+
name: Optional[str] = None,
21+
entities: Optional[Union[List[Entity], List[str]]] = None,
22+
ttl: Optional[timedelta] = None,
23+
tags: Optional[Dict[str, str]] = None,
24+
online: bool = True,
25+
description: str = "",
26+
owner: str = "",
27+
schema: Optional[List[Field]] = None,
28+
source: Optional[DataSource] = None,
29+
):
30+
31+
if source is None:
32+
raise ValueError("Feature views need a source specified")
33+
if (
34+
type(source).__name__ not in SUPPORTED_STREAM_SOURCES
35+
and source.to_proto().type != DataSourceProto.SourceType.CUSTOM_SOURCE
36+
):
37+
raise ValueError(
38+
f"Stream feature views need a stream source, expected one of {SUPPORTED_STREAM_SOURCES} "
39+
f"or CUSTOM_SOURCE, got {type(source).__name__}: {source.name} instead "
40+
)
41+
42+
super().__init__(
43+
name=name,
44+
entities=entities,
45+
ttl=ttl,
46+
batch_source=None,
47+
stream_source=None,
48+
tags=tags,
49+
online=online,
50+
description=description,
51+
owner=owner,
52+
schema=schema,
53+
source=source,
54+
)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from datetime import timedelta
2+
3+
import pytest
4+
5+
from feast.batch_feature_view import BatchFeatureView
6+
from feast.data_format import AvroFormat
7+
from feast.data_source import KafkaSource
8+
from feast.infra.offline_stores.file_source import FileSource
9+
from feast.stream_feature_view import StreamFeatureView
10+
11+
12+
def test_create_batch_feature_view():
13+
batch_source = FileSource(path="some path")
14+
BatchFeatureView(
15+
name="test batch feature view",
16+
entities=[],
17+
ttl=timedelta(days=30),
18+
source=batch_source,
19+
)
20+
21+
with pytest.raises(ValueError):
22+
BatchFeatureView(
23+
name="test batch feature view", entities=[], ttl=timedelta(days=30)
24+
)
25+
26+
stream_source = KafkaSource(
27+
name="kafka",
28+
event_timestamp_column="",
29+
bootstrap_servers="",
30+
message_format=AvroFormat(""),
31+
topic="topic",
32+
batch_source=FileSource(path="some path"),
33+
)
34+
with pytest.raises(ValueError):
35+
BatchFeatureView(
36+
name="test batch feature view",
37+
entities=[],
38+
ttl=timedelta(days=30),
39+
source=stream_source,
40+
)
41+
42+
43+
def test_create_stream_feature_view():
44+
stream_source = KafkaSource(
45+
name="kafka",
46+
event_timestamp_column="",
47+
bootstrap_servers="",
48+
message_format=AvroFormat(""),
49+
topic="topic",
50+
batch_source=FileSource(path="some path"),
51+
)
52+
StreamFeatureView(
53+
name="test batch feature view",
54+
entities=[],
55+
ttl=timedelta(days=30),
56+
source=stream_source,
57+
)
58+
59+
with pytest.raises(ValueError):
60+
StreamFeatureView(
61+
name="test batch feature view", entities=[], ttl=timedelta(days=30)
62+
)
63+
64+
with pytest.raises(ValueError):
65+
StreamFeatureView(
66+
name="test batch feature view",
67+
entities=[],
68+
ttl=timedelta(days=30),
69+
source=FileSource(path="some path"),
70+
)

0 commit comments

Comments
 (0)