Skip to content

feat(vector/search): PQ → SQ → f32 three-stage rerank chain (#650 PR-3) - #937

Merged
mosuka merged 1 commit into
mainfrom
feat/673-pq-sq-rerank
Aug 4, 2026
Merged

feat(vector/search): PQ → SQ → f32 three-stage rerank chain (#650 PR-3)#937
mosuka merged 1 commit into
mainfrom
feat/673-pq-sq-rerank

Conversation

@mosuka

@mosuka mosuka commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

Changes

  • ScalarQuantParams::train_from_slices (vector/core/quantization.rs): slice-iterator variant of train; train(&[Vector]) now delegates to it.
  • RerankStoragePool::int8_view() (vector/index/rerank_storage.rs): lazily derives a QuantizedVectorPool from the pool's own f32 payload, encoded in the same position order so int8_view.record_at(pos) and f32_slice_at(pos) trivially agree on pos. Degrades to None on an empty pool or training failure.
  • SqRerankStage (vector/search/rerank.rs): mirrors F32SidecarStage, rescoring via distance_quantized.
  • HnswSearcher::finalize_graph_results: inserts SqRerankStage ahead of F32SidecarStage only when segment=PQ/PQ-FastScan + sidecar loaded + rerank_factor set + effective_ef_search > top_k * rerank_factor. score_basis stamping (bug(vector/search): cross-segment scores are not comparable — out-of-range queries clamp to similarity 1.0 per segment #927) is unchanged — still keyed only on the final (still f32) stage.
  • Bench: bench_hnsw_graph_search_pq_rerank_real_data_wide_ef (opt-in SIFT, not run in this session — no local fixture).
  • Docs (EN+JA): new "PQ → SQ → f32 three-stage rerank" section in vector_indexing.md; grpc_api.md rerank_factor row updated (also fixes a stale feat(vector/search): Stage-2 rerank for Flat/IVF via the shared pipeline (#650 PR-2) #932-era "Flat/IVF fall back" claim) + new ef_search row.

Tests

  • Unit: train_from_slices (2), int8_view (6: position-consistency, quantization-error bound, single-build-cached, degrade-to-None), SqRerankStage (2).
  • Integration (vector_pq_three_stage_rerank_test.rs, new): pq_three_stage_rerank_end_to_end — wide-ef_search (SQ active) Recall@10 ≥ narrow/budget-exact ef_search (SQ inactive) Recall@10 (measured 0.66 → 0.98 on a deliberately lossy PQ fixture); score_basis stays "f32-rerank"; narrow-ef_search results are bit-exact reproducible.
  • RED proof (reversible edit disabling the SQ-stage insertion): wide-ef_search recall dropped 0.98 → 0.9567, confirming the SQ stage's causal contribution.
  • Regression: existing PQ recall gates (hnsw_pq_rerank_recall_at_10_meets_stage3_recall_gate + opt-in SIFT variant) stay green.

Verification

  • cargo fmt --check / cargo clippy --all-targets -D warnings: clean on stable, 1.97.0, and --features pq-fastscan.
  • cargo test -p laurus --lib: 1270 passed. --tests: 68 binaries, all green.
  • cargo check -p laurus-wasm --target wasm32-unknown-unknown: clean.
  • cargo doc --no-deps -p laurus: 73 warnings (unchanged baseline).
  • markdownlint-cli2 EN+JA: 0 errors. Both mdBooks build.

Test plan

  • Unit tests for the new derivation/stage logic
  • Integration test covering the 3-stage recall property, score_basis contract, and 2-stage-path determinism
  • RED proof isolating the SQ stage's causal effect
  • No regression on existing PQ rerank recall gates
  • Full verification suite (fmt/clippy ×3 configs/tests/wasm/doc/markdownlint/mdbook)

)

Insert a cheap int8 (SQ) rerank stage ahead of the exact f32 stage on
PQ-quantized HNSW fields, activated only when ef_search exceeds the
exact-stage budget (top_k * rerank_factor) — the surplus candidates the
graph traversal already computed are re-ranked by a much better proxy
(int8) instead of being discarded on the noisier PQ ADC order.

The int8 view is lazily derived from the existing f32 rerank sidecar
(RerankStoragePool::int8_view), so this needs no new on-disk format, no
new RerankStorageKind variant, and no new query parameter.
@mosuka
mosuka merged commit 09ff63e into main Aug 4, 2026
22 checks passed
@mosuka
mosuka deleted the feat/673-pq-sq-rerank branch August 4, 2026 07:17
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.

perf(vector/search): PQ rerank pipeline not exposed: PQ → SQ → f32 not possible

1 participant