feat(bench): Group C differentiators — W10..W12 (sub-phase 9.4)#105
Merged
Conversation
Lands the Phase 7 / Phase 8 differentiator workloads on top of the 9.3
Group B baseline:
W10 vector top-10 10k 384-dim vectors, cosine top-10. Two
variants: brute-force (no index) and HNSW
(CREATE INDEX ... USING hnsw). SQLRite-only —
sqlite-vec extension wiring is a follow-up,
rusqlite[bundled] doesn't ship it.
W11 BM25 top-10 SQLRite USING fts vs SQLite FTS5 virtual
table. Engine-asymmetric setup + query.
1000-doc corpus.
W12 hybrid SQLRite-only — 50/50 BM25 + cosine fusion
over a 1000-doc corpus with paired text +
vector. Mirrors examples/hybrid-retrieval/.
Two notable plan deviations land alongside the workloads:
W11 / W12 corpus scaled 10k → 1000 docs. Plan target was 10k.
SQLRite's FTS doc-lengths sidecar is a single cell that scales
with corpus size (~3 bytes per doc); 10k docs blew through the
4 KiB page cap with `posting cell 1 of 31754 bytes exceeds
empty-page capacity 4085 (overflow chaining is Phase 8.1)`. The
practical cap is ~1,360 docs; v1 ships at 1000 with a comfort
margin. SQLR-21 tracks Phase 8.1.
W10 sqlite-vec comparator deferred. Plan said "sqlite-vec if
installable, else SQLRite-only baseline." rusqlite[bundled]
doesn't ship the extension; loading a pre-compiled .dylib at
runtime is non-trivial and out of scope for v1. Both W10
variants ship as SQLRite-only.
Smoke run (M1 Pro, criterion --warm-up-time 1 --measurement-time 1
--sample-size 10):
W10 brute-force sqlrite ~122 ms — parser cost
dominates per-iter
W10 hnsw sqlrite ~132 ms — same band as brute-
force at 10k vectors
W11 BM25 top-10 sqlrite ~533 us / sqlite ~24 us — ~22x (healthy band)
W12 hybrid sqlrite ~654 us — RAG headline
W11's ~22× is one of the smaller gaps in the suite — SQLRite's
BM25 path is in the same per-iter-parse-dominated band as W1 / W6
(rather than the per-row-commit-dominated W4 / W5).
W10's brute-force vs HNSW gap is essentially noise at 10k vectors:
both paths are dominated by the per-iter ~4 KB SQL parse cost (the
384-dim bracket-array literal in ORDER BY). HNSW would dominate
at much larger corpus sizes; at 10k the parse cost masks the
algorithmic win. A future "vector-bind" or "prepared-vector-query"
path would surface the real gap.
Suite wiring:
- Three new workload files (vector.rs, fts.rs, hybrid.rs) plus
matching dataset generators in data.rs (vector_dataset,
fts_dataset, plus the synthetic-word fts_word builder).
- benches/suite.rs grew register_w10 / register_w11 / register_w12.
W10 registers two criterion groups per driver (brute-force +
hnsw); W11 / W12 register one each. driver_supports gates
SQLite-incompatible workloads cleanly.
- W11's bench_iter branches on driver.name() — SQLite gets an
OR-joined query string to match SQLRite's any-of fts_match
semantics (FTS5's default operator is AND).
Verification:
- cargo fmt --all -- --check clean
- cargo clippy -p sqlrite-benchmarks --all-targets clean
- Full CI-equivalent build / test / doc green
(--exclude desktop / python / nodejs / benchmarks)
- Smoke run end-to-end across W10..W12 + aggregator → JSON envelope
- W11 / W12 correctness gates pass on both drivers (after the
OR-join fix on the SQLite path)
Refs: SQLR-16 (parent), SQLR-21 (Phase 8.1 FTS overflow chaining).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 7, 2026
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.
Summary
Sub-phase 9.4 of
docs/benchmarks-plan.md. Builds on #102 / #103 / #104. Lands the three Phase 7 / Phase 8 differentiator workloads:USING ftsvs SQLite FTS5 virtual tableexamples/hybrid-retrieval/)Smoke-run numbers (M1 Pro, criterion
--warm-up-time 1 --measurement-time 1 --sample-size 10)W11's ~22× is one of the smaller gaps in the suite — SQLRite's BM25 path sits in the same per-iter-parse-dominated band as W1 / W6, not the per-row-commit-dominated W4 / W5.
W10's HNSW vs brute-force is essentially flat at 10k vectors — both paths are dominated by the per-iter ~4 KB SQL parse cost (the 384-dim bracket-array literal in
ORDER BY). HNSW would shine at much larger corpus sizes; at 10k the parse cost masks the algorithmic win. A future "vector-bind" or "prepared-vector-query" path would surface the real gap.Two plan deviations, documented + tracked
W11 / W12: 10k docs → 1000 docs
Engine constraint — SQLR-21. SQLRite's FTS index serializes a per-doc-length sidecar as a single cell. That cell must fit inside one 4 KiB page (overflow chaining is Phase 8.1, not yet shipped). At ~3 bytes per doc, the practical cap is ~1,360 docs. 10k docs crashed setup with:
v1 ships at 1000 docs with margin. Bumping back to 10k follows SQLR-21 + a
W11.v2/W12.v2tag.W10
sqlite-veccomparator deferredPlan said "sqlite-vec if installable, else SQLRite-only baseline."
rusqlite[bundled]doesn't ship the extension; loading a pre-compiled.dylibat runtime would need extra plumbing. Out of scope for v1 — both W10 variants ship as SQLRite-only. Adding sqlite-vec is a future follow-up alongside libSQL (post-9.6 vector benchmark page).Notable engineering finds
OR-join infts.rs::bench_iterto match SQLRite'sfts_matchany-of semantics. Without it, multi-term queries against the synthetic dictionary returned 0 hits.Test plan
cargo fmt --all -- --checkcleancargo clippy -p sqlrite-benchmarks --all-targetscleancargo build / test / doc --workspace --exclude {desktop,python,nodejs,benchmarks}greencargo test -p sqlrite-benchmarks— 5 tests passcargo bench -p sqlrite-benchmarks --bench suite -- '^W1[012]'runs all three workloads end-to-endFollow-ups
sqlite-vecdriver wiring — adding the extension load path on the rusqlite driver. Lets W10 grow a SQLite comparator column.What's left
9.5 — DuckDB driver, optional, Group B only. Cargo feature wiring + the
make bench-duckdbtarget.9.6 —
scripts/compare.py+ first official pinned-host JSON committed +docs/benchmarks.md(canonical user-facing reference) + top-levelREADME.md"Benchmarks" section.References
docs/benchmarks-plan.mdbenchmarks/src/workloads/{vector,fts,hybrid}.rs🤖 Generated with Claude Code