Skip to content

feat: Feast First-Class LabelView Implementation#6292

Merged
ntkathole merged 3 commits into
feast-dev:masterfrom
ntkathole:labelView
Jun 8, 2026
Merged

feat: Feast First-Class LabelView Implementation#6292
ntkathole merged 3 commits into
feast-dev:masterfrom
ntkathole:labelView

Conversation

@ntkathole

@ntkathole ntkathole commented Apr 17, 2026

Copy link
Copy Markdown
Member

What this PR does / why we need it:

RFC - https://docs.google.com/document/d/1mcJM0sHeBk269oMIsLsLnAlrMtgnxn5Pws0oEeogc48/edit?usp=sharing

Summary

Introduces LabelView, a new alpha-stage Feast primitive that manages mutable labels and annotations separately from immutable feature data stored in regular FeatureViews. This supports multi-labeler workflows (human reviewers, automated safety scanners, reward models) where different sources independently write labels for the same entity keys.

LabelView is fully opt-in — existing workflows are unaffected unless a user explicitly defines one.

labelview_v2.mov

What's included

Core implementation (feast.labeling module)

  • LabelView class inheriting from BaseFeatureView, with label-specific attributes: labeler_field, conflict_policy, retain_history, reference_feature_view
  • ConflictPolicy enum (LAST_WRITE_WINS, LABELER_PRIORITY, MAJORITY_VOTE)
  • Protobuf definition (LabelView.proto) with LabelViewSpec, LabelViewMeta, and ConflictResolutionPolicy

Full SDK integration

  • FeatureStore.apply() — registers LabelViews, auto-registers their PushSource, validates name uniqueness across all view types
  • FeatureStore.push() — routes push data to LabelView when its PushSource matches
  • FeatureStore.get_historical_features() — works via batch_source/stream_source properties on LabelView
  • FeatureStore.teardown() — includes LabelView tables
  • FeatureStore.list_label_views() / get_label_view() — new public API methods
  • FeatureService composability — LabelViews can be included alongside regular feature views

Registry support (all backends)

  • File registry — full CRUD, apply_materialization, name-conflict checks
  • SQL registry — label_views table, _infer_fv_table/_infer_fv_classes support, proto() builder
  • Remote (gRPC) registry — label_view arm added to ApplyFeatureViewRequest oneof, full client + server wiring
  • Snowflake registry — DDL for LABEL_VIEWS table, correct column-name mapping in delete_feature_view

CLI

  • feast label-views list — lists all label views with name, entities, conflict policy
  • feast label-views describe <name> — shows full label view details
  • feast feature-views list unchanged (label views are only in their dedicated command)

Permissions

  • LABEL_VIEW = 11 added to Permission.proto Type enum
  • _PERMISSION_TYPES map updated for from_proto/to_proto roundtrip

Regression safety

  • No changes to existing feature-views list output
  • All registry proto() builders include label_views so cached/exported blobs are complete
  • Cross-type name uniqueness enforced via _ensure_feature_view_name_is_unique

Documentation

  • Docstrings with [Alpha] tags and Google-style Args blocks on all public classes/methods
  • Sphinx/RST API reference entries for LabelView and ConflictPolicy
  • Concept guide (docs/getting-started/concepts/label-view.md) with usage examples, conflict policies, and alpha limitations
  • Alpha limitations clearly documented: conflict_policy stored but not enforced at read time (requires online-store query-path changes); retain_history stored but not enforced at write time (requires online-store write-path changes); batch materialization not supported

Tests

  • 30 unit tests covering creation, defaults, proto roundtrip, copy/equality, validation, FeatureService composition, registry proto roundtrip, batch_source/stream_source properties, name-conflict detection, and MaterializationTask acceptance

Alpha Limitations

  • conflict_policy — persisted in registry metadata but not enforced during get_online_features. Online store returns last-written row regardless of policy.
  • retain_history — persisted but not acted on. Online store always overwrites previous value.

Test Plan

  • All 30 test_label_view.py unit tests pass
  • All 5 test_registry_diff.py tests pass (including test_diff_registry_objects_permissions)
  • No linter errors introduced
  • Existing feature view / entity / feature service workflows unaffected when no LabelView is defined
  • Manual: feast apply with a repo containing a LabelView definition
  • Manual: feast label-views list / feast label-views describe
  • Manual: FeatureStore.push() to a LabelView's PushSource

Which issue(s) this PR fixes:

#5456

@ntkathole ntkathole self-assigned this Apr 17, 2026
@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from 0f755c2 to 468ea54 Compare April 17, 2026 08:31
@ntkathole ntkathole marked this pull request as ready for review April 17, 2026 08:43
@ntkathole ntkathole requested a review from a team as a code owner April 17, 2026 08:43
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from 623acc0 to d8daa1f Compare April 17, 2026 10:51
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from 85c9875 to 2678090 Compare April 17, 2026 12:51
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@JiwaniZakir JiwaniZakir left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

