/root/doris/be/src/exprs/vexpr_context.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #pragma once |
19 | | |
20 | | #include <glog/logging.h> |
21 | | |
22 | | #include <algorithm> |
23 | | #include <cstddef> |
24 | | #include <memory> |
25 | | #include <string> |
26 | | #include <unordered_map> |
27 | | #include <utility> |
28 | | #include <vector> |
29 | | |
30 | | #include "common/factory_creator.h" |
31 | | #include "common/status.h" |
32 | | #include "core/block/block.h" |
33 | | #include "core/block/column_with_type_and_name.h" |
34 | | #include "core/column/column.h" |
35 | | #include "exec/runtime_filter/runtime_filter_selectivity.h" |
36 | | #include "exprs/expr_zonemap_filter.h" |
37 | | #include "exprs/function_context.h" |
38 | | #include "exprs/vexpr_fwd.h" |
39 | | #include "runtime/runtime_state.h" |
40 | | #include "storage/index/ann/ann_range_search_runtime.h" |
41 | | #include "storage/index/ann/ann_search_params.h" |
42 | | #include "storage/index/inverted/inverted_index_reader.h" |
43 | | #include "storage/index/zone_map/zonemap_filter_result.h" |
44 | | #include "storage/segment/column_reader.h" |
45 | | |
46 | | namespace doris { |
47 | | class RowDescriptor; |
48 | | class RuntimeState; |
49 | | class Schema; |
50 | | class ZoneMapEvalContext; |
51 | | using SchemaSPtr = std::shared_ptr<const Schema>; |
52 | | } // namespace doris |
53 | | |
54 | | namespace doris::segment_v2 { |
55 | | class Segment; |
56 | | class ColumnIterator; |
57 | | class Segment; |
58 | | } // namespace doris::segment_v2 |
59 | | |
60 | | namespace doris { |
61 | | |
62 | | class ScoreRuntime; |
63 | | class LambdaExecutionContext; |
64 | | using ScoreRuntimeSPtr = std::shared_ptr<ScoreRuntime>; |
65 | | |
66 | | class IndexExecContext { |
67 | | public: |
68 | | IndexExecContext(const std::vector<ColumnId>& col_ids, |
69 | | const std::vector<std::unique_ptr<segment_v2::IndexIterator>>& index_iterators, |
70 | | const std::vector<IndexFieldNameAndTypePair>& storage_name_and_type_vec, |
71 | | std::unordered_map<ColumnId, std::unordered_map<const VExpr*, bool>>& |
72 | | common_expr_index_status, |
73 | | ScoreRuntimeSPtr score_runtime, segment_v2::Segment* segment = nullptr, |
74 | | const segment_v2::ColumnIteratorOptions& column_iter_opts = {}, |
75 | | SchemaSPtr read_schema = nullptr) |
76 | 4.52k | : _col_ids(col_ids), |
77 | 4.52k | _index_iterators(index_iterators), |
78 | 4.52k | _storage_name_and_type(storage_name_and_type_vec), |
79 | 4.52k | _expr_index_status(common_expr_index_status), |
80 | 4.52k | _score_runtime(std::move(score_runtime)), |
81 | 4.52k | _segment(segment), |
82 | 4.52k | _column_iter_opts(column_iter_opts), |
83 | 4.52k | _read_schema(std::move(read_schema)) {} |
84 | | |
85 | 41 | segment_v2::IndexIterator* get_inverted_index_iterator_by_column_id(int column_index) const { |
86 | 41 | if (column_index < 0 || column_index >= _col_ids.size()) { |
87 | 0 | return nullptr; |
88 | 0 | } |
89 | 41 | const auto& column_id = _col_ids[column_index]; |
90 | 41 | if (column_id >= _index_iterators.size()) { |
91 | 0 | return nullptr; |
92 | 0 | } |
93 | 41 | if (!_index_iterators[column_id]) { |
94 | 6 | return nullptr; |
95 | 6 | } |
96 | 35 | return _index_iterators[column_id].get(); |
97 | 41 | } |
98 | | |
99 | | const IndexFieldNameAndTypePair* get_storage_name_and_type_by_column_id( |
100 | 35 | int column_index) const { |
101 | 35 | if (column_index < 0 || column_index >= _col_ids.size()) { |
102 | 0 | return nullptr; |
103 | 0 | } |
104 | 35 | const auto& column_id = _col_ids[column_index]; |
105 | 35 | if (column_id >= _storage_name_and_type.size()) { |
106 | 1 | return nullptr; |
107 | 1 | } |
108 | 34 | return &_storage_name_and_type[column_id]; |
109 | 35 | } |
110 | | |
111 | 0 | bool get_column_id(int column_index, ColumnId* column_id) const { |
112 | 0 | if (column_id == nullptr) { |
113 | 0 | return false; |
114 | 0 | } |
115 | 0 | if (column_index < 0 || column_index >= _col_ids.size()) { |
116 | 0 | return false; |
117 | 0 | } |
118 | 0 | *column_id = _col_ids[column_index]; |
119 | 0 | return true; |
120 | 0 | } |
121 | | |
122 | 0 | segment_v2::Segment* segment() const { return _segment; } |
123 | | |
124 | 0 | const SchemaSPtr& read_schema() const { return _read_schema; } |
125 | | |
126 | 0 | const segment_v2::ColumnIteratorOptions& column_iter_opts() const { return _column_iter_opts; } |
127 | | |
128 | 105 | bool has_index_result_for_expr(const VExpr* expr) const { |
129 | 105 | return _index_result_bitmap.contains(expr); |
130 | 105 | } |
131 | | |
132 | | void set_index_result_for_expr(const VExpr* expr, |
133 | 39 | segment_v2::InvertedIndexResultBitmap bitmap) { |
134 | 39 | _index_result_bitmap[expr] = std::move(bitmap); |
135 | 39 | } |
136 | | |
137 | | std::unordered_map<const VExpr*, segment_v2::InvertedIndexResultBitmap>& |
138 | 8 | get_index_result_bitmap() { |
139 | 8 | return _index_result_bitmap; |
140 | 8 | } |
141 | | |
142 | 28 | std::unordered_map<const VExpr*, ColumnPtr>& get_index_result_column() { |
143 | 28 | return _index_result_column; |
144 | 28 | } |
145 | | |
146 | 37 | const segment_v2::InvertedIndexResultBitmap* get_index_result_for_expr(const VExpr* expr) { |
147 | 37 | auto iter = _index_result_bitmap.find(expr); |
148 | 37 | if (iter == _index_result_bitmap.end()) { |
149 | 1 | return nullptr; |
150 | 1 | } |
151 | 36 | return &iter->second; |
152 | 37 | } |
153 | | |
154 | | // Dedicated entry point for approximate (superset) index results, kept strictly apart from |
155 | | // the exact result map above. |
156 | | void set_approx_index_result_for_expr(const VExpr* expr, |
157 | 24 | segment_v2::InvertedIndexResultBitmap bitmap) { |
158 | 24 | _approx_index_result_bitmap[expr] = std::move(bitmap); |
159 | 24 | } |
160 | | |
161 | | const segment_v2::InvertedIndexResultBitmap* get_approx_index_result_for_expr( |
162 | 53 | const VExpr* expr) const { |
163 | 53 | auto iter = _approx_index_result_bitmap.find(expr); |
164 | 53 | if (iter == _approx_index_result_bitmap.end()) { |
165 | 30 | return nullptr; |
166 | 30 | } |
167 | 23 | return &iter->second; |
168 | 53 | } |
169 | | |
170 | 1 | void set_index_result_column_for_expr(const VExpr* expr, ColumnPtr column) { |
171 | 1 | _index_result_column[expr] = std::move(column); |
172 | 1 | } |
173 | | |
174 | 16 | void set_true_for_index_status(const VExpr* expr, int column_index) { |
175 | 16 | if (column_index < 0 || column_index >= _col_ids.size()) { |
176 | 0 | return; |
177 | 0 | } |
178 | 16 | const auto& column_id = _col_ids[column_index]; |
179 | 16 | if (_expr_index_status.contains(column_id)) { |
180 | 16 | if (_expr_index_status[column_id].contains(expr)) { |
181 | 16 | _expr_index_status[column_id][expr] = true; |
182 | 16 | } |
183 | 16 | } |
184 | 16 | } |
185 | | |
186 | 0 | ScoreRuntimeSPtr get_score_runtime() const { return _score_runtime; } |
187 | | |
188 | 0 | void set_analyzer_ctx_for_expr(const VExpr* expr, InvertedIndexAnalyzerCtxSPtr analyzer_ctx) { |
189 | 0 | if (expr == nullptr || analyzer_ctx == nullptr) { |
190 | 0 | return; |
191 | 0 | } |
192 | 0 | _expr_analyzer_ctx[expr] = std::move(analyzer_ctx); |
193 | 0 | } |
194 | | |
195 | 30 | const InvertedIndexAnalyzerCtx* get_analyzer_ctx_for_expr(const VExpr* expr) const { |
196 | 30 | auto iter = _expr_analyzer_ctx.find(expr); |
197 | 30 | if (iter == _expr_analyzer_ctx.end()) { |
198 | 30 | return nullptr; |
199 | 30 | } |
200 | 0 | return iter->second.get(); |
201 | 30 | } |
202 | | |
203 | 4.41k | void set_index_query_context(segment_v2::IndexQueryContextPtr index_query_context) { |
204 | 4.41k | _index_query_context = index_query_context; |
205 | 4.41k | } |
206 | | |
207 | 8 | const segment_v2::IndexQueryContextPtr& get_index_query_context() const { |
208 | 8 | return _index_query_context; |
209 | 8 | } |
210 | | |
211 | 0 | segment_v2::Segment* get_segment() const { return _segment; } |
212 | | |
213 | 0 | const segment_v2::ColumnIteratorOptions& get_column_iter_opts() const { |
214 | 0 | return _column_iter_opts; |
215 | 0 | } |
216 | | |
217 | | private: |
218 | | // A reference to a vector of column IDs for the current expression's output columns. |
219 | | const std::vector<ColumnId>& _col_ids; |
220 | | |
221 | | // A reference to a vector of unique pointers to index iterators. |
222 | | const std::vector<std::unique_ptr<segment_v2::IndexIterator>>& _index_iterators; |
223 | | |
224 | | // A reference to a vector of storage name and type pairs related to schema. |
225 | | const std::vector<IndexFieldNameAndTypePair>& _storage_name_and_type; |
226 | | |
227 | | // A map of expressions to their corresponding inverted index result bitmaps. |
228 | | std::unordered_map<const VExpr*, segment_v2::InvertedIndexResultBitmap> _index_result_bitmap; |
229 | | |
230 | | // A map of expressions to their corresponding result columns. |
231 | | std::unordered_map<const VExpr*, ColumnPtr> _index_result_column; |
232 | | |
233 | | // Approximate (superset) index results: rows outside the bitmap certainly do not match, but |
234 | | // rows inside it may not match either, so it may only be used to prune candidate rows and |
235 | | // the expression must stay in the push-down list to re-verify them. Three invariants: |
236 | | // (a) never write into _index_result_bitmap / _index_result_column -- VExpr::fast_execute |
237 | | // would then pass the candidate bitmap off as the function result, and |
238 | | // _output_index_result_column would materialize it as a result column; |
239 | | // (b) never call set_true_for_index_status -- the column would then be judged |
240 | | // need_read_data=false and there would be no column left to read during re-verification; |
241 | | // (c) intersecting with _row_bitmap is allowed only when the expression happens to be the |
242 | | // root of the VExprContext (a top-level AND context); wrapped in NOT/OR, VCompoundPred |
243 | | // never sees this map, so it simply does not apply. |
244 | | std::unordered_map<const VExpr*, segment_v2::InvertedIndexResultBitmap> |
245 | | _approx_index_result_bitmap; |
246 | | |
247 | | // Per-expression analyzer context for inverted index evaluation. |
248 | | std::unordered_map<const VExpr*, InvertedIndexAnalyzerCtxSPtr> _expr_analyzer_ctx; |
249 | | |
250 | | // A reference to a map of common expressions to their inverted index evaluation status. |
251 | | std::unordered_map<ColumnId, std::unordered_map<const VExpr*, bool>>& _expr_index_status; |
252 | | |
253 | | ScoreRuntimeSPtr _score_runtime; |
254 | | |
255 | | segment_v2::Segment* _segment = nullptr; // Ref |
256 | | segment_v2::ColumnIteratorOptions _column_iter_opts; |
257 | | SchemaSPtr _read_schema; |
258 | | segment_v2::IndexQueryContextPtr _index_query_context; |
259 | | }; |
260 | | |
261 | | class VExprContext { |
262 | | ENABLE_FACTORY_CREATOR(VExprContext); |
263 | | |
264 | | public: |
265 | | VExprContext(VExprSPtr expr); |
266 | | ~VExprContext(); |
267 | | [[nodiscard]] Status prepare(RuntimeState* state, const RowDescriptor& row_desc); |
268 | | [[nodiscard]] Status open(RuntimeState* state); |
269 | | [[nodiscard]] Status clone(RuntimeState* state, VExprContextSPtr& new_ctx); |
270 | | [[nodiscard]] Status execute(Block* block, int* result_column_id); |
271 | | [[nodiscard]] Status execute(const Block* block, ColumnPtr& result_column); |
272 | | [[nodiscard]] Status execute(const Block* block, ColumnWithTypeAndName& result_data); |
273 | | [[nodiscard]] DataTypePtr execute_type(const Block* block); |
274 | | [[nodiscard]] const std::string& expr_name() const; |
275 | | [[nodiscard]] bool is_blockable() const; |
276 | | |
277 | | [[nodiscard]] Status execute_const_expr(ColumnWithTypeAndName& result); |
278 | | |
279 | | double execute_cost() const; |
280 | | |
281 | 730k | VExprSPtr root() { return _root; } |
282 | 0 | void set_root(const VExprSPtr& expr) { _root = expr; } |
283 | 125 | void set_index_context(std::shared_ptr<IndexExecContext> index_context) { |
284 | 125 | _index_context = std::move(index_context); |
285 | 125 | } |
286 | | |
287 | 447 | std::shared_ptr<IndexExecContext> get_index_context() const { return _index_context; } |
288 | | |
289 | | LambdaExecutionContext& lambda_execution_context(); |
290 | | |
291 | | /// Creates a FunctionContext, and returns the index that's passed to fn_context() to |
292 | | /// retrieve the created context. Exprs that need a FunctionContext should call this in |
293 | | /// Prepare() and save the returned index. 'varargs_buffer_size', if specified, is the |
294 | | /// size of the varargs buffer in the created FunctionContext (see udf-internal.h). |
295 | | int register_function_context(RuntimeState* state, const DataTypePtr& return_type, |
296 | | const std::vector<DataTypePtr>& arg_types); |
297 | | |
298 | | /// Retrieves a registered FunctionContext. 'i' is the index returned by the call to |
299 | | /// register_function_context(). This should only be called by VExprs. |
300 | 1.80k | FunctionContext* fn_context(int i) { |
301 | 1.80k | if (i < 0 || i >= _fn_contexts.size()) { |
302 | 2 | throw Exception(ErrorCode::INTERNAL_ERROR, |
303 | 2 | "fn_context index invalid, index={}, _fn_contexts.size()={}", i, |
304 | 2 | _fn_contexts.size()); |
305 | 2 | } |
306 | 1.80k | return _fn_contexts[i].get(); |
307 | 1.80k | } |
308 | | |
309 | 2 | void set_auto_partition_boundary_context() { |
310 | 2 | for (auto& fn_context : _fn_contexts) { |
311 | 0 | fn_context->set_auto_partition_boundary_context(); |
312 | 0 | } |
313 | 2 | } |
314 | | |
315 | | // execute expr with inverted index which column a, b has inverted indexes |
316 | | // but some situation although column b has indexes, but apply index is not useful, we should |
317 | | // skip this expr, just do not apply index anymore. |
318 | | [[nodiscard]] Status evaluate_inverted_index(uint32_t segment_num_rows); |
319 | | |
320 | | // The one expression whose approximate (superset) index result this caller will read back, |
321 | | // or null when it reads none. SegmentIterator names the root of a pushed-down conjunct, |
322 | | // because _apply_approx_index_result looks the result up by exactly that pointer; its |
323 | | // virtual column loop names nothing, because it only materializes exact results. For any |
324 | | // other expression -- an operand of a compound predicate, a nested child push-down -- the |
325 | | // result would be stored under its own pointer and never read again, so a function that can |
326 | | // only answer approximately skips the evaluation instead of paying for the index reads. |
327 | 77 | void set_approx_index_result_consumer(const VExpr* expr) { |
328 | 77 | _approx_index_result_consumer = expr; |
329 | 77 | } |
330 | 24 | const VExpr* approx_index_result_consumer() const { return _approx_index_result_consumer; } |
331 | | |
332 | | [[nodiscard]] static ZoneMapFilterResult evaluate_zonemap_filter( |
333 | | const VExprContextSPtrs& conjuncts, const ZoneMapEvalContext& ctx); |
334 | | [[nodiscard]] static ZoneMapFilterResult evaluate_dictionary_filter( |
335 | | const VExprContextSPtrs& conjuncts, const DictionaryEvalContext& ctx); |
336 | | [[nodiscard]] static ZoneMapFilterResult evaluate_bloom_filter( |
337 | | const VExprContextSPtrs& conjuncts, const BloomFilterEvalContext& ctx); |
338 | | |
339 | | bool all_expr_inverted_index_evaluated(); |
340 | | |
341 | | Status execute_filter(const Block* block, uint8_t* __restrict result_filter_data, size_t rows, |
342 | | bool accept_null, bool* can_filter_all); |
343 | | |
344 | | [[nodiscard]] static Status filter_block(VExprContext* vexpr_ctx, Block* block); |
345 | | |
346 | | [[nodiscard]] static Status filter_block(const VExprContextSPtrs& expr_contexts, Block* block, |
347 | | size_t column_to_keep); |
348 | | |
349 | | [[nodiscard]] static Status execute_conjuncts(const VExprContextSPtrs& ctxs, |
350 | | const std::vector<IColumn::Filter*>* filters, |
351 | | bool accept_null, const Block* block, |
352 | | IColumn::Filter* result_filter, |
353 | | bool* can_filter_all); |
354 | | |
355 | | [[nodiscard]] static Status execute_conjuncts(const VExprContextSPtrs& conjuncts, |
356 | | const Block* block, ColumnUInt8& null_map, |
357 | | IColumn::Filter& result_filter); |
358 | | |
359 | | static Status execute_conjuncts(const VExprContextSPtrs& ctxs, |
360 | | const std::vector<IColumn::Filter*>* filters, Block* block, |
361 | | IColumn::Filter* result_filter, bool* can_filter_all); |
362 | | |
363 | | [[nodiscard]] static Status execute_conjuncts_and_filter_block( |
364 | | const VExprContextSPtrs& ctxs, Block* block, std::vector<uint32_t>& columns_to_filter, |
365 | | int column_to_keep); |
366 | | |
367 | | static Status execute_conjuncts_and_filter_block(const VExprContextSPtrs& ctxs, Block* block, |
368 | | std::vector<uint32_t>& columns_to_filter, |
369 | | int column_to_keep, IColumn::Filter& filter); |
370 | | |
371 | | [[nodiscard]] static Status get_output_block_after_execute_exprs(const VExprContextSPtrs&, |
372 | | const Block&, Block*, |
373 | | bool do_projection = false); |
374 | | |
375 | 7 | int get_last_result_column_id() const { |
376 | 7 | DCHECK(_last_result_column_id != -1); |
377 | 7 | return _last_result_column_id; |
378 | 7 | } |
379 | | |
380 | 63 | RuntimeFilterSelectivity& get_runtime_filter_selectivity() { |
381 | 63 | if (!_rf_selectivity) { |
382 | 0 | throw Exception(ErrorCode::INTERNAL_ERROR, "RuntimeFilterSelectivity is null"); |
383 | 0 | } |
384 | 63 | return *_rf_selectivity; |
385 | 63 | } |
386 | | |
387 | 0 | FunctionContext::FunctionStateScope get_function_state_scope() const { |
388 | 0 | return _is_clone ? FunctionContext::THREAD_LOCAL : FunctionContext::FRAGMENT_LOCAL; |
389 | 0 | } |
390 | | |
391 | | void clone_fn_contexts(VExprContext* other); |
392 | | |
393 | | VExprContext& operator=(const VExprContext& other) = delete; |
394 | | |
395 | | VExprContext& operator=(VExprContext&& other) = delete; |
396 | | |
397 | 145 | [[nodiscard]] static size_t get_memory_usage(const VExprContextSPtrs& contexts) { |
398 | 145 | size_t usage = 0; |
399 | 145 | std::for_each(contexts.cbegin(), contexts.cend(), |
400 | 145 | [&usage](auto&& context) { usage += context->_memory_usage; }); |
401 | 145 | return usage; |
402 | 145 | } |
403 | | |
404 | 0 | [[nodiscard]] size_t get_memory_usage() const { return _memory_usage; } |
405 | | |
406 | | void prepare_ann_range_search(const doris::VectorSearchUserParams& params); |
407 | | |
408 | | Status evaluate_ann_range_search( |
409 | | const std::vector<std::unique_ptr<segment_v2::IndexIterator>>& cid_to_index_iterators, |
410 | | const std::vector<ColumnId>& idx_to_cid, |
411 | | const std::vector<std::unique_ptr<segment_v2::ColumnIterator>>& column_iterators, |
412 | | const std::unordered_map<VExprContext*, std::unordered_map<ColumnId, VExpr*>>& |
413 | | common_expr_to_slotref_map, |
414 | | size_t rows_of_segment, roaring::Roaring& row_bitmap, |
415 | | segment_v2::AnnIndexStats& ann_index_stats, bool* ann_range_search_executed); |
416 | | |
417 | | uint64_t get_digest(uint64_t seed) const; |
418 | | |
419 | | private: |
420 | | // Close method is called in vexpr context dector, not need call expicility |
421 | | void close(); |
422 | | |
423 | | static void _reset_memory_usage(const VExprContextSPtrs& contexts); |
424 | | |
425 | | friend class VExpr; |
426 | | |
427 | | /// The expr tree this context is for. |
428 | | VExprSPtr _root; |
429 | | |
430 | | /// True if this context came from a Clone() call. Used to manage FunctionStateScope. |
431 | | bool _is_clone = false; |
432 | | |
433 | | /// Variables keeping track of current state. |
434 | | bool _prepared = false; |
435 | | bool _opened = false; |
436 | | |
437 | | /// See set_approx_index_result_consumer. Null by default, so a caller that does not read the |
438 | | /// approximate map never pays for the index reads behind one. |
439 | | const VExpr* _approx_index_result_consumer = nullptr; |
440 | | |
441 | | /// FunctionContexts for each registered expression. The FunctionContexts are created |
442 | | /// and owned by this VExprContext. |
443 | | std::vector<std::unique_ptr<FunctionContext>> _fn_contexts; |
444 | | |
445 | | int _last_result_column_id = -1; |
446 | | |
447 | | /// The depth of expression-tree. |
448 | | int _depth_num = 0; |
449 | | |
450 | | std::shared_ptr<IndexExecContext> _index_context; |
451 | | size_t _memory_usage = 0; |
452 | | |
453 | | segment_v2::AnnRangeSearchRuntime _ann_range_search_runtime; |
454 | | bool _suitable_for_ann_index = true; |
455 | | |
456 | | std::unique_ptr<LambdaExecutionContext> _lambda_execution_context; |
457 | | |
458 | | std::unique_ptr<RuntimeFilterSelectivity> _rf_selectivity = |
459 | | std::make_unique<RuntimeFilterSelectivity>(); |
460 | | }; |
461 | | } // namespace doris |