Skip to content

Performance Optimizations#2366

Closed
CascadingRadium wants to merge 13 commits into
masterfrom
perfGar1
Closed

Performance Optimizations#2366
CascadingRadium wants to merge 13 commits into
masterfrom
perfGar1

Conversation

@CascadingRadium

@CascadingRadium CascadingRadium commented Jul 1, 2026

Copy link
Copy Markdown
Member
  • perf: §22 guard clear(scoreBreakdown) on nil; MergeFieldTermLocations fast path.
  • perf: §22: Compute coord only when required.
  • perf: §22 skip empty bitmap allocs in disjunction:unadorned Finish().
  • perf: specialize score-descending comparator + sort.Slice in heap Final.
  • fix: close orphaned sub-searchers after unadorned disjunction optimization.
  • test: cover collectStoreList linked-list store, collectStoreHeap and collectStoreKNN (pre-perf-gar gap).

steveyen and others added 7 commits July 1, 2026 21:24
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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread search/scorer/scorer_disjunction.go Outdated
@coveralls

coveralls commented Jul 1, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 52.305% (+0.2%) from 52.142% — perfGar1 into master

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread search/collector/heap.go
steveyen and others added 2 commits July 2, 2026 11:21
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 CascadingRadium changed the title MB-72489: Performance Optimizations Performance Optimizations Jul 2, 2026
@CascadingRadium
CascadingRadium deleted the perfGar1 branch July 2, 2026 08:38
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.

4 participants