feat: Version-pinning for FeatureService (online + offline) - #6718
feat: Version-pinning for FeatureService (online + offline)#6718HSarwat wants to merge 4 commits into
Conversation
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #6718 +/- ##
==========================================
+ Coverage 46.80% 46.88% +0.07%
==========================================
Files 415 415
Lines 50397 50465 +68
Branches 7215 7232 +17
==========================================
+ Hits 23589 23660 +71
+ Misses 25155 25153 -2
+ Partials 1653 1652 -1
... and 2 files with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
|
@HSarwat Please fix CI |
bc41ab7 to
6083f35
Compare
|
@ntkathole This PR doesnt introduce any dependency change, yet the CI is failing because it cant resolve greenlet 3.5.5 . I am not really sure where the error is coming from. Rebased my PR with the latest changed from main in case this error was resolved in a later commit and to trigger the CI again |
A FeatureService built from a version-pinned FeatureView (e.g.
FeatureView(version="v2")) silently served the promoted version instead
of the pinned one, defeating the guarantee a FeatureService is meant to
provide. Two bugs caused this:
1. FeatureService.__init__ appended the source view's projection without
translating its `version` string into `projection.version_tag` (the
field name_to_use() checks to render "fv@v2").
2. utils._get_feature_views_to_use hard-coded the version as None for the
FeatureService branch, so retrieval always fell through to the
promoted snapshot.
Stamp version_tag from the source view's version in __init__, and read
projection.version_tag (instead of None) during retrieval. The default
version ("latest") leaves version_tag as None, so every existing
unversioned FeatureService is unaffected. Covers both online and offline
retrieval, which share _get_feature_views_to_use.
Signed-off-by: h-sarwat <hussein_sarwat@yahoo.com>
FeatureService.features now accepts string refs using the same '<feature_view>[@<version>][:<feature>]' syntax as get_historical_features/get_online_features, e.g. "driver_stats@v2" or "driver_stats@v2:trips_today". This lets a service pin a historical FeatureView version without importing or reconstructing the underlying object. String entries are stashed at construction (no registry is available then) and resolved once, in FeatureStore.apply/plan, via a new FeatureService.resolve_pending_refs. A pinned ref always resolves from the registry snapshot for that version; an unversioned ref prefers the apply batch, then the promoted version. utils._parse_feature_ref is refactored onto a new _parse_feature_or_view_ref that makes the ':<feature>' suffix optional (whole-view refs); _parse_feature_ref is unchanged for existing callers. Signed-off-by: h-sarwat <hussein_sarwat@yahoo.com>
Offline stores re-fetch OnDemandFeatureViews from the registry independently of the version-aware online path, using an unversioned registry.list_on_demand_feature_views. A version-pinned ODFV (e.g. from a FeatureService pinning a specific ODFV version) therefore either raised "Could not find feature view from reference odfv@v1:feat" or silently served the promoted version during get_historical_features. Add a shared utils._get_requested_on_demand_feature_views that resolves each ref version-aware — pinned refs via get_feature_view_by_version (stamping projection.version_tag so name_to_use() matches downstream), unversioned refs via the promoted list as before. Route the three unversioned call sites through it: OnDemandFeatureView.get_requested_odfvs, offline_utils.get_feature_view_query_context, and dask.py's inline duplicate. This covers every offline backend, which all funnel through one of those. Unversioned refs are unchanged. Signed-off-by: h-sarwat <hussein_sarwat@yahoo.com>
Document pinning a historical feature view version inside a
FeatureService, via both string feature refs
("driver_stats@v2:trips_today") and version-pinned FeatureView objects,
on the alpha feature-view-versioning page. Clarify that
enable_online_feature_view_versioning gates both online and offline
versioned resolution (they share one code path), both in the page and in
the RegistryConfig field docstring. Update Known Limitations: offline
version-qualified retrieval and version-pinned feature services are now
supported.
Signed-off-by: h-sarwat <hussein_sarwat@yahoo.com>
6083f35 to
573931b
Compare
Closes #6717.
Related to #6389 (feature versioning in offline retrieval).
What
Lets a
FeatureServicepin a specific historical FeatureView / OnDemandFeatureView version, honored by bothget_online_featuresandget_historical_features. Feast's docs currently list this as a known limitation ("Feature services always resolve to the active (promoted) version"); this closes that gap.Commits
projection.version_tagfrom the source view'sversioninFeatureService.__init__; readprojection.version_tag(instead ofNone) inutils._get_feature_views_to_use.version="latest"is unaffected.featuresaccepts"<fv>[@<version>][:<feature>]"strings, resolved once inFeatureStore.applyviaFeatureService.resolve_pending_refs. Factors_parse_feature_or_view_refout of_parse_feature_ref(optional:feature).utils._get_requested_on_demand_feature_viewsused by all three unversioned ODFV call sites; pinned ODFV refs now resolve to the pinned snapshot offline. This is the offline-retrieval versioning gap tracked in Proposal: Version-qualified feature refs in get_historical_features (offline store versioning) #6389.enable_online_feature_view_versioningdocstring clarified to note it gates offline too; Known Limitations updated.Problem
Building a service from a version-pinned
FeatureViewsilently falls back to the promoted version:Two bugs cause this:
FeatureService.__init__never translates the view'sversionstring intoprojection.version_tag, andutils._get_feature_views_to_usehard-codes the version asNonefor theFeatureServicebranch. A related pre-existing bug (#6389) breaks offline retrieval of version-pinnedOnDemandFeatureViews: offline stores re-fetch ODFVs via an unversionedregistry.list_on_demand_feature_views, so a pinned ODFV ref raisesValueError: Could not find feature view from reference ...or silently drops features across every offline backend.Design notes for reviewers
registry.get_feature_view_by_version, never fromfvs_to_update(the apply batch only ever holds "latest" objects and would substitute the wrong schema). Covered bytest_pinned_ref_ignores_fvs_to_update.version="latest"behave exactly as before; every existing (unversioned) FeatureService is unaffected.enable_online_feature_view_versioningis misleadingly scoped to "online" — it gates both paths. Clarified in the docstring/docs here rather than renamed (rename would be a breaking config change; happy to follow up if maintainers prefer).Tests
New unit tests:
test_feature_service_versioning.py(object + string-ref pinning, proto round-trip, backward compat, error guards, priority ordering) andtest_odfv_offline_versioning.py(version-aware ODFV resolution, v0 fallback, non-ODFV skip, dedup). All pass; ruff (0.16.0) + mypy clean on changed files.