From eadef33eac45d7ac8c74a30991763ae2442e615a Mon Sep 17 00:00:00 2001 From: Krispire Admin Date: Tue, 23 Jun 2026 14:04:08 +0530 Subject: [PATCH] fix: search fix --- internal/handler/search.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/internal/handler/search.go b/internal/handler/search.go index 7c74999..2153a05 100644 --- a/internal/handler/search.go +++ b/internal/handler/search.go @@ -203,11 +203,20 @@ func (h *SearchHandler) multiSearch(ctx context.Context, collections []string, q prioritizeTokenPos := true prefix, numTypos := fuzzinessKnobs(exact) searches := make([]api.MultiSearchCollectionParameters, 0, len(collections)) + // Merge-paginate: every sub-search fetches the first page*limit hits (page 1, + // a wide window) so the merged top page*limit is fully covered; we slice the + // requested page out after sorting below. Asking each collection for its OWN + // page N instead would miss globally-ranked hits and go blank past page 1 + // (e.g. a sparse query whose few hits all sit in each collection's page 1). + window := page * limit + if window > 250 { // Typesense per_page ceiling + window = 250 + } for _, col := range collections { queryBy := collectionQueryByFields[col] weights := collectionQueryByWeights[col] - perPage := limit - pg := page + perPage := window + pg := 1 params := api.MultiSearchCollectionParameters{ Collection: col, Q: stringPtr(query), @@ -262,14 +271,18 @@ func (h *SearchHandler) multiSearch(ctx context.Context, collections []string, q return allItems[i].score > allItems[j].score }) - // Paginate the merged results: since each sub-search already returned `limit` - // results for the given page, the merged set has at most 9*limit items. - // We take the top `limit` after sorting. - if len(allItems) > limit { - allItems = allItems[:limit] + // Slice the requested page out of the merged ranking. Collections hold + // disjoint documents, so totalFound (sum of per-collection founds) is the + // exact total and start past the end means the page is genuinely empty. + start := (page - 1) * limit + if start >= len(allItems) { + return []searchResultItem{}, totalFound } - - return allItems, totalFound + end := start + limit + if end > len(allItems) { + end = len(allItems) + } + return allItems[start:end], totalFound } // singleSearch searches a single collection.