FeastDataset(
*,
repo,
credentials=None,
load_args=None,
save_args=None,
metadata=None
)
Bases: AbstractDataset
Kedro dataset backed by a Feast feature view or feature service.
Load returns a FeastFeatureSource for point-in-time queries against the
offline store. Save persists a DataFrame to a feature view's batch source
via Feast's write_to_offline_store (which matches the DataFrame to the
feature view's schema and appends) and, when write_mode is
online_and_offline, also to the online store. Feast infers the write
schema from the existing table; set create_table: true to bootstrap a
(BigQuery) table from the feature view schema when it does not yet exist.
Examples:
Using the YAML API:
feast_features:
type: kedro_datasets_experimental.feast.FeastDataset
repo: # forwarded to feast.RepoConfig
registry: gs://bucket/feast
project: project_name
provider: gcp # default is local
offline_store:
type: bigquery # default is bigquery
location: EU
online_store: # optional; required for online_and_offline writes
type: sqlite
path: /tmp/online_store.db
save_args:
feature_view_name: features
write_mode: online_and_offline # or "offline" (default)
create_table: true # bootstrap the BigQuery table from the FV schema
load_args:
feature_view_name: features
Parameters:
-
repo
(dict[str, Any])
–
Feast repo configuration, forwarded to feast.RepoConfig
(which validates it). Any RepoConfig field is accepted, e.g.
registry (a path string or dict), project, provider
and offline_store. provider defaults to "local" and
offline_store to {"type": "bigquery"} when not set;
either can be overridden via repo. online_store defaults
to disabled (None); set it in repo to enable
online_and_offline writes.
-
credentials
(dict[str, Any] | str | None, default:
None
)
–
Not supported; Feast authenticates via Application
Default Credentials (the ambient environment). Passing anything
other than None raises NotImplementedError.
-
load_args
(dict[str, Any] | None, default:
None
)
–
Must contain either feature_view_name or
feature_service_name identifying what load retrieves.
-
save_args
(dict[str, Any] | None, default:
None
)
–
Must contain feature_view_name — the feature view to
write to. Optional write_mode selects where to write:
"offline" (default) writes only the offline store;
"online_and_offline" also pushes to the online store
(requires an online_store in repo). Optional
create_table (default False): when True, create the
backing table from the feature view schema if it does not exist
(BigQuery sources only; raises a DatasetError otherwise).
Source code in kedro_datasets_experimental/feast/feast_dataset.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 | def __init__(
self,
*,
repo: dict[str, Any],
credentials: dict[str, Any] | str | None = None,
load_args: dict[str, Any] | None = None,
save_args: dict[str, Any] | None = None,
metadata: dict[str, Any] | None = None,
) -> None:
"""Create a new ``FeastDataset``.
Args:
repo: Feast repo configuration, forwarded to ``feast.RepoConfig``
(which validates it). Any ``RepoConfig`` field is accepted, e.g.
``registry`` (a path string or dict), ``project``, ``provider``
and ``offline_store``. ``provider`` defaults to ``"local"`` and
``offline_store`` to ``{"type": "bigquery"}`` when not set;
either can be overridden via ``repo``. ``online_store`` defaults
to disabled (``None``); set it in ``repo`` to enable
``online_and_offline`` writes.
credentials: Not supported; Feast authenticates via Application
Default Credentials (the ambient environment). Passing anything
other than ``None`` raises ``NotImplementedError``.
load_args: Must contain either ``feature_view_name`` or
``feature_service_name`` identifying what ``load`` retrieves.
save_args: Must contain ``feature_view_name`` — the feature view to
write to. Optional ``write_mode`` selects where to write:
``"offline"`` (default) writes only the offline store;
``"online_and_offline"`` also pushes to the online store
(requires an ``online_store`` in ``repo``). Optional
``create_table`` (default ``False``): when ``True``, create the
backing table from the feature view schema if it does not exist
(BigQuery sources only; raises a ``DatasetError`` otherwise).
"""
if credentials is not None:
raise NotImplementedError("`FeastDataset` supports only Application Default Credentials")
repo = repo or {}
repo_config = RepoConfig(
**{
"provider": "local",
"offline_store": {"type": "bigquery"},
"online_store": None,
**repo,
}
)
self._repo = repo
self._feature_store = FeatureStore(config=repo_config)
self._load_args = load_args or {}
self._save_args = save_args or {}
self.metadata = metadata
|
_WRITE_MODES
class-attribute
instance-attribute
_WRITE_MODES = frozenset({'offline', 'online_and_offline'})
_feature_store
instance-attribute
_feature_store = FeatureStore(config=repo_config)
_load_args
instance-attribute
_load_args = load_args or {}
_save_args
instance-attribute
_save_args = save_args or {}
_build_bq_schema
staticmethod
_build_bq_schema(feature_view, timestamp_field)
Build the BigQuery schema: entity keys, then features, then timestamp.
Source code in kedro_datasets_experimental/feast/feast_dataset.py
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 | @staticmethod
def _build_bq_schema(
feature_view: FeatureView, timestamp_field: str
) -> list[bigquery.SchemaField]:
"""Build the BigQuery schema: entity keys, then features, then timestamp."""
def bq_type(dtype: Any) -> str:
key = dtype.name if hasattr(dtype, "name") else type(dtype).__name__
return _FEAST_FIELD_TYPE_TO_BQ.get(key, "STRING")
fields: list[bigquery.SchemaField] = []
entity_names: set[str] = set()
for field in feature_view.entity_columns:
fields.append(bigquery.SchemaField(field.name, bq_type(field.dtype)))
entity_names.add(field.name)
for field in feature_view.schema:
if field.name not in entity_names:
fields.append(
bigquery.SchemaField(
field.name, bq_type(field.dtype), mode="NULLABLE"
)
)
fields.append(bigquery.SchemaField(timestamp_field, "TIMESTAMP"))
return fields
|
_create_bigquery_table
_create_bigquery_table(feature_view_name)
Create the feature view's backing BigQuery table if it doesn't exist.
The table schema is derived from the feature view (entity keys, features,
then the event timestamp). Raises aDatasetError for non-BigQuery sources.
Source code in kedro_datasets_experimental/feast/feast_dataset.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310 | def _create_bigquery_table(self, feature_view_name: str) -> None:
"""Create the feature view's backing BigQuery table if it doesn't exist.
The table schema is derived from the feature view (entity keys, features,
then the event timestamp). Raises a``DatasetError`` for non-BigQuery sources.
"""
feature_view = self._feature_store.get_feature_view(feature_view_name)
source = feature_view.source
batch_source = getattr(source, "batch_source", source)
if not isinstance(batch_source, BigQuerySource):
msg = (
f"save_args['create_table'] is only supported for BigQuerySource "
f"batch sources, got {type(batch_source).__name__!r} for "
f"'{feature_view_name}'."
)
raise DatasetError(msg)
if not batch_source.table:
msg = (
f"Feature view '{feature_view_name}' uses a query-based source "
f"with no table to create."
)
raise DatasetError(msg)
timestamp_field = batch_source.timestamp_field
schema = self._build_bq_schema(feature_view, timestamp_field)
# Run against the project the source table lives in (a fully-qualified
# `project.dataset.table` ref), falling back to the offline store's.
offline = self._feature_store.config.offline_store
parts = batch_source.table.split(".")
is_fully_qualified = len(parts) == _FULLY_QUALIFIED_BQ_TABLE_PARTS
table_project = (
parts[0]
if is_fully_qualified
else (offline.billing_project_id or offline.project_id)
)
if table_project is None:
msg = (
f"Cannot resolve a project for table '{batch_source.table}'; set "
f"'billing_project_id' or 'project_id' on the offline_store, or use "
f"a fully-qualified 'project.dataset.table' reference."
)
raise DatasetError(msg)
table_id = (
batch_source.table
if is_fully_qualified
else f"{table_project}.{batch_source.table}"
)
table = bigquery.Table(table_id, schema=schema)
client = bigquery.Client(project=table_project, location=offline.location)
client.create_table(table, exists_ok=True)
|
_describe
Source code in kedro_datasets_experimental/feast/feast_dataset.py
| def _describe(self) -> dict[str, Any]:
return {
"repo": self._repo,
"load_args": self._load_args,
"save_args": self._save_args,
}
|
load
Source code in kedro_datasets_experimental/feast/feast_dataset.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 | def load(self) -> FeastFeatureSource:
if (feature_view_name := self._load_args.get("feature_view_name")) is not None:
feature_view = self._feature_store.get_feature_view(feature_view_name)
features = [
f"{feature_view.name}:{field.name}" for field in feature_view.features
]
return FeastFeatureSource(self._feature_store, features)
if (
feature_service_name := self._load_args.get("feature_service_name")
) is not None:
feature_service = self._feature_store.get_feature_service(
feature_service_name
)
return FeastFeatureSource(self._feature_store, feature_service)
msg = (
"load_args must contain either a `feature_view_name` or "
"`feature_service_name`"
)
raise DatasetError(msg)
|
save
Source code in kedro_datasets_experimental/feast/feast_dataset.py
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256 | def save(self, data: pd.DataFrame) -> None:
feature_view_name = self._save_args.get("feature_view_name")
if feature_view_name is None:
msg = "save_args must contain a `feature_view_name`"
raise DatasetError(msg)
write_mode = self._save_args.get("write_mode", "offline")
if write_mode not in self._WRITE_MODES:
msg = (
f"save_args['write_mode'] must be one of "
f"{sorted(self._WRITE_MODES)}, got {write_mode!r}."
)
raise DatasetError(msg)
# Optionally bootstrap the backing table from the feature view schema.
# Feast's write infers its schema from the *existing* table, so this
# must happen first. Only BigQuery-backed sources are supported for now.
if self._save_args.get("create_table", False):
self._create_bigquery_table(feature_view_name)
# Persist the DataFrame into the feature view's batch source: Feast
# matches/reorders columns to the Feast schema and appends. Fails if
# columns don't match.
self._feature_store.write_to_offline_store(
feature_view_name, data, reorder_columns=True
)
# Optionally also push to the online store (requires an online_store to
# be configured in `repo`; it is disabled by default).
if write_mode == "online_and_offline":
self._feature_store.write_to_online_store(feature_view_name, data)
|