perf(fts): delay must-not probes until candidates survive - #8574
perf(fts): delay must-not probes until candidates survive#8574BubbleCal wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
✅ Gate recommendation: approve.
The positive-preflight-and-replay design defers prohibited posting I/O only for partitions that can still contribute to global top-k, while exact membership, phrase confirmation, visibility, score-floor equality, and row-ID tie ordering remain intact.
Compared with filtering a provisional top-k, this keeps the exact post-exclusion scorer authoritative, so excluded candidates never raise the shared floor.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Closing this optimization path after the 10M MMLB results. The exact implementation improved target k=10 throughput by only 1.023-1.026x, was effectively flat at k=100, and regressed the dense all-match k=100 control by 1.013x. Rebasing and reviewing the conflicting change is not justified relative to the higher-impact follow-ups now tracked in Linear. |
What is the performance issue?
Same-column compound FTS evaluated Boolean
MUST_NOTclauses while advancing the positive driver. Candidates rejected by positive two-phase confirmation, block bounds, or the exact competitive score could still pay for prohibited posting advances and phrase confirmation. Prohibited clauses also used scoring cursors even though exclusion only needs exact membership, and their postings were loaded before the query knew whether a partition contained a competitive positive candidate.Closes OSS-1705.
How does this PR improve performance?
This follows the same separation used by Lucene's
ReqExclScorerandCOMPLETE_NO_SCOREShandling inBooleanScorerSupplier:MUST_NOTconfirmation until the exact positive side survives two-phase matching and the current competitive score floor. The current-document positive score and prohibited decision are cached.CompleteNoScoresthrough the complete prohibited subtree, including nested Boolean, MultiMatch, and Boost queries. Membership-irrelevant scoring branches are removed while query validation remains unchanged.MUST_NOT.The query API and persisted index format do not change.
Measurement
10M-row end-to-end benchmark
Every value below is the geometric mean of four isolated process samples per build and case. Throughput is higher-is-better; latency is lower-is-better.
MUST_NOT, k=10 throughputMUST_NOT, k=10 p99 latencyMUST_NOT, k=100 throughputMUST_NOT, k=100 p99 latencyMUST_NOT, k=10 throughputMUST_NOT, k=10 p99 latencyMUST_NOT, k=100 throughputMUST_NOT, k=100 p99 latencyMUST_NOTcontrol, k=10 throughputMUST_NOTcontrol, k=10 p99 latencyMUST_NOTcontrol, k=100 throughputMUST_NOTcontrol, k=100 p99 latencyMUST_NOT, k=10 throughputMUST_NOT, k=10 p99 latencyMUST_NOT, k=100 throughputMUST_NOT, k=100 p99 latencyThe intended tight-top-k workloads improve most: k=10 gains 1.023-1.026x throughput and 1.089-1.112x p99 latency. At k=100, fewer candidates can be eliminated before exclusion, so throughput is close to flat. The dense all-match k=100 case is the expected adverse control: it never establishes a useful accepted-result floor and regresses throughput by 1.013x. The no-
MUST_NOTcontrol is within 0.5% of baseline.Methodology: GCP
c4-highmem-16inus-central1-c(16 vCPU, 121 GiB OS-visible RAM), frozen 10,000,000-row MMLB code dataset spanning 42 languages and 10 fragments, 37.8 GiB FTS index, 64 GiB Lance index cache, 8 workers, andrelease-with-debug. Each case ran 1,000 deterministic queries repeated 20 times (20,000 timed executions). Two A-B-B-A blocks compared baseline706b941b6with target source tree0c4bad883, reversed case order, and prewarmed positions in every process. The suite completed 1,280,000 timed executions. All 56,000 cross-process result signatures matched exactly, and the input index tree was unchanged before and after the run.This hot-cache benchmark primarily measures delayed confirmation and no-score CPU work. The doc-only decoder reduces decoding CPU, not persisted bytes for a posting that is loaded. True cold-I/O avoidance is covered deterministically by the deferred-posting-load integration tests rather than claimed from this prewarmed latency run.
Validation
cargo test -p lance-index --lib(1,050 passed, 2 ignored)cargo check -p lance-index --testscargo fmt --all -- --checkcargo clippy --all --tests --benches -- -D warningsRegression coverage includes required conjunction, required-plus-optional, pure
SHOULD, nested Boolean/MultiMatch/Boost, Phrase prohibitions, multiple fragments and partitions, score-floor ties, signed negative subtrees, visibility masks, projection overflow retry, cached and uncached prohibited postings, and doc-only plain/compressed OR and AND cursors.