Performance Optimizations#2366
Closed
CascadingRadium wants to merge 13 commits into
Closed
Conversation
Two changes to OptimizeTFRDisjunctionUnadorned.Finish():
1. Remove the dead first loop that computed cMax per segment but never
used the result. This was a full O(segments × TFRs) scan for nothing.
2. Add fast paths after collecting actualBMs/docNums for each segment:
- Empty segment (no bitmaps, no 1-hit docs): reuse the zero-alloc
anEmptyPostingsIterator singleton instead of allocating roaring.New()
+ unadornedPostingsIteratorBitmap.
- Single 1-hit doc with no bitmaps: use newUnadornedPostingsIteratorFrom1Hit,
saving the roaring.Bitmap alloc.
Also implement segment.OptimizablePostingsIterator on emptyPostingsIterator
(ActualBitmap→nil, DocNum1Hit→false, ReplaceActual→noop) so that the empty
sentinel composes correctly in nested disjunction optimizations — a second
disjunction:unadorned Finish() treats it as contributing nothing to the OR,
which is correct, rather than aborting the optimization with ok=false.
Impact on entity search corpus (15 segs, 500k docs, 6 keyword fields):
Miss6FieldDisjScoreNone: 273 allocs/op (-14%, was 318)
MissConjScoreNone: 532 allocs/op (-20%, was 667)
The conjunction cascade benefits because emptyPostingsIterator now triggers
the *emptyPostingsIterator short-circuit in conjunction:unadorned Finish(),
saving the AND-of-empty-bitmaps allocation per segment as well.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ation optimizeCompositeSearcher() returns a new merged TermSearcher wrapping a combined bitmap, but never closed the original N sub-searchers. Their TFRs were never returned to the snapshot per-field pool (is.fieldTFRs), so every subsequent query reopened the Dictionary + vellum FST Reader for each field and segment — 90 dictionary() calls per EntityRare6FieldDisjScoreNone query. Close the original qsearchers in newDisjunctionSearcher immediately after the optimization succeeds. This is safe because OptimizeTFRDisjunctionUnadorned Finish() clones/creates all bitmaps before returning, so the originals hold no shared state. The close loop is intentionally in newDisjunctionSearcher (not inside optimizeCompositeSearcher) because optimizeMultiTermSearcher already calls cleanup() on its batch after the call — putting it inside would double-close. For EntityRare6FieldDisjScoreNone the TFR pool now stays warm across queries, eliminating the 24.9M dictionary alloc_objects (90/query) and contributing the remaining ~14µs of the combined -59% improvement (33.8µs → 13.8µs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR focuses on reducing allocations and hot-path overhead in search execution and collection, including optimized disjunction handling, faster TopN finalization, and a specialized score-descending comparator.
Changes:
- Optimize allocation patterns in term location merging, score breakdown reset, and unadorned disjunction bitmap building.
- Speed up TopN collection by caching comparator logic and sorting the final heap window directly.
- Improve disjunction optimization lifecycle by closing unused sub-searchers when an optimized composite searcher is returned.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| search/util.go | Adds a fast-path to avoid work when there are no field term locations to merge and adjusts capacity growth logic. |
| search/sort.go | Introduces ScoreCompare to specialize the common “score desc” comparator. |
| search/searcher/search_disjunction.go | Ensures orphaned sub-searchers are closed when the unadorned disjunction optimization succeeds. |
| search/search.go | Avoids clearing a nil score-breakdown map during DocumentMatch.Reset(). |
| search/scorer/scorer_disjunction.go | Attempts to avoid coord math when not needed in disjunction scoring (but currently introduces a compile-time issue). |
| search/collector/topn.go | Caches a comparator function (cmp) and uses it throughout TopN collection/pagination logic. |
| search/collector/heap.go | Replaces repeated heap pops in Final() with an in-place sort of the internal slice and a window copy. |
| index/scorch/optimize.go | Avoids empty bitmap allocations in unadorned disjunction optimization and adds a 1-hit fast path. |
| index/scorch/empty.go | Extends the empty postings iterator to satisfy the optimizable postings iterator API used by the new fast paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Adds 9 unit tests for the collectStoreList type in search/collector that had 0% coverage before this commit. Tests cover round-trip insertion order, size-capped eviction (AddNotExceedingSize), skip-based pagination (Final), Internal() ascending traversal, removeLast worst-doc eviction, single-element and equal-score edge cases, and fixup error propagation — all using existing scoreDesc / makeScoreDoc helpers from heap_test.go. These tests have no dependency on any perf-gar change and can be rebased or cherry-picked independently. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CascadingRadium
requested review from
a team,
Likith101,
Samsonnyyeet,
Thejas-bhat,
capemox,
maneuvertomars and
steveyen
July 2, 2026 07:05
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.
Uh oh!
There was an error while loading. Please reload this page.