Skip to content

feat: Add Vector Store Support in Valkey & Elastic Search#364

Open
Manisha4 wants to merge 7 commits intomasterfrom
ess-vector-store
Open

feat: Add Vector Store Support in Valkey & Elastic Search#364
Manisha4 wants to merge 7 commits intomasterfrom
ess-vector-store

Conversation

@Manisha4
Copy link
Copy Markdown
Collaborator

@Manisha4 Manisha4 commented May 7, 2026

What this PR does / why we need it:

What this PR introduces:

New APIs :
- retrieve_online_documents_v2 — single-signal vector kNN on Elasticsearch and Valkey online stores, with per-query distance-metric override - retrieve_online_documents_v3 — multi-signal retrieval with configurable fusion strategies and reserved output fields

V3 fusion strategies (Elasticsearch)

  • AUTO — single-signal runs as native kNN; multi-signal routes to RRF
  • RRF — Reciprocal Rank Fusion with tunable rrf_k (rank-window parameter)
  • WEIGHTED_LINEAR — per-signal weights, with validation that every signal has a weight
  • VECTOR_ONLY — explicitly drop any text signal, run pure vector kNN (basic-license safe)

V3 reserved output fields

  • final_score — the backend's ranking score (ES _score, higher = better; Valkey distance, lower = better)
  • signal_scores — per-signal score breakdown (populated for single-signal queries)

