Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,40 @@ for version in client.list_model_versions("my-model"):
print(f"Version: {version.name}")
```

### Manage features with Feast

**Install Feast support:**
```bash
pip install 'kubeflow[feast]'
```

Feast is a feature store that enables offline retrieval of historical datasets and online serving of features/data for ML applications.

The FeastClient provides simplified initialization. Access full Feast functionality through the `feature_store` property:

```python
from kubeflow.feast import FeastClient

# Initialize the Feast client with your feature repository path
client = FeastClient(repo_path="/path/to/feast/repo")

# Access full Feast functionality through feature_store property
online_features = client.feature_store.get_online_features(
features=["feature_view:feature1", "feature_view:feature2"],
entity_rows=[{"entity_id": 1}, {"entity_id": 2}],
)

# Materialize features to the online store
from datetime import datetime, timedelta
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
client.feature_store.materialize(start_date=start_date, end_date=end_date)

# List all feature views
for fv in client.feature_store.list_feature_views():
print(f"Feature view: {fv.name}")
```

## Local Development

Kubeflow Trainer client supports local development without needing a Kubernetes cluster.
Expand Down Expand Up @@ -186,6 +220,7 @@ job_id = client.train(trainer=CustomTrainer(func=train_fn))
| **Kubeflow Trainer** | ✅ **Available** | v2.0.0+ | Train and fine-tune AI models with various frameworks |
| **Kubeflow Katib** | ✅ **Available** | v0.19.0+ | Hyperparameter optimization |
| **Kubeflow Model Registry** | ✅ **Available** | v0.3.0+ | Manage model artifacts, versions and ML artifacts metadata |
| **Feast** | ✅ **Available** | v0.59.0+ | Feature store for offline and online feature serving |
| **Kubeflow Pipelines** | 🚧 Planned | TBD | Build, run, and track AI workflows |
| **Kubeflow Spark Operator** | 🚧 Planned | TBD | Manage Spark applications for data processing and feature engineering |

Expand Down
17 changes: 17 additions & 0 deletions kubeflow/feast/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2025 The Kubeflow Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.

from kubeflow.feast.api.feast_client import FeastClient

__all__ = ["FeastClient"]
13 changes: 13 additions & 0 deletions kubeflow/feast/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2025 The Kubeflow Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
101 changes: 101 additions & 0 deletions kubeflow/feast/api/feast_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Copyright 2025 The Kubeflow Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.

from __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from feast import FeatureStore


class FeastClient:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot why are we implementing all of the feast Feature Store class methods? Why wouldn't the user just directly use the Feast SDK?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You raise a good point. The current implementation does wrap many Feast methods without adding significant value beyond what users would get from using Feast directly.

Looking at the ModelRegistryClient pattern, the wrapper should provide value through:

  1. Simplified, Kubeflow-aligned initialization
  2. Integration with Kubeflow workflows
  3. The store property already provides direct access to the underlying FeatureStore for advanced use cases

I can simplify this in a few ways:

Option 1: Minimal wrapper - Keep only essential initialization and provide the store property for full Feast access. Users who want all Feast features use client.store.*

Option 2: Remove wrapper entirely - Just document how to use Feast alongside Kubeflow SDK

Option 3: Keep current approach - The wrapper provides consistent API patterns across the Kubeflow SDK ecosystem, even if it's mostly pass-through

What's your preference? I'd lean toward Option 1 (minimal wrapper with store property access) as it balances convenience with avoiding unnecessary abstraction.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah Option 1 feels right.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Option 1 feels right. Small nit it should probably be client.feature_store.*

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Simplified to minimal wrapper approach with feature_store property in commit e78cee2.

Changes:

  • Removed all pass-through methods (get_online_features, materialize, apply, list_* methods)
  • Renamed storefeature_store property
  • Updated tests and README to use client.feature_store.* pattern
  • Reduced code from ~189 lines to ~103 lines

Users now access full Feast functionality through the property: client.feature_store.get_online_features(...), client.feature_store.materialize(...), etc.

"""Client for Feast feature store operations.

Feast is a feature store that enables offline retrieval of historical datasets
and online serving of features/data for ML applications.

This is a minimal wrapper that provides simplified initialization. For full Feast
functionality, use the `feature_store` property to access the underlying FeatureStore.

Requires the feast package to be installed. Install it with:

pip install 'kubeflow[feast]'

Example:
```python
from kubeflow.feast import FeastClient

# Initialize client
client = FeastClient(repo_path="/path/to/feast/repo")

# Access full Feast functionality
client.feature_store.get_online_features(...)
client.feature_store.materialize(...)
```
"""

def __init__(self, repo_path: str | None = None, config: dict[str, Any] | None = None):
"""Initialize the FeastClient.

Args:
repo_path: Path to the Feast repository. If not provided, uses the current directory.
config: Optional configuration dictionary for Feast FeatureStore.
If provided, takes precedence over repo_path.

Raises:
ImportError: If feast is not installed.
"""
try:
from feast import FeatureStore
except ImportError as e:
raise ImportError(
"feast is not installed. Install it with:\n\n" # fmt: skip
" pip install 'kubeflow[feast]'\n"
) from e

if config is not None:
self._feature_store: FeatureStore = FeatureStore(config=config)
else:
self._feature_store: FeatureStore = FeatureStore(repo_path=repo_path)

@property
def feature_store(self) -> FeatureStore:
"""Access the underlying Feast FeatureStore instance.

Use this property to access the full Feast API for operations like:
- get_online_features() / get_historical_features()
- materialize() / materialize_incremental()
- apply() - Deploy feature definitions
- list_feature_views() / list_entities() / list_data_sources()

Returns:
The Feast FeatureStore instance.

Example:
```python
client = FeastClient(repo_path="/path/to/feast/repo")

# Get online features
features = client.feature_store.get_online_features(
features=["feature_view:feature1"],
entity_rows=[{"entity_id": 1}],
)

# List feature views
for fv in client.feature_store.list_feature_views():
print(fv.name)
```
"""
return self._feature_store
Loading