Skip to content

Commit edefc3f

Browse files
feat: Enable static artifacts for feature server that can be used in Feature Transformations (#5787)
* feat: Enable static artifacts for feature server that can be used in Feature Transformations Signed-off-by: Francisco Javier Arceo <[email protected]> * feat: Enable static artifacts for feature server that can be used in Feature Transformations Signed-off-by: Francisco Javier Arceo <[email protected]> * feat: Enable static artifacts for feature server that can be used in Feature Transformations Signed-off-by: Francisco Javier Arceo <[email protected]> * updated docs Signed-off-by: Francisco Javier Arceo <[email protected]> * adding docs Signed-off-by: Francisco Javier Arceo <[email protected]> * update Signed-off-by: Francisco Javier Arceo <[email protected]> --------- Signed-off-by: Francisco Javier Arceo <[email protected]>
1 parent f2486a9 commit edefc3f

File tree

8 files changed

+921
-67
lines changed

8 files changed

+921
-67
lines changed

docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
* [Registry server](reference/feature-servers/registry-server.md)
159159
* [\[Beta\] Web UI](reference/alpha-web-ui.md)
160160
* [\[Beta\] On demand feature view](reference/beta-on-demand-feature-view.md)
161+
* [\[Alpha\] Static Artifacts Loading](reference/alpha-static-artifacts.md)
161162
* [\[Alpha\] Vector Database](reference/alpha-vector-database.md)
162163
* [\[Alpha\] Data quality monitoring](reference/dqm.md)
163164
* [\[Alpha\] Streaming feature computation with Denormalized](reference/denormalized.md)
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# [Alpha] Static Artifacts Loading
2+
3+
**Warning**: This is an experimental feature. To our knowledge, this is stable, but there are still rough edges in the experience. Contributions are welcome!
4+
5+
## Overview
6+
7+
Static Artifacts Loading allows you to load models, lookup tables, and other static resources once during feature server startup instead of loading them on each request. These artifacts are cached in memory and accessible to on-demand feature views for real-time inference.
8+
9+
This feature optimizes the performance of on-demand feature views that require external resources by eliminating the overhead of repeatedly loading the same artifacts during request processing.
10+
11+
### Why Use Static Artifacts Loading?
12+
13+
Static artifacts loading enables data scientists and ML engineers to:
14+
15+
1. **Improve performance**: Eliminate model loading overhead from each feature request
16+
2. **Enable complex transformations**: Use pre-trained models in on-demand feature views without performance penalties
17+
3. **Share resources**: Multiple feature views can access the same loaded artifacts
18+
4. **Simplify deployment**: Package models and lookup tables with your feature repository
19+
20+
Common use cases include:
21+
- Sentiment analysis using pre-trained transformers models
22+
- Text classification with small neural networks
23+
- Lookup-based transformations using static dictionaries
24+
- Embedding generation with pre-computed vectors
25+
26+
## How It Works
27+
28+
1. **Feature Repository Setup**: Create a `static_artifacts.py` file in your feature repository root
29+
2. **Server Startup**: When `feast serve` starts, it automatically looks for and loads the artifacts
30+
3. **Memory Storage**: Artifacts are stored in the FastAPI application state and accessible via global references
31+
4. **Request Processing**: On-demand feature views access pre-loaded artifacts for fast transformations
32+
33+
## Example 1: Basic Model Loading
34+
35+
Create a `static_artifacts.py` file in your feature repository:
36+
37+
```python
38+
# static_artifacts.py
39+
from fastapi import FastAPI
40+
from transformers import pipeline
41+
42+
def load_sentiment_model():
43+
"""Load sentiment analysis model."""
44+
return pipeline(
45+
"sentiment-analysis",
46+
model="cardiffnlp/twitter-roberta-base-sentiment-latest",
47+
device="cpu"
48+
)
49+
50+
def load_artifacts(app: FastAPI):
51+
"""Load static artifacts into app.state."""
52+
app.state.sentiment_model = load_sentiment_model()
53+
54+
# Update global references for access from feature views
55+
import example_repo
56+
example_repo._sentiment_model = app.state.sentiment_model
57+
```
58+
59+
Use the pre-loaded model in your on-demand feature view:
60+
61+
```python
62+
# example_repo.py
63+
import pandas as pd
64+
from feast.on_demand_feature_view import on_demand_feature_view
65+
from feast import Field
66+
from feast.types import String, Float32
67+
68+
# Global reference for static artifacts
69+
_sentiment_model = None
70+
71+
@on_demand_feature_view(
72+
sources=[text_input_request],
73+
schema=[
74+
Field(name="predicted_sentiment", dtype=String),
75+
Field(name="sentiment_confidence", dtype=Float32),
76+
],
77+
)
78+
def sentiment_prediction(inputs: pd.DataFrame) -> pd.DataFrame:
79+
"""Sentiment prediction using pre-loaded model."""
80+
global _sentiment_model
81+
82+
results = []
83+
for text in inputs["input_text"]:
84+
predictions = _sentiment_model(text)
85+
best_pred = max(predictions, key=lambda x: x["score"])
86+
87+
results.append({
88+
"predicted_sentiment": best_pred["label"],
89+
"sentiment_confidence": best_pred["score"],
90+
})
91+
92+
return pd.DataFrame(results)
93+
```
94+
95+
## Example 2: Multiple Artifacts with Lookup Tables
96+
97+
Load multiple types of artifacts:
98+
99+
```python
100+
# static_artifacts.py
101+
from fastapi import FastAPI
102+
from transformers import pipeline
103+
import json
104+
from pathlib import Path
105+
106+
def load_sentiment_model():
107+
"""Load sentiment analysis model."""
108+
return pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
109+
110+
def load_lookup_tables():
111+
"""Load static lookup tables."""
112+
return {
113+
"sentiment_labels": {"NEGATIVE": "negative", "POSITIVE": "positive"},
114+
"domain_categories": {"twitter.com": "social", "news.com": "news", "github.com": "tech"},
115+
"priority_users": {"user_123", "user_456", "user_789"}
116+
}
117+
118+
def load_config():
119+
"""Load application configuration."""
120+
return {
121+
"model_threshold": 0.7,
122+
"max_text_length": 512,
123+
"default_sentiment": "neutral"
124+
}
125+
126+
def load_artifacts(app: FastAPI):
127+
"""Load all static artifacts."""
128+
app.state.sentiment_model = load_sentiment_model()
129+
app.state.lookup_tables = load_lookup_tables()
130+
app.state.config = load_config()
131+
132+
# Update global references
133+
import example_repo
134+
example_repo._sentiment_model = app.state.sentiment_model
135+
example_repo._lookup_tables = app.state.lookup_tables
136+
example_repo._config = app.state.config
137+
```
138+
139+
Use multiple artifacts in feature transformations:
140+
141+
```python
142+
# example_repo.py
143+
import pandas as pd
144+
from feast.on_demand_feature_view import on_demand_feature_view
145+
146+
# Global references for static artifacts
147+
_sentiment_model = None
148+
_lookup_tables: dict = {}
149+
_config: dict = {}
150+
151+
@on_demand_feature_view(
152+
sources=[text_input_request, user_input_request],
153+
schema=[
154+
Field(name="predicted_sentiment", dtype=String),
155+
Field(name="is_priority_user", dtype=Bool),
156+
Field(name="domain_category", dtype=String),
157+
],
158+
)
159+
def enriched_prediction(inputs: pd.DataFrame) -> pd.DataFrame:
160+
"""Multi-artifact feature transformation."""
161+
global _sentiment_model, _lookup_tables, _config
162+
163+
results = []
164+
for i, row in inputs.iterrows():
165+
text = row["input_text"]
166+
user_id = row["user_id"]
167+
domain = row.get("domain", "")
168+
169+
# Use pre-loaded model
170+
predictions = _sentiment_model(text)
171+
sentiment_scores = {pred["label"]: pred["score"] for pred in predictions}
172+
173+
# Use lookup tables
174+
predicted_sentiment = _lookup_tables["sentiment_labels"].get(
175+
max(sentiment_scores, key=sentiment_scores.get),
176+
_config["default_sentiment"]
177+
)
178+
179+
is_priority = user_id in _lookup_tables["priority_users"]
180+
category = _lookup_tables["domain_categories"].get(domain, "unknown")
181+
182+
results.append({
183+
"predicted_sentiment": predicted_sentiment,
184+
"is_priority_user": is_priority,
185+
"domain_category": category,
186+
})
187+
188+
return pd.DataFrame(results)
189+
```
190+
191+
## Container Deployment
192+
193+
Static artifacts work with containerized deployments. Include your artifacts in the container image:
194+
195+
```dockerfile
196+
FROM python:3.11-slim
197+
198+
# Install dependencies
199+
COPY requirements.txt .
200+
RUN pip install -r requirements.txt
201+
202+
# Copy feature repository including static_artifacts.py
203+
COPY feature_repo/ /app/feature_repo/
204+
205+
WORKDIR /app/feature_repo
206+
207+
# Start feature server
208+
CMD ["feast", "serve", "--host", "0.0.0.0"]
209+
```
210+
211+
The server will automatically load static artifacts during container startup.
212+
213+
## Supported Artifact Types
214+
215+
### Recommended Artifacts
216+
- **Small ML models**: Sentiment analysis, text classification, small neural networks
217+
- **Lookup tables**: Label mappings, category dictionaries, user segments
218+
- **Configuration data**: Model parameters, feature mappings, business rules
219+
- **Pre-computed embeddings**: User vectors, item features, static representations
220+
221+
### Not Recommended
222+
- **Large Language Models**: Use dedicated serving solutions (vLLM, TensorRT-LLM, TGI)
223+
- **Models requiring specialized hardware**: GPU clusters, TPUs
224+
- **Frequently updated models**: Consider model registries with versioning
225+
- **Large datasets**: Use feature views with proper data sources instead
226+
227+
## Error Handling
228+
229+
Static artifacts loading includes graceful error handling:
230+
- **Missing file**: Server starts normally without static artifacts
231+
- **Loading errors**: Warnings are logged, feature views should implement fallback logic
232+
- **Partial failures**: Successfully loaded artifacts remain available
233+
234+
Always implement fallback behavior in your feature transformations:
235+
236+
```python
237+
@on_demand_feature_view(...)
238+
def robust_prediction(inputs: pd.DataFrame) -> pd.DataFrame:
239+
global _sentiment_model
240+
241+
results = []
242+
for text in inputs["input_text"]:
243+
if _sentiment_model is not None:
244+
# Use pre-loaded model
245+
predictions = _sentiment_model(text)
246+
sentiment = max(predictions, key=lambda x: x["score"])["label"]
247+
else:
248+
# Fallback when artifacts aren't available
249+
sentiment = "neutral"
250+
251+
results.append({"predicted_sentiment": sentiment})
252+
253+
return pd.DataFrame(results)
254+
```
255+
256+
## Starting the Feature Server
257+
258+
Start the feature server as usual:
259+
260+
```bash
261+
feast serve
262+
```
263+
264+
You'll see log messages indicating artifact loading:
265+
266+
```
267+
INFO:fastapi:Loading static artifacts from static_artifacts.py
268+
INFO:fastapi:Static artifacts loading completed
269+
INFO:uvicorn:Application startup complete
270+
```
271+
272+
## Template Example
273+
274+
The PyTorch NLP template demonstrates static artifacts loading:
275+
276+
```bash
277+
feast init my-nlp-project -t pytorch_nlp
278+
cd my-nlp-project/feature_repo
279+
feast serve
280+
```
281+
282+
This template includes a complete example with sentiment analysis model loading, lookup tables, and integration with on-demand feature views.
283+
284+
## Performance Considerations
285+
286+
- **Startup time**: Artifacts are loaded during server initialization, which may increase startup time
287+
- **Memory usage**: All artifacts remain in memory for the server's lifetime
288+
- **Concurrency**: Artifacts are shared across all request threads
289+
- **Container resources**: Ensure sufficient memory allocation for your artifacts
290+
291+
## Configuration
292+
293+
Currently, static artifacts loading uses convention-based configuration:
294+
- **File name**: Must be named `static_artifacts.py`
295+
- **Location**: Must be in the feature repository root directory
296+
- **Function name**: Must implement `load_artifacts(app: FastAPI)` function
297+
298+
## Limitations
299+
300+
- File name and location are currently fixed (not configurable)
301+
- Artifacts are loaded synchronously during startup
302+
- No built-in artifact versioning or hot reloading
303+
- Limited to Python-based artifacts (no external binaries)
304+
305+
## Contributing
306+
307+
This is an alpha feature and we welcome contributions! Areas for improvement:
308+
- Configurable artifact file locations
309+
- Asynchronous artifact loading
310+
- Built-in artifact versioning
311+
- Performance monitoring and metrics
312+
- Integration with model registries
313+
314+
Please report issues and contribute improvements via the [Feast GitHub repository](https://github.com/feast-dev/feast).

docs/reference/feature-servers/python-feature-server.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,48 @@ To start the feature server in TLS mode, you need to provide the private and pub
268268
feast serve --key /path/to/key.pem --cert /path/to/cert.pem
269269
```
270270

271+
# [Alpha] Static Artifacts Loading
272+
273+
**Warning**: This is an experimental feature. To our knowledge, this is stable, but there are still rough edges in the experience.
274+
275+
Static artifacts loading allows you to load models, lookup tables, and other static resources once during feature server startup instead of loading them on each request. This improves performance for on-demand feature views that require external resources.
276+
277+
## Quick Example
278+
279+
Create a `static_artifacts.py` file in your feature repository:
280+
281+
```python
282+
# static_artifacts.py
283+
from fastapi import FastAPI
284+
from transformers import pipeline
285+
286+
def load_artifacts(app: FastAPI):
287+
"""Load static artifacts into app.state."""
288+
app.state.sentiment_model = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
289+
290+
# Update global references for access from feature views
291+
import example_repo
292+
example_repo._sentiment_model = app.state.sentiment_model
293+
```
294+
295+
Access pre-loaded artifacts in your on-demand feature views:
296+
297+
```python
298+
# example_repo.py
299+
_sentiment_model = None
300+
301+
@on_demand_feature_view(...)
302+
def sentiment_prediction(inputs: pd.DataFrame) -> pd.DataFrame:
303+
global _sentiment_model
304+
return _sentiment_model(inputs["text"])
305+
```
306+
307+
## Documentation
308+
309+
For comprehensive documentation, examples, and best practices, see the [Alpha Static Artifacts Loading](../alpha-static-artifacts.md) reference guide.
310+
311+
The [PyTorch NLP template](https://github.com/feast-dev/feast/tree/main/sdk/python/feast/templates/pytorch_nlp) provides a complete working example.
312+
271313
# Online Feature Server Permissions and Access Control
272314

273315
## API Endpoints and Permissions

0 commit comments

Comments
 (0)