V3 input validation

  • Unknown embedding keys → clear ValueError listing available vector fields
  • "embedding" magic-key auto-resolves on single-vector FVs; errors on ambiguous multi-vector FVs
  • Reserved-name collision detection (callers can't shadow final_score / signal_scores)
  • Missing signal weights for WEIGHTED_LINEAR → ValueError before ES call
  • Whitespace-only query_string normalized to None

Elasticsearch backend enhancements

  • Quantization support: int8_hnsw, int4_hnsw, bbq_hnsw, and matching flat variants (75–97% memory savings)
  • HNSW tuning: hnsw_m, hnsw_ef_construction configurable per store
  • rescore_oversample for accuracy recovery on quantized indices (wired through V2 and V3)
  • use_native_knn toggle — native kNN (approximate, fast) or script_score (exact, backward compat)
  • knn_num_candidates_multiplier for per-query HNSW breadth tuning
  • Dimension-based validation: int4 requires even dims; BBQ requires ≥ 64 dims; all validated at feast apply time
  • Hybrid queries built via ES's native retriever API (ES 8.14+)

Valkey backend enhancements (V2)

  • Vector index creation via FT.CREATE during online_write_batch
  • Two-step retrieval pattern: FT.SEARCH for kNN + pipelined HMGET for feature hydration
  • Project scoping — project tag field on every hash, filtered at query time, prevents cross-project leakage on shared clusters
  • V3 calls with multi-signal fusion gracefully degrade to single-vector kNN with a warning (Valkey Search doesn't support native fusion)

Signal-scores utility

  • Shared encode_signal_scores / decode_signal_scores helpers in infra/online_stores/_signal_scores.py for consistent score-dict encoding across backends

Infrastructure

  • V3 API plumbed through FeatureStore, Provider, PassthroughProvider, RemoteProvider, and the OnlineStore base class so additional backends can adopt V3 without further framework changes

Correctness fixes rolled in

  • Ranked-row ordering fix (V3) — retrieval results returned in backend rank order instead of lexicographic entity-key order
  • rescore_oversample wired to V3 retrievers — quantized-index queries now actually receive the rescore step the config promises
  • ES correctness/perf/robustness fixes, ES integration test fixes, vector-field identification fix

Backwards compatibility

- V1 and V2 APIs remain functional; V3 is additive

  • Defaults preserve legacy behavior (use_native_knn=False, no quantization, etc.)

Known runtime dependencies

  • Elasticsearch 8.14+ for V3 RRF; 8.19+ for linear retriever
  • Elasticsearch fusion strategies (RRF, linear) require a trial / platinum / enterprise license; V3 on basic-license clusters is limited to single-signal retrieval (VECTOR_ONLY), equivalent to V2 plus V3's validation and output improvements
  • Valkey Search module required on the Valkey cluster for vector support

Which issue(s) this PR fixes:

Misc

vanitabhagwat and others added 7 commits March 30, 2026 22:25
…ature view to identify vector fields (#348)

* updated the elastic search  to use vector_index defined in the feature view to identify vector fields

* fix: formatting

* Added logging and switched to use open source elastic search

---------

Co-authored-by: vanitabhagwat <vbhagwat@expediagroup.com>
* fix: ES integration tests

* fix: Added fromisoformat() for converting timestamps

---------

Co-authored-by: vanitabhagwat <vbhagwat@expediagroup.com>
…ness fixes (#353)

Co-authored-by: vanitabhagwat <vbhagwat@expediagroup.com>
* feat: Valkey Online Write Batch Vector Search Support (#351)

* Adding support for Valkey Search, adding changes to the online_write_batch functionality

* Addressing PR comments

* addressing linting error

* fix tests

* addressing PR comments

* addressing PR comments

* fixing linting

---------

Co-authored-by: Manisha4 <Manisha4@github.com>

* feat: Support Vector Search in Valkey (#354)

* Adding support for Valkey Search, adding changes to the online_write_batch functionality

* Addressing PR comments

* addressing linting error

* Adding changes to support search in valkey

* fix tests

* adding unit tests

* reformatting files and adding checks and more tests

* reformatting files and adding checks and more tests

* reformatting files and adding checks and more tests

* Fix linter errors: type annotations and code formatting

- Add explicit type annotation for schema_fields to support both TagField and VectorField
- Encode project string to bytes for consistency with other hash values
- Decode doc_key bytes to string for hmget compatibility
- Fix code formatting: break long lines and remove extra blank lines
- Remove tests for multiple vector fields (Feast enforces one vector per feature view)
- Fix config type: use 'eg-valkey' (hyphen) not 'eg_valkey' (underscore)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* addressing PR comments

* addressing PR comments

* fixing linting

* Fix missing feature_name argument in retrieve_online_documents_v2

Add the third argument (vector_field.name) to _get_vector_index_name
call to match the updated function signature.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* addressing comments, PR changes for some fixes and merge conflicts

* fixing tests

* fixing tests

* fixing linting

* fixing linting

---------

Co-authored-by: Manisha4 <Manisha4@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Valkey vector search - remove unsupported SORTBY (#356)

* fix: Valkey vector search - remove unsupported SORTBY and fix tag filter syntax

Valkey Search KNN queries return results pre-sorted by distance, so
explicit SORTBY is not supported and causes a ResponseError. This removes
the .sort_by() call from the query builder.

Additionally, fixes the project tag filter to use unquoted syntax with
backslash escaping for special characters (e.g. hyphens, dots) instead
of the quoted syntax which was returning empty results.

Updates unit tests to reflect both changes: replaces three metric-specific
sort order tests with a single test asserting no SORTBY is set, and
updates escaping assertions to match the new backslash-escape approach.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: apply ruff format to eg_valkey.py and test_valkey.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Manisha4 <Manisha4@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Manisha4 <Manisha4@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…id fusion (#358)

* feat: implement retrieve_online_documents_v3 SDK method
  - Multi-vector search with configurable fusion (RRF, WEIGHTED_LINEAR, VECTOR_ONLY) via the ES retriever API. Valkey gracefully degrades to single-vector KNN with warnings.
  - "embedding" magic key for V2→V3 migration convenience
  - Reserved output fields: final_score, signal_scores
  - include_signal_scores and distance_metric accepted as reserved params
  - ODFV and reserved-name collision validation
  - Shared signal_scores encoding via _signal_scores helper

* update tests

* update tests

* fixing linting

* docs: clarify final_score semantics in Valkey V3 docstring

Correct the Valkey final_score description — Valkey's __distance__ is
lower-is-better across all metrics (COSINE, L2, IP), not higher-is-better
for IP. Call out the ordering inversion vs Elasticsearch so callers don't
assume cross-backend score portability.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: plumb include_signal_scores through V3 and align defaults to False

Valkey/ES/provider/passthrough/online-store defaults were True, mismatching
the SDK's False default. Align all layers on False and thread the parameter
from retrieve_online_documents_v3 through the internal dispatcher, provider,
and online stores so callers can opt in today and transparently pick up the
explain-based per-signal path when it lands — no API change required.

Tighten docstrings to describe the current best-effort behavior instead of
hinting at latency tradeoffs that aren't wired yet.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* updating doc string

* fix: preserve ranked row order in V3 retrieve_online_documents

_retrieve_from_online_store_v3 was passing the driver's ranked rows
through _get_unique_entities_from_values, which sorts and dedupes by
entity-key bytes. That helper is correct for batch entity lookups but
wrong here — ES/Valkey have already ordered rows by relevance, and the
sort was scrambling them in the final DataFrame (e.g. doc_10 jumping
ahead of doc_3 because "10" < "3" lexicographically).

Replace the helper call with an identity mapping so the driver's rank
order flows through untouched. No change to V1, V2, batch reads, or
the helper itself; V3 output now matches the order returned by the
online store.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Manisha4 <Manisha4@github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
V3's retriever construction was silently ignoring rescore_oversample. V2
honored it (lines 483-486, 617-620) but V3 never added rescore_vector to
its kNN clauses. On quantized indices (int8_hnsw / int4_hnsw / bbq_hnsw),
this meant V3 queries returned lower recall than the config promised,
with no error or warning.

Wire rescore_oversample into each kNN retriever the same way V2 does.
Covers single-vector and multi-vector V3 queries; BM25 retrievers skip
the branch since they lack a "knn" key.

Existing config validation (lines 102-127) already prevents rescore on
non-quantized indices, so no new validation needed.

Added three unit tests in TestRetrieveOnlineDocumentsV3QueryBuilding:
- rescore_vector appears in single-vector query body when configured
- rescore_vector appears on every kNN retriever in multi-vector query
- rescore_vector absent when rescore_oversample is None

Co-authored-by: Manisha4 <Manisha4@github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants