Skip to content

fix(rank-fusion): show previous page on multi-page semantic-only results#3180

Merged
marevol merged 1 commit into
masterfrom
fix/rankfusion-pagination-prevpage
Jul 2, 2026
Merged

fix(rank-fusion): show previous page on multi-page semantic-only results#3180
marevol merged 1 commit into
masterfrom
fix/rankfusion-pagination-prevpage

Conversation

@marevol

@marevol marevol commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Problem

When rank fusion runs and the primary (BM25 / default) searcher returns few or zero hits while a secondary searcher (e.g. a semantic/multimodal searcher) returns many, pagination breaks on multi-page result sets:

  • prev_page is false on every page past the first, so themes that key their pager on prev_page/next_page hide the whole control and the user cannot navigate back.
  • page_count inflates by one, one page past the actual end.

Example: a query that matches 37 documents only via the secondary searcher (4 pages of 10) reports prev_page=false on pages 2–4 and page_count=5 past the end. A normal keyword query paginates correctly, because BM25 contributes to the main searcher's hit set.

Root cause

QueryResponseList's offset field does double duty:

  • The rank-fusion merge inflates the effective record count by offset when the primary searcher contributes few/zero hits (allRecordCount = mainCount + offset).
  • calculatePageInfo() also reused that same offset-adjusted value (startWithOffset = start - offset) as a navigation origin-shift for the pagination flags.

When the primary searcher returns ~0 hits, offset inflates to roughly the full result count, so startWithOffset clamps to 0 on every page. That makes existPrevPage = startWithOffset > 0 false on all pages, and a spurious next page one page past the end is then collapsed into an inflated allPageCount.

Fix

Decouple the navigation flags from the count-inflation role inside calculatePageInfo():

  • existPrevPage now also considers currentPageNumber — a previous page exists whenever we are past page 1.
  • existNextPage is computed from the raw start, keeping it consistent with allPageCount (which is derived from allRecordCount), instead of the offset-deflated startWithOffset.

No other pagination logic changes. For offset == 0 (all non-fusion / single-searcher paths) the behavior is provably identical to before, and normal deep-pagination behavior is preserved.

Tests

Added QueryResponseListTest#test_calculatePageInfo_rankFusionZeroMainMultiPage covering the zero-primary multi-page case: previous page present on pages 2–4, no spurious next page, page_count stays 4, and no previous page on page 1.

QueryResponseListTest (38 tests) and RankFusionProcessorTest (11 tests) pass with no regressions.

The offset field in QueryResponseList was doing double duty: it is used by the
rank-fusion merge step to inflate the effective record count when the primary
(BM25/default) searcher returns few or zero hits while a secondary searcher
returns many, but calculatePageInfo() also reused that same offset-adjusted
value (startWithOffset) as a navigation origin-shift for pagination flags. When
offset inflated to roughly the full result count, startWithOffset clamped to 0
on every page, making existPrevPage false on all pages past the first and
producing a spurious next page one page beyond the actual end.

This change decouples the navigation flags from that count-inflation role:
existPrevPage now also considers currentPageNumber, and existNextPage is
computed from the raw start (consistent with allPageCount, which is derived
from allRecordCount) instead of the offset-deflated startWithOffset. No other
pagination logic changed.
@marevol marevol self-assigned this Jul 2, 2026
@marevol marevol added the bug label Jul 2, 2026
@marevol marevol added this to the 15.8.0 milestone Jul 2, 2026
@marevol marevol merged commit 46cc73d into master Jul 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant