Repository navigation
branch-4.1: [fix](nereids) Support minimum score filters without TopN #69292 - #69565
Merged
yiguolei merged 3 commits intoOct 26, 2026
Merged
Conversation
### What problem does this PR solve? Related PR: apache#69399 Problem Summary: Backport apache#69399 to branch-4.1. A CTE that orders by score() or by an ANN distance with a LIMIT, or that has MATCH in its select list and is inlined after rewrite, failed with "A expression contains slot not from children". LogicalPlanDeepCopier gave each virtual column two ids, copied them in list order, kept the old slot in the output of the copied scan and left the score and ANN order keys on the old slots. The copier now maps every virtual column to its new id before copying their expressions and remaps the order keys, and LogicalOlapScan.withVirtualColumns replaces the old virtual slots in the output. The branch has no table streams, so the change to LogicalOlapTableStreamScan is dropped. withVirtualColumns keeps the constructor call of the branch, and LogicalPlanDeepCopierTest and CTEInlineTest keep the tests of the branch and add the tests of apache#69399. ### Release note Fix "A expression contains slot not from children" for a CTE that orders by score() or by an ANN distance with a LIMIT, or that has MATCH in its select list and is inlined after rewrite. ### Check List (For Author) - Test: Includes the unit and regression tests of apache#69399; results are recorded in the pull request. - Behavior changed: No. - Does this need documentation: No. Source-PR: apache#69399 Source-Head: 5be9ff5 Co-Authored-By: Claude Opus 5.5 <[email protected]>
### What problem does this PR solve? Related PR: apache#69292 Problem Summary: Backport apache#69292 to branch-4.1. score() only worked as ORDER BY score() LIMIT n directly above the scan whose MATCH defines it. A minimum score filter without that TopN evaluated the unbound score() placeholder as zero and silently dropped every row: SELECT id FROM t WHERE c1 MATCH 'apple' AND score() > 0.00001 returned nothing. BindScoreToOlapScan, which replaces CheckScoreUsage, binds score() to the scan of its SELECT at the start of rewrite and rejects the uses it cannot bind. The minimum score stays a predicate of the scan, and PushDownScoreTopNIntoOlapScan still pushes a TopN on the score together with the minimum. In the BE, an expression on the score reads the score column instead of evaluating Score(), and MATCH projections do not add to the score. This needs the backport of apache#69399: binding happens before CTE inlining, which copies scans with virtual columns. Branch adaptations: - The SegmentIterator of the branch collects the columns of pushed-down expressions in _extract_common_expr_columns instead of per-column states, so the score column is marked there, and the new BE test checks _common_expr_columns and _is_common_expr_column. - The branch evaluates MATCH projections with evaluate_inverted_index directly, and that loop runs without the score collector. - PushDownScoreTopNIntoOlapScan keeps the overflow check of the branch for limit + offset, which fails like master does. - SearchDslParser and CollectionSimilarity are included from their packages on the branch. - The branch has no SNII storage format, so BindScoreToOlapScanTest and test_score_filter_matrix cover V2 and V3, and the .out of test_score_filter_matrix is regenerated without the SNII cases. - The branch does not have apache#68672, which keeps predicates on virtual columns out of the condition cache. The minimum score is now a predicate of the scan, and a score depends on every rowset, so a cached result goes stale when a rowset is added: test_score_filter_matrix lost rows. VirtualSlotRef::get_digest returns 0 as on master, the part of apache#68672 that this needs, with the VirtualSlotRef tests of apache#68672 that the branch can run. ### Release note score() works in the select list, window functions and ORDER BY of a SELECT on one table whose WHERE clause has MATCH or SEARCH, with an optional minimum score score() > x or score() >= x, without ORDER BY score() LIMIT. A scored SELECT in a subquery, view, CTE or set operation still needs ORDER BY score() LIMIT. Other uses of score() are rejected instead of evaluating it as 0. ### Check List (For Author) - Test: Includes the unit and regression tests of apache#69292; results are recorded in the pull request. - Behavior changed: Yes. A minimum score works without ORDER BY score() LIMIT, and unsupported uses of score() fail planning instead of evaluating it as 0. A minimum score without a TopN needs the BE change, so BEs must be upgraded before FEs. - Does this need documentation: Yes. The score() documentation should describe where score() can be used. Source-PR: apache#69292 Source-Head: 7a621a1 Co-Authored-By: Claude Opus 5.5 <[email protected]>
Member
Author
|
run buildall |
Contributor
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
Contributor
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
Contributor
FE Regression Coverage ReportIncrement line coverage |
### What problem does this PR solve? Related PR: apache#69292 Problem Summary: CI on branch-4.1 draws enable_common_expr_pushdown at random for each session. With it off, MATCH is not evaluated with the inverted index in the scan, so no BM25 score is collected and score() returns 0. test_score_filter_usage and test_score_filter_matrix got no rows for a minimum score, and test_cte_inline_virtual_column got score 0.0 for its TopN. Like the score suites of the branch, these suites set enable_common_expr_pushdown = true. ### Release note None ### Check List (For Author) - Test: Regression test. With use_fuzzy_session_variable = true and the pull request number of CI, the three suites failed in sessions that drew enable_common_expr_pushdown = false (1 to 3 suites per run); with the setting pinned, four runs passed. - Behavior changed: No - Does this need documentation: No Co-Authored-By: Claude Opus 5.5 <[email protected]>
Member
Author
|
run buildall |
Contributor
FE UT Coverage ReportIncrement line coverage |
Contributor
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
Contributor
FE Regression Coverage ReportIncrement line coverage |
yiguolei
approved these changes
Oct 26, 2026
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.
What problem does this PR solve?
Related PR: #69292
Problem Summary: Backport #69292 to
branch-4.1. It contains the commit of #69563, the backport of #69399, which it needs: binding runs before CTE inlining, which copies scans with virtual columns. Merge #69563 first.score()only worked asORDER BY score() LIMIT ndirectly above the scan whose MATCH defines it. A minimum score filter without that TopN evaluated the unboundscore()placeholder as zero and silently dropped every row:BindScoreToOlapScan, which replacesCheckScoreUsage, bindsscore()to the scan of its SELECT at the start of rewrite and rejects the uses it cannot bind. The minimum score stays a predicate of the scan, andPushDownScoreTopNIntoOlapScanstill pushes a TopN on the score together with the minimum. In the BE, an expression on the score reads the score column instead of evaluatingScore(), and MATCH projections do not add to the score. See #69292 for the supported and rejected uses.Branch adaptations
SegmentIteratorof the branch collects the columns of pushed-down expressions in_extract_common_expr_columnsinstead of per-column states, so the score column is marked there, and the new BE test checks_common_expr_columnsand_is_common_expr_column. The branch reads the columns collected there before it evaluates the expressions, also virtual ones, and a virtual slot uses a column that is already read.evaluate_inverted_indexdirectly, and that loop runs without the score collector.PushDownScoreTopNIntoOlapScankeeps the overflow check of the branch forlimit + offset, which fails like master does.SearchDslParserandCollectionSimilarityare included from their packages on the branch.BindScoreToOlapScanTestandtest_score_filter_matrixcover V2 and V3, and the.outoftest_score_filter_matrixis regenerated without the SNII cases.test_score_filter_matrixlost the rows of the first rowset.VirtualSlotRef::get_digestreturns 0 as on master, the part of [fix](cache) Share cache eligibility for nondeterministic expressions #68672 that this needs, with theVirtualSlotReftests of [fix](cache) Share cache eligibility for nondeterministic expressions #68672 that the branch can run.test_score_filter_usage,test_score_filter_matrixandtest_cte_inline_virtual_columnsetenable_common_expr_pushdown = true, as the score suites of the branch do: CI on branch-4.1 draws it at random for each session, and without it MATCH is not evaluated with the index in the scan andscore()is 0.Release note
score()works in the select list, window functions and ORDER BY of a SELECT on one table whose WHERE clause has MATCH or SEARCH, with an optional minimum scorescore() > xorscore() >= x, withoutORDER BY score() LIMIT. A scored SELECT in a subquery, view, CTE or set operation still needsORDER BY score() LIMIT. Other uses ofscore()are rejected instead of evaluating it as 0.Check List (For Author)
ORDER BY score() LIMIT, and unsupported uses ofscore()fail planning instead of evaluating it as 0. A minimum score without a TopN needs the BE change, so BEs must be upgraded before FEs.score()documentation should describe wherescore()can be used.Validation
Validated together with the other two backports (#69399, #69419 and #69292 on
branch-4.1at 3f911d0), in a local ASAN build:LogicalPlanDeepCopierTest,CTEInlineTest,InferPredicateByReplaceTest,InferPredicatesTest,UnequalPredicateInferTest,BindScoreToOlapScanTest,SearchExpressionTest,TopNRuntimeFilterTestandMaterializedViewUtilsTest(228 tests), and FE Checkstyle../build.sh --beand./build.sh --fe.SegmentIteratorScoreCommonExprTest,SegmentIteratorApplyIndexExprTestandVirtualSlotRefTest(31 tests); clang-format 16 on the changed BE files.score(), includingtest_cte_inline_virtual_column,infer_match_predicate,test_score_filter_usageandtest_score_filter_matrix. The framework regenerated the.outoftest_score_filter_matrixon this branch: it drops the 46 SNII cases and keeps the 94 V2 and V3 cases of master unchanged. The other.outfiles are unchanged.use_fuzzy_session_variable = trueand its pull request number), the score suites failed in sessions that drewenable_common_expr_pushdown = false; with the setting pinned, four runs oftest_score_filter_usage,test_score_filter_matrixandtest_cte_inline_virtual_column, and four ofinfer_match_predicate, passed.🤖 Generated with Claude Code