-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[improvement](scan) Align scanner split to segments for MATCH #67915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -460,6 +460,17 @@ static bool contains_expr_node_type(const VExprSPtr& expr, TExprNodeType::type n | |
| }); | ||
| } | ||
|
|
||
| // Find MATCH recursively; ones nested in AND / OR / NOT count too. | ||
| static bool is_match_expr(const VExprSPtr& expr) { | ||
| DORIS_CHECK(expr != nullptr); | ||
| if (expr->node_type() == TExprNodeType::MATCH_PRED || | ||
| expr->node_type() == TExprNodeType::SEARCH_EXPR || expr->can_push_down_to_index()) { | ||
| return true; | ||
| } | ||
| return std::ranges::any_of(expr->children(), | ||
| [](const auto& child) { return is_match_expr(child); }); | ||
| } | ||
|
|
||
| static Status validate_residual_scan_conjuncts(RuntimeState* state, | ||
| TPushAggOp::type push_down_agg_type, | ||
| const VExprContextSPtrs& conjuncts) { | ||
|
|
@@ -635,6 +646,21 @@ bool OlapScanLocalState::_is_binlog_merge_scan() const { | |
| return scan_type == TBinlogScanType::MIN_DELTA || scan_type == TBinlogScanType::DETAIL; | ||
| } | ||
|
|
||
| // Give each segment a scanner of its own for queries like: | ||
| // SELECT k1 FROM t ORDER BY l2_distance_approximate(embedding, [1.0, 2.0]) LIMIT 2 | ||
| // SELECT k1 FROM t WHERE msg MATCH_PHRASE 'error timeout' | ||
| bool OlapScanLocalState::_use_scan_parallelism_by_per_segment() { | ||
| // TODO: Use optimize_index_scan_parallelism for ann range search in the future. | ||
| // Currently, ann topn is enough | ||
| if (state()->query_options().__isset.optimize_index_scan_parallelism && | ||
| state()->query_options().optimize_index_scan_parallelism && _ann_topn_runtime != nullptr) { | ||
| return true; | ||
| } | ||
| return config::is_cloud_mode() && | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Preserve global BM25 statistics before splitting by segment. This branch also covers score-enabled MATCH/SEARCH scans. Each generated scanner gets one segment from one rowset, and
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CollectionStatistics 一直是按scanner 的粒度构建的 |
||
| std::ranges::any_of(_common_expr_ctxs_push_down, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Include pushed-down MATCH virtual-column projections in this decision. Projection-only MATCH is stored in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不考虑 projection 先,仅针对 where 后面的倒排索引计算 |
||
| [](const auto& ctx) { return is_match_expr(ctx->root()); }); | ||
| } | ||
|
|
||
| Status OlapScanLocalState::_init_scanners(std::list<ScannerSPtr>* scanners) { | ||
| if (_scan_ranges.empty()) { | ||
| _eos = true; | ||
|
|
@@ -764,15 +790,7 @@ Status OlapScanLocalState::_init_scanners(std::list<ScannerSPtr>* scanners) { | |
| std::max<int64_t>(1024, state()->parallel_scan_min_rows_per_scanner()); | ||
| scanner_builder.set_max_scanners_count(max_scanners_count); | ||
| scanner_builder.set_min_rows_per_scanner(min_rows_per_scanner); | ||
| // If the session variable is set, force one scanner per segment. | ||
| if (state()->query_options().__isset.optimize_index_scan_parallelism && | ||
| state()->query_options().optimize_index_scan_parallelism) { | ||
| // TODO: Use optimize_index_scan_parallelism for ann range search in the future. | ||
| // Currently, ann topn is enough | ||
| if (_ann_topn_runtime != nullptr) { | ||
| scanner_builder.set_scan_parallelism_by_per_segment(true); | ||
| } | ||
| } | ||
| scanner_builder.set_scan_parallelism_by_per_segment(_use_scan_parallelism_by_per_segment()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Keep segment-aligned scans within the configured scanner cap.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. scanner 变多的代价很低 |
||
|
|
||
| RETURN_IF_ERROR(scanner_builder.build_scanners(*scanners)); | ||
| for (auto& scanner : *scanners) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P1] Gate this on index execution, not only on expression shape. With
enable_inverted_index_query=false(or a MATCH column without an iterator), this still returns true even though SegmentIterator skips index evaluation and runs the supported row fallback. On a single large segment, the old row-count builder can split that expensive fallback across scanners, while this route creates exactly one scanner and serializes it; on many segments it also triggers the unbounded population noted separately. Row-only wrappers have the same false positive because their roots never dispatchevaluate_inverted_index()to the MATCH child. Require index execution to be enabled and a usable/index-evaluable root before selecting this strategy.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
在cloud 上可以认为 match 的执行一定有倒排索引的