In docs/getting-started/concepts/label-view.md, the LabelView definition example includes interaction_id both as the entity join key (Entity(join_keys=["interaction_id"])) and as an explicit Field inside the schema list. Standard Feast FeatureView definitions typically exclude join-key columns from the schema since they're inferred from the entity definition — duplicating them here either reflects an inconsistency with how the underlying implementation handles schema validation, or it will silently produce duplicate columns. This should either be removed from the schema to match Feast conventions or explicitly documented as a required pattern specific to LabelView.

On the alpha-limitations transparency: documenting that conflict_policy and retain_history are persisted but not enforced is the right call, but consider surfacing a runtime warning (e.g., a UserWarning on apply() or push()) when a non-default ConflictPolicy or retain_history=True is configured. As written, users who set ConflictPolicy.MAJORITY_VOTE will silently get last-write-wins behavior, which is a subtle correctness hazard that the docs alone may not prevent.

@ntkathole

Copy link
Copy Markdown
Member Author

In docs/getting-started/concepts/label-view.md, the LabelView definition example includes interaction_id both as the entity join key (Entity(join_keys=["interaction_id"])) and as an explicit Field inside the schema list. Standard Feast FeatureView definitions typically exclude join-key columns from the schema since they're inferred from the entity definition — duplicating them here either reflects an inconsistency with how the underlying implementation handles schema validation, or it will silently produce duplicate columns. This should either be removed from the schema to match Feast conventions or explicitly documented as a required pattern specific to LabelView.

Thanks for review @JiwaniZakir. Can you please re-confirm - this is how regular feature view works, it isn't duplication.

On the alpha-limitations transparency: documenting that conflict_policy and retain_history are persisted but not enforced is the right call, but consider surfacing a runtime warning (e.g., a UserWarning on apply() or push()) when a non-default ConflictPolicy or retain_history=True is configured. As written, users who set ConflictPolicy.MAJORITY_VOTE will silently get last-write-wins behavior, which is a subtle correctness hazard that the docs alone may not prevent.

valid point but the next PR will have support for conflict_policy and retain_history and required changes in online store.

@JiwaniZakir

Copy link
Copy Markdown

The Python 3.12 worker crash in test_e2e_local.py is worth investigating before merging — a gw6 worker crash typically signals a segfault or unhandled exception during collection or teardown, which could be unrelated to LabelView itself but should be confirmed. Can you share the full traceback from that run? Also, given the retain_history and conflict_policy attributes on LabelView, it would be worth confirming the batched write tests cover the MAJORITY_VOTE conflict resolution path specifically, since that's the most stateful and error-prone of the three policies.

@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from f3432c8 to a00b5b1 Compare May 7, 2026 13:48
@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from 26a06ac to 45bd948 Compare May 19, 2026 09:56
@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from 15dc7f3 to 6a3162d Compare May 25, 2026 04:24
@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from 0fdcead to 869d67f Compare June 4, 2026 07:24
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
Comment thread sdk/python/feast/ui_server.py Fixed
@ntkathole ntkathole force-pushed the labelView branch 10 times, most recently from c4b0dfb to a792e7a Compare June 5, 2026 09:31
ntkathole added 2 commits June 8, 2026 17:49
Signed-off-by: ntkathole <nikhilkathole2683@gmail.com>
Signed-off-by: ntkathole <nikhilkathole2683@gmail.com>
@ntkathole ntkathole force-pushed the labelView branch 2 times, most recently from d215704 to 487b55e Compare June 8, 2026 13:39
Signed-off-by: ntkathole <nikhilkathole2683@gmail.com>
@ntkathole ntkathole merged commit c0e7e5d into feast-dev:master Jun 8, 2026
31 of 32 checks passed
franciscojavierarceo pushed a commit that referenced this pull request Jun 13, 2026
# [0.64.0](v0.63.0...v0.64.0) (2026-06-13)

### Bug Fixes

