Skip to content

Commit bd93766

Browse files
authored
Fixing the Java helm charts and adding a demo tutorial on how to use them (feast-dev#2298)
* Fixing helm chart and adding java tutorial Signed-off-by: Danny Chiao <danny@tecton.ai> * fix chart version Signed-off-by: Danny Chiao <danny@tecton.ai> * test Signed-off-by: Danny Chiao <danny@tecton.ai> * Parse the overrides to not pass enabled Signed-off-by: Danny Chiao <danny@tecton.ai> * Disable secrets by default Signed-off-by: Danny Chiao <danny@tecton.ai> * Change secrets default Signed-off-by: Danny Chiao <danny@tecton.ai> * revert Signed-off-by: Danny Chiao <danny@tecton.ai> * Update README Signed-off-by: Danny Chiao <danny@tecton.ai> * finally Signed-off-by: Danny Chiao <danny@tecton.ai> * remove credentials Signed-off-by: Danny Chiao <danny@tecton.ai> * new line Signed-off-by: Danny Chiao <danny@tecton.ai> * new line Signed-off-by: Danny Chiao <danny@tecton.ai> * new line Signed-off-by: Danny Chiao <danny@tecton.ai> * Add reference from Gitbook Signed-off-by: Danny Chiao <danny@tecton.ai> * remove description Signed-off-by: Danny Chiao <danny@tecton.ai>
1 parent 55b7cd1 commit bd93766

14 files changed

Lines changed: 343 additions & 12 deletions

File tree

docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
* [Load data into the online store](how-to-guides/feast-snowflake-gcp-aws/load-data-into-the-online-store.md)
4747
* [Read features from the online store](how-to-guides/feast-snowflake-gcp-aws/read-features-from-the-online-store.md)
4848
* [Running Feast in production](how-to-guides/running-feast-in-production.md)
49+
* [Deploying a Java feature server on Kubernetes](how-to-guides/fetching-java-features-k8s.md)
4950
* [Upgrading from Feast 0.9](https://docs.google.com/document/u/1/d/1AOsr\_baczuARjCpmZgVd8mCqTF4AZ49OEyU4Cn-uTT0/edit)
5051
* [Adding a custom provider](how-to-guides/creating-a-custom-provider.md)
5152
* [Adding a new online store](how-to-guides/adding-support-for-a-new-online-store.md)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# How to set up a Java feature server
2+
3+
This tutorial guides you on how to:
4+
5+
* Define features and data sources in Feast using the Feast CLI
6+
* Materialize features to a Redis cluster deployed on Kubernetes.
7+
* Deploy a Feast Java feature server into a Kubernetes cluster using the Feast helm charts
8+
* Retrieve features using the gRPC API exposed by the Feast Java server
9+
10+
Try it and let us know what you think!
11+
12+
| ![](../.gitbook/assets/github-mark-32px.png)[ View guide in Github](../../examples/java-demo/README.md) |
13+
|:--------------------------------------------------------------------------------------------------------|
14+
15+

examples/java-demo/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
2+
# Running Feast Java Server with Redis & calling with python (with registry in GCP)
3+
4+
For this tutorial, we setup Feast with Redis, using the Feast CLI to register and materialize features, and then retrieving via a Feast Java server deployed in Kubernetes via a gRPC call.
5+
> :point_right: for tips on how to run and debug this locally without using Kubernetes, see [java/serving/README.md](https://github.com/feast-dev/feast/blob/master/java/serving/README.md)
6+
7+
## First, let's setup a Redis cluster
8+
1. Start minikube (`minikube start`)
9+
2. Use helm to install a default Redis cluster
10+
```bash
11+
helm repo add bitnami https://charts.bitnami.com/bitnami
12+
helm repo update
13+
helm install my-redis bitnami/redis
14+
```
15+
![](redis-screenshot.png)
16+
3. Port forward Redis so we can materialize features to it
17+
18+
```bash
19+
kubectl port-forward --namespace default svc/my-redis-master 6379:6379
20+
```
21+
4. Get your Redis password using the command (pasted below for convenience). We'll need this to tell Feast how to communicate with the cluster.
22+
23+
```bash
24+
export REDIS_PASSWORD=$(kubectl get secret --namespace default my-redis -o jsonpath="{.data.redis-password}" | base64 --decode)
25+
echo $REDIS_PASSWORD
26+
```
27+
28+
## Next, we setup a local Feast repo
29+
1. Install Feast with Redis dependencies `pip install "feast[redis]"`
30+
2. Make a bucket in GCS (or S3)
31+
3. The feature repo is already setup here, so you just need to swap in your GCS bucket and Redis credentials.
32+
We need to modify the `feature_store.yaml`, which has two fields for you to replace:
33+
```yaml
34+
registry: gs://[YOUR BUCKET]/demo-repo/registry.db
35+
project: feast_java_demo
36+
provider: gcp
37+
online_store:
38+
type: redis
39+
connection_string: localhost:6379,password=[YOUR PASSWORD]
40+
offline_store:
41+
type: file
42+
flags:
43+
alpha_features: true
44+
on_demand_transforms: true
45+
```
46+
4. Run `feast apply` to apply your local features to the remote registry
47+
5. Materialize features to the online store:
48+
```bash
49+
CURRENT_TIME=$(date -u +"%Y-%m-%dT%H:%M:%S")
50+
feast materialize-incremental $CURRENT_TIME
51+
```
52+
53+
## Now let's setup the Feast Server
54+
1. Add the gcp-auth addon to mount GCP credentials:
55+
```bash
56+
minikube addons enable gcp-auth
57+
```
58+
3. Add Feast's Java feature server chart repo
59+
```bash
60+
helm repo add feast-charts https://feast-helm-charts.storage.googleapis.com
61+
helm repo update
62+
```
63+
4. Modify the application-override.yaml file to have your credentials + bucket location:
64+
```yaml
65+
feature-server:
66+
application-override.yaml:
67+
enabled: true
68+
feast:
69+
activeStore: online
70+
stores:
71+
- name: online
72+
type: REDIS
73+
config:
74+
host: my-redis-master
75+
port: 6379
76+
password: [YOUR PASSWORD]
77+
global:
78+
registry:
79+
path: gs://[YOUR BUCKET]/demo-repo/registry.db
80+
cache_ttl_seconds: 60
81+
project: feast_java_demo
82+
```
83+
5. Install the Feast helm chart: `helm install feast-release feast-charts/feast --values application-override.yaml`
84+
6. (Optional): check logs of the server to make sure it’s working
85+
```bash
86+
kubectl logs svc/feast-release-feature-server
87+
```
88+
7. Port forward to expose the grpc endpoint:
89+
```bash
90+
kubectl port-forward svc/feast-release-feature-server 6566:6566
91+
```
92+
8. Make a gRPC call:
93+
- Python example
94+
```bash
95+
python test.py
96+
```
97+
- gRPC cli:
98+
99+
```bash
100+
grpc_cli call localhost:6566 GetOnlineFeatures '
101+
features {
102+
val: "driver_hourly_stats:conv_rate"
103+
val: "driver_hourly_stats:acc_rate"
104+
}
105+
entities {
106+
key: "driver_id"
107+
value {
108+
val {
109+
int64_val: 1001
110+
}
111+
val {
112+
int64_val: 1002
113+
}
114+
}
115+
}'
116+
```
117+
118+
- Response:
119+
120+
```bash
121+
connecting to localhost:6566
122+
metadata {
123+
feature_names {
124+
val: "driver_hourly_stats:conv_rate"
125+
val: "driver_hourly_stats:acc_rate"
126+
}
127+
}
128+
results {
129+
values {
130+
float_val: 0.812357187
131+
}
132+
values {
133+
float_val: 0.379484832
134+
}
135+
statuses: PRESENT
136+
statuses: PRESENT
137+
event_timestamps {
138+
seconds: 1631725200
139+
}
140+
event_timestamps {
141+
seconds: 1631725200
142+
}
143+
}
144+
results {
145+
values {
146+
float_val: 0.840873241
147+
}
148+
values {
149+
float_val: 0.151376978
150+
}
151+
statuses: PRESENT
152+
statuses: PRESENT
153+
event_timestamps {
154+
seconds: 1631725200
155+
}
156+
event_timestamps {
157+
seconds: 1631725200
158+
}
159+
}
160+
Rpc succeeded with OK status
161+
162+
```

examples/java-demo/feature_repo/__init__.py

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
feature-server:
2+
application-override.yaml:
3+
enabled: true
4+
feast:
5+
activeStore: online
6+
stores:
7+
- name: online
8+
type: REDIS
9+
config:
10+
host: my-redis-master
11+
port: 6379
12+
password: [YOUR PASSWORD]
13+
global:
14+
registry:
15+
path: gs://[YOUR BUCKET]/demo-repo/registry.db
16+
cache_ttl_seconds: 60
17+
project: feast_java_demo
Binary file not shown.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import pandas as pd
2+
from feast import Entity, Feature, FeatureView, FileSource, ValueType
3+
from feast.data_source import RequestDataSource
4+
from feast.on_demand_feature_view import on_demand_feature_view
5+
from feast.request_feature_view import RequestFeatureView
6+
from google.protobuf.duration_pb2 import Duration
7+
8+
driver_hourly_stats = FileSource(
9+
path="data/driver_stats_with_string.parquet",
10+
event_timestamp_column="event_timestamp",
11+
created_timestamp_column="created",
12+
)
13+
driver = Entity(name="driver_id", value_type=ValueType.INT64, description="driver id",)
14+
driver_hourly_stats_view = FeatureView(
15+
name="driver_hourly_stats",
16+
entities=["driver_id"],
17+
ttl=Duration(seconds=86400000),
18+
features=[
19+
Feature(name="conv_rate", dtype=ValueType.FLOAT),
20+
Feature(name="acc_rate", dtype=ValueType.FLOAT),
21+
Feature(name="avg_daily_trips", dtype=ValueType.INT64),
22+
Feature(name="string_feature", dtype=ValueType.STRING),
23+
],
24+
online=True,
25+
batch_source=driver_hourly_stats,
26+
tags={},
27+
)
28+
29+
# Define a request data source which encodes features / information only
30+
# available at request time (e.g. part of the user initiated HTTP request)
31+
input_request = RequestDataSource(
32+
name="vals_to_add",
33+
schema={"val_to_add": ValueType.INT64, "val_to_add_2": ValueType.INT64},
34+
)
35+
36+
# Define an on demand feature view which can generate new features based on
37+
# existing feature views and RequestDataSource features
38+
@on_demand_feature_view(
39+
inputs={
40+
"driver_hourly_stats": driver_hourly_stats_view,
41+
"vals_to_add": input_request,
42+
},
43+
features=[
44+
Feature(name="conv_rate_plus_val1", dtype=ValueType.DOUBLE),
45+
Feature(name="conv_rate_plus_val2", dtype=ValueType.DOUBLE),
46+
],
47+
)
48+
def transformed_conv_rate(inputs: pd.DataFrame) -> pd.DataFrame:
49+
df = pd.DataFrame()
50+
df["conv_rate_plus_val1"] = inputs["conv_rate"] + inputs["val_to_add"]
51+
df["conv_rate_plus_val2"] = inputs["conv_rate"] + inputs["val_to_add_2"]
52+
return df
53+
54+
55+
# Define request feature view
56+
driver_age_request_fv = RequestFeatureView(
57+
name="driver_age",
58+
request_data_source=RequestDataSource(
59+
name="driver_age", schema={"driver_age": ValueType.INT64,}
60+
),
61+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
registry: gs://[YOUR BUCKET]/demo-repo/registry.db
2+
project: feast_java_demo
3+
provider: gcp
4+
online_store:
5+
type: redis
6+
connection_string: localhost:6379,password=[YOUR PASSWORD]
7+
offline_store:
8+
type: file
9+
flags:
10+
alpha_features: true
11+
on_demand_transforms: true
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import grpc
2+
from feast.protos.feast.serving.ServingService_pb2 import (
3+
FeatureList,
4+
GetOnlineFeaturesRequest,
5+
)
6+
from feast.protos.feast.serving.ServingService_pb2_grpc import ServingServiceStub
7+
from feast.protos.feast.types.Value_pb2 import RepeatedValue, Value
8+
9+
10+
# Sample logic to fetch from a local gRPC java server deployed at 6566
11+
def fetch_java():
12+
channel = grpc.insecure_channel("localhost:6566")
13+
stub = ServingServiceStub(channel)
14+
feature_refs = FeatureList(val=["driver_hourly_stats:conv_rate"])
15+
entity_rows = {
16+
"driver_id": RepeatedValue(
17+
val=[Value(int64_val=driver_id) for driver_id in range(1001, 1003)]
18+
)
19+
}
20+
21+
print(
22+
stub.GetOnlineFeatures(
23+
GetOnlineFeaturesRequest(features=feature_refs, entities=entity_rows,)
24+
)
25+
)
26+
27+
if __name__ == "__main__":
28+
fetch_java()
75.6 KB
Loading

0 commit comments

Comments
 (0)