perf(fts): prune low-scoring conjunction candidates#7386
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Xuanwo
left a comment
There was a problem hiding this comment.
I did not find a blocking correctness, security, or concurrency issue in the AND prune itself.
The remaining test gap is that the new prune branch is only directly covered for the compressed posting path. Plain postings, phrase AND, fuzzy AND, mask/tombstone filtering, and exec/analyze-plan metric exposure are still not directly covered, so the unchanged-semantics claim is mostly carried by existing tests rather than targeted coverage for this branch.
| .saturating_sub(pruned_before_return_start); | ||
| metrics.record_and_candidates_seen(and_candidates_seen); | ||
| metrics.record_and_candidates_pruned_before_return(and_candidates_pruned_before_return); | ||
| metrics.record_and_candidates_pruned_before_score(and_candidates_pruned_before_return); |
There was a problem hiding this comment.
These two counters are recorded from the same value, while and_candidates_seen only counts candidates that returned from next(). Once exposed as plan metrics, these names can lead users to compute prune rates with the wrong denominator.
Performance Improvement
What is the performance issue or bottleneck?
For FTS conjunction searches, once the top-k threshold is established, the AND path can still fully validate and score aligned candidate documents even when a cheap upper bound proves they cannot enter the heap. That pays for full BM25 scoring, phrase checks, and frequency collection for candidates that are already below the competitive threshold.
How does this PR improve performance?
This adds an AND-only score-first candidate prune in
Wand::search. After all conjunction postings are aligned, the scorer first computes the exact contribution of one lead posting, then adds the remaining postings' current block-max scores as a safe upper bound. If that upper bound cannot beat the threshold, the candidate is skipped before phrase validation, full scoring, and term-frequency collection.The change is intentionally narrow:
wand_factor == 1.0.Benchmark or measurement results
No end-to-end benchmark was run for this draft. The new regression coverage includes a counting scorer case that verifies low-scoring AND candidates avoid full scoring, plus a top-k correctness case that keeps a later high-scoring candidate.
Validation
cargo fmt --all --checkgit diff --checkCARGO_TARGET_DIR=/tmp/lance-target-fts-and-prune-main cargo test -p lance-index scalar::inverted::wand::tests -- --nocaptureCARGO_TARGET_DIR=/tmp/lance-target-fts-and-prune-clippy cargo clippy --all --tests --benches -- -D warnings