feat: Version-pinning for FeatureService (online + offline) - #6718
Open
HSarwat wants to merge 4 commits into
Open
feat: Version-pinning for FeatureService (online + offline)#6718HSarwat wants to merge 4 commits into
HSarwat wants to merge 4 commits into
Conversation
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>
HSarwat
requested review from
ejscribner,
robhowley and
tokoko
and removed request for
a team
August 9, 2026 20:51
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #6718 +/- ##
==========================================
- Coverage 46.75% 46.73% -0.02%
==========================================
Files 414 414
Lines 50348 50330 -18
Branches 7208 7204 -4
==========================================
- Hits 23539 23522 -17
Misses 25157 25157
+ Partials 1652 1651 -1
*This pull request uses carry forward flags. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.