diff --git a/internal/handler/search.go b/internal/handler/search.go index a944167..823a754 100644 --- a/internal/handler/search.go +++ b/internal/handler/search.go @@ -70,19 +70,15 @@ var collectionQueryByWeights = map[string]string{ "other_documents": "10,10,2,2", } -// collectionTextMatchType lets specific collections opt-in to `sum_score` -// instead of the Typesense default `max_score`. +// searchStopwordsSet is the name of the Typesense stopwords set applied to +// every search. The set is configured server-side (`PUT /stopwords/common`) +// and contains conversational words like "letter", "to", "of", "essay", etc. // -// `sum_score` boosts documents that match in MULTIPLE fields, so e.g. a letter -// whose `recipient_display` AND `content` both contain the query ranks above -// a letter that only matches in `content`. Useful for collections that have a -// strong metadata field (recipient, title) tied to the user's intent. -// -// `max_score` (default elsewhere) preserves single-field dominance — important -// for verses where the canonical verse should beat commentaries that quote it. -var collectionTextMatchType = map[string]string{ - "letters": "sum_score", -} +// Without this, a query like "letter to tusta krsna" ranks letters that merely +// contain "letter" and "to" in their body above letters whose recipient is +// actually "Tusta Krsna", because those common tokens contribute heavily to +// the multi-field score. +const searchStopwordsSet = "common" // searchResultItem represents a single search result in the API response. type searchResultItem struct { @@ -212,6 +208,7 @@ func (h *SearchHandler) multiSearch(ctx context.Context, collections []string, q Prefix: stringPtr("true"), NumTypos: stringPtr("2"), ExhaustiveSearch: &exhaustive, + Stopwords: stringPtr(searchStopwordsSet), // Boost docs whose tokens are exact matches and appear early in the field // so "karma" outranks "karmic" and frequent matches outrank single ones. PrioritizeExactMatch: &prioritizeExact, @@ -220,9 +217,6 @@ func (h *SearchHandler) multiSearch(ctx context.Context, collections []string, q if weights != "" { params.QueryByWeights = stringPtr(weights) } - if tmt := collectionTextMatchType[col]; tmt != "" { - params.TextMatchType = stringPtr(tmt) - } searches = append(searches, params) } @@ -287,6 +281,7 @@ func (h *SearchHandler) singleSearch(ctx context.Context, collection, query stri Prefix: stringPtr("true"), NumTypos: stringPtr("2"), ExhaustiveSearch: &exhaustive, + Stopwords: stringPtr(searchStopwordsSet), // Boost docs whose tokens are exact matches and appear early in the field // so "karma" outranks "karmic" and frequent matches outrank single ones. PrioritizeExactMatch: &prioritizeExact, @@ -295,9 +290,6 @@ func (h *SearchHandler) singleSearch(ctx context.Context, collection, query stri if weights := collectionQueryByWeights[collection]; weights != "" { params.QueryByWeights = stringPtr(weights) } - if tmt := collectionTextMatchType[collection]; tmt != "" { - params.TextMatchType = stringPtr(tmt) - } sr, err := h.ts.Client.Collection(collection).Documents().Search(ctx, params) if err != nil {