* Add async_supported property to RedisOnlineStore ([9b088fe](9b088fe))
* Add missing feast init templates to operator CRD and enhance persistence documentation ([1941d4d](1941d4d))
* Allow to publish from reference branch ([5458ec8](5458ec8))
* API calls list ([4203eb7](4203eb7))
* **bigquery:** Enable list inference for parquet loads in offline_write_batch ([9243497](9243497)), closes [#5845](#5845)
* Bump grpcio dependencies ([07b4782](07b4782))
* **compute-engine/local:** Honor field_mapping on join keys in dedup + join nodes ([#6395](#6395)) ([bd01824](bd01824))
* **dynamodb:** Avoid tag race condition by using diff-based tag updates ([#6479](#6479)) ([bad2b7d](bad2b7d)), closes [#6418](#6418)
* **dynamodb:** Fix mypy type for _build_projection_expression return ([217b4da](217b4da))
* Fix intermittent async test failures for DynamoDB and Redis ([63c5eb1](63c5eb1))
* Fix mongodb blog title ([57d28d4](57d28d4))
* Fix shared SQL registry crash - avoid unnecessary UDF deserialization in proto cache building ([ac588d7](ac588d7))
* Fix SparkRetrievalJob.persist() failing for SparkSource ([209d7cd](209d7cd))
* Fixed formatting and image for mongo blog ([#6377](#6377)) ([f8389fb](f8389fb))
* Fixes for ray source ([7f592a4](7f592a4))
* **go:** skip registry refresh when cache_ttl_seconds <= 0 ([97ed40c](97ed40c))
* Handle array of strings columns in Athena materialization ([#6324](#6324)) ([4ed0278](4ed0278))
* make milvus VARCHAR max_length configurable, remove hardcoded 512 limit ([3b98c22](3b98c22))
* **operator:** Set appProtocol: grpc on registry gRPC Service ([#6367](#6367)) ([c9ae2b4](c9ae2b4))
* PyJWT 2.10+ added validation that rejects empty HMAC keys ([e756ffe](e756ffe))
* RemoteOnlineStore sends all features in a single HTTP request ([8f187dd](8f187dd))
* Remove registry proto dump to enforce RBAC and add permission checks to Commit/Refresh RPCs ([328431f](328431f))
* Remove selector migration job - no longer needed ([51c325e](51c325e))
* replace broken .claude skill symlink with correct relative path ([4541690](4541690))
* Replace selector label strip patch with migration Job for upgrade-safe selector uniqueness ([00dea50](00dea50))
* Scope feature view name conflict check to current project in file-based registry ([#6369](#6369)) ([a4fde83](a4fde83)), closes [#6209](#6209)
* **snowflake:** Stop double-quoting connection identifiers ([#6462](#6462)) ([e914d59](e914d59))
* **spark:** S3/GCS PyArrow filesystem resolution for staging paths ([#6442](#6442)) ([ae50414](ae50414))
* **trino:** Clean up temporary entity tables after retrieval ([#6381](#6381)) ([d86b13d](d86b13d)), closes [#6306](#6306)
* Update go-feature-server base image to Go 1.25 and fix operator Dockerfile COPY permissions ([86ef0bc](86ef0bc))

### Features

* [Backend] Data Quality Monitoring with native compute, multi-backend support, REST API, CLI ([#6202](#6202)) ([5458c37](5458c37))
* Add apache flink compute engine ([#6476](#6476)) ([9636d6a](9636d6a))
* Add demo noteboooks for users ([e362173](e362173))
* Add enabled/disabled toggle for feature views ([#6401](#6401)) ([5f1fa0d](5f1fa0d)), closes [#6395](#6395)
* Add Label View to init template ([ec272d5](ec272d5))
* Add mTLS support to remote registry gRPC client ([#6474](#6474)) ([c9602d8](c9602d8))
* Add Prometheus gauges for FeatureStore installation telemetry ([#6354](#6354)) ([1b681b7](1b681b7))
* Adds registry REST API endpoints for managing entities, data sources, and feature views ([#6413](#6413)) ([f77bd1d](f77bd1d))
* Allow CRUD on entities, data sources, and feature views from UI ([#6412](#6412)) ([2321c07](2321c07))
* Allow default openlineage configuration ([#6467](#6467)) ([276b6df](276b6df))
* **bigquery:** Support DATE-type event timestamp columns ([#6362](#6362)) ([753dee5](753dee5)), closes [#2530](#2530)
* **cli:** Add `feast projects delete` command (closes [#5095](#5095)) ([#6318](#6318)) ([1a4b96c](1a4b96c))
* Data Quality Monitoring added in feast UI ([#6422](#6422)) ([fa271be](fa271be))
* **dynamodb:** Use ProjectionExpression when requested_features is set ([0adc906](0adc906)), closes [#6058](#6058)
* Enhance DataSource and FeatureView modals with error handling and submission states ([96d7169](96d7169))
* Expose registry endpoints on feature server for MCP access ([f77981c](f77981c))
* Feast First-Class LabelView Implementation ([#6292](#6292)) ([c0e7e5d](c0e7e5d))
* Feast-MLflow Integration ([#6235](#6235)) ([7279c75](7279c75))
* Operational metrics for offline store and SOX metrics for both ([#6340](#6340)) ([65b1b80](65b1b80))
* Pre-compute feature service ([8011550](8011550))
* REST API-backed UI for RBAC compatibility and per-page lazy loading ([#6414](#6414)) ([6ae80af](6ae80af))
* Support non-string map key types ([#6382](#6382)) ([#6383](#6383)) ([728aa2e](728aa2e))
* Update FeatureStore CRD with DRA Fields ([01241e4](01241e4))

### Performance Improvements

* Cache feature view resolution in get_online_features to reduce per-request overhead ([55c2f18](55c2f18))
* Optimize feature serving latency with batched async Redis, cached checks fix ([103809a](103809a))
* Replace MessageToDict with optimized custom dict builder ([#6015](#6015)) ([9902064](9902064))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants