Repository navigation
branch-4.2: [fix](be) Score MATCH on keyword inverted indexes like SEARCH #69790 - #70008
Merged
Merged
Conversation
…#69790) ### What problem does this PR solve? Issue Number: None Related PR: apache#69051 Problem Summary: score() of a MATCH on an untokenized (keyword) inverted index is always 0, while SEARCH on the same field scores BM25: INDEX idx_redirect (redirect) USING INVERTED -- one row ('BP') SELECT score() FROM t WHERE redirect MATCH 'BP'; -- 0 SELECT score() FROM t WHERE SEARCH('redirect:BP'); -- 0.2876821 Elasticsearch scores a match, term or match_phrase query on a keyword field with BM25 in query context, so the score is the idf of the whole value. apache#69051 made the engine score keyword postings but kept MATCH out: can_score_match required an analyzed index and MatchPredicateCollector returned early for indexes without an analyzer. Fix: a keyword index is eligible for MATCH scoring and the collector collects its whole value as one term, the one the reader looks up (a keyword MATCH_PHRASE drops its " ~N" slop first). Statistics skip what has no terms: a MATCH on a non-string leaf such as CAST(n AS STRING), and a VARIANT path a segment indexed as BKD or does not hold, also when the BKD searcher comes from the searcher cache. A SNII index kind is looked up without copying the directory. Branch adaptations for branch-4.2: - can_score_match keeps 4.2's analyzed rule (support_phrase only); 4.2 has no lowercase-normalizer clause. - test_omit_norms does not exist on 4.2, so its .out change is dropped, and IndexReaderHelperTest has no regexp test here (apache#69815 is not on 4.2). - test_match_keyword_score inserts the VARIANT rows as JSON strings: parse_to_variant in VALUES fails on 4.2 with a max-subcolumns conversion error. The expected output is master's, unchanged. - apache#69901 (statistics per index) is not on 4.2. A MATCH on a keyword and a MATCH on an analyzed index of the same column in one score() query fails with "Scoring predicates for one field select different inverted indexes", as it did on master before apache#69901; before this change the keyword clause scored 0 there. ### Release note score() of MATCH / MATCH_ALL / MATCH_PHRASE on a keyword (untokenized) inverted index now returns the BM25 score of the value, the same as SEARCH, instead of 0. ### Check List (For Author) - Test: Regression test / Unit Test - Unit Test: 1593 tests in IndexReaderHelperTest, CollectionStatistics* and *Snii* pass on branch-4.2 - Regression test: test_match_keyword_score (master's .out, V2/V3/SNII), test_match_phrase_prefix_score, test_bm25_score, test_score_filter_matrix, test_score_filter_usage, test_search_score_topn_predicates, test_multi_analyzer_query, test_match_using_analyzer, test_single_column_multi_index, test_search_score_keyword_filters, test_search_score_raw_index pass - Behavior changed: Yes. Keyword MATCH contributes its BM25 score to score() instead of 0. - Does this need documentation: No Source-PR: apache#69790 Source-Head: a66e73d Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
Member
Author
|
run buildall |
…branch-4.2 # Conflicts: # be/test/storage/segment/index_reader_helper_test.cpp
Member
Author
|
run buildall |
Resolving the backport conflict left the analyzed-index return of can_score_match with the old continuation indent. clang-format 16 only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
Author
|
run buildall |
Contributor
BE UT Coverage ReportIncrement line coverage Increment coverage report
|
Contributor
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
yiguolei
approved these changes
Nov 5, 2026
Contributor
|
PR approved by anyone and no changes requested. |
Contributor
|
PR approved by at least one committer and no changes requested. |
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.
Backport of #69790 to branch-4.2.
What problem does this PR solve?
Issue Number: None
Related PR: #69790, #69051
Problem Summary: score() of a MATCH on an untokenized (keyword) inverted index is always 0, while SEARCH on the same field scores BM25:
Elasticsearch scores match, term and match_phrase on a keyword field with BM25 in query context, so the score is the idf of the whole value. #69051 (already on 4.2) made the engine score keyword postings but kept MATCH out. This makes a keyword index eligible for MATCH scoring and collects its whole value as one term, the one the reader looks up. It also carries the follow-up fixes from #69790's review:
~Nslop before collecting.CAST(n AS STRING)collects nothing.Branch adaptations
can_score_matchkeeps 4.2's analyzed rule (support_phrase only); branch-4.2 has no lowercase-normalizer clause.test_omit_normsdoes not exist on 4.2, so its.outchange is dropped. The branch was cut before branch-4.2: [fix](be) Score regexp and wildcard patterns with a constant like Elasticsearch #69815 #69922 (the 4.2 backport of [fix](be) Score regexp and wildcard patterns with a constant like Elasticsearch #69815) and then merged with branch-4.2 to resolve its conflict inindex_reader_helper_test.cpp: both tests are kept, as on master.test_match_keyword_scoreinserts its VARIANT rows as JSON strings:parse_to_variantinVALUESfails on 4.2 with a max-subcolumns conversion error. The expected output is master's file, unchanged.score()query (name MATCH 'apple' USING ANALYZER english AND name MATCH 'apple' USING ANALYZER none) now fails with "Scoring predicates for one field select different inverted indexes". Master behaved the same before [fix](be) Keep BM25 statistics per index for MATCH on one column #69901. Before this change, that query ran with the keyword clause scoring 0. Each clause alone scores fine. Two analyzed indexes on one column already fail this way on 4.2. Backporting [fix](be) Keep BM25 statistics per index for MATCH on one column #69901 lifts this.Validation
On this branch merged with branch-4.2 c2aaed9, ASAN build:
IndexReaderHelperTest,CollectionStatistics*and*Snii*pass.test_match_keyword_scorepasses against master's.outon V2/V3/SNII. The following also pass:test_match_phrase_prefix_score,test_bm25_score,test_score_filter_matrix,test_score_filter_usage,test_search_score_topn_predicates,test_multi_analyzer_query,test_match_using_analyzer,test_single_column_multi_index(with debug points on),test_search_score_keyword_filters,test_search_score_raw_index,test_search_score_pattern_constant.lance_reader.cpp'slance_scanner_set_scalar_index_auto_selectioncall was stubbed for the local build only. It is not part of this PR.Release note
score() of MATCH / MATCH_ALL / MATCH_PHRASE on a keyword (untokenized) inverted index now returns the BM25 score of the value, the same as SEARCH, instead of 0.
Check List (For Author)
🤖 Generated with Claude Code