Coverage Report

Created: 2026-08-11 00:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 <unordered_map>
26
#include <utility>
27
#include <vector>
28
29
#include "common/factory_creator.h"
30
#include "common/status.h"
31
#include "core/block/block.h"
32
#include "core/block/column_with_type_and_name.h"
33
#include "core/column/column.h"
34
#include "exec/runtime_filter/runtime_filter_selectivity.h"
35
#include "exprs/expr_zonemap_filter.h"
36
#include "exprs/function_context.h"
37
#include "exprs/vexpr_fwd.h"
38
#include "runtime/runtime_state.h"
39
#include "storage/index/ann/ann_range_search_runtime.h"
40
#include "storage/index/ann/ann_search_params.h"
41
#include "storage/index/inverted/inverted_index_reader.h"
42
#include "storage/index/zone_map/zonemap_filter_result.h"
43
#include "storage/segment/column_reader.h"
44
45
namespace doris {
46
class RowDescriptor;
47
class RuntimeState;
48
class ZoneMapEvalContext;
49
} // namespace doris
50
51
namespace doris::segment_v2 {
52
class Segment;
53
class ColumnIterator;
54
class Segment;
55
} // namespace doris::segment_v2
56
57
namespace doris {
58
59
class ScoreRuntime;
60
using ScoreRuntimeSPtr = std::shared_ptr<ScoreRuntime>;
61
62
class IndexExecContext {
63
public:
64
    IndexExecContext(const std::vector<ColumnId>& col_ids,
65
                     const std::vector<std::unique_ptr<segment_v2::IndexIterator>>& index_iterators,
66
                     const std::vector<IndexFieldNameAndTypePair>& storage_name_and_type_vec,
67
                     std::unordered_map<ColumnId, std::unordered_map<const VExpr*, bool>>&
68
                             common_expr_index_status,
69
                     ScoreRuntimeSPtr score_runtime, segment_v2::Segment* segment = nullptr,
70
                     const segment_v2::ColumnIteratorOptions& column_iter_opts = {})
71
3.07k
            : _col_ids(col_ids),
72
3.07k
              _index_iterators(index_iterators),
73
3.07k
              _storage_name_and_type(storage_name_and_type_vec),
74
3.07k
              _expr_index_status(common_expr_index_status),
75
3.07k
              _score_runtime(std::move(score_runtime)),
76
3.07k
              _segment(segment),
77
3.07k
              _column_iter_opts(column_iter_opts) {}
78
79
22
    segment_v2::IndexIterator* get_inverted_index_iterator_by_column_id(int column_index) const {
80
22
        if (column_index < 0 || column_index >= _col_ids.size()) {
81
0
            return nullptr;
82
0
        }
83
22
        const auto& column_id = _col_ids[column_index];
84
22
        if (column_id >= _index_iterators.size()) {
85
0
            return nullptr;
86
0
        }
87
22
        if (!_index_iterators[column_id]) {
88
6
            return nullptr;
89
6
        }
90
16
        return _index_iterators[column_id].get();
91
22
    }
92
93
    const IndexFieldNameAndTypePair* get_storage_name_and_type_by_column_id(
94
16
            int column_index) const {
95
16
        if (column_index < 0 || column_index >= _col_ids.size()) {
96
0
            return nullptr;
97
0
        }
98
16
        const auto& column_id = _col_ids[column_index];
99
16
        if (column_id >= _storage_name_and_type.size()) {
100
1
            return nullptr;
101
1
        }
102
15
        return &_storage_name_and_type[column_id];
103
16
    }
104
105
0
    bool get_column_id(int column_index, ColumnId* column_id) const {
106
0
        if (column_id == nullptr) {
107
0
            return false;
108
0
        }
109
0
        if (column_index < 0 || column_index >= _col_ids.size()) {
110
0
            return false;
111
0
        }
112
0
        *column_id = _col_ids[column_index];
113
0
        return true;
114
0
    }
115
116
0
    segment_v2::Segment* segment() const { return _segment; }
117
118
0
    const segment_v2::ColumnIteratorOptions& column_iter_opts() const { return _column_iter_opts; }
119
120
21
    bool has_index_result_for_expr(const VExpr* expr) const {
121
21
        return _index_result_bitmap.contains(expr);
122
21
    }
123
124
    void set_index_result_for_expr(const VExpr* expr,
125
20
                                   segment_v2::InvertedIndexResultBitmap bitmap) {
126
20
        _index_result_bitmap[expr] = std::move(bitmap);
127
20
    }
128
129
    std::unordered_map<const VExpr*, segment_v2::InvertedIndexResultBitmap>&
130
6
    get_index_result_bitmap() {
131
6
        return _index_result_bitmap;
132
6
    }
133
134
8
    std::unordered_map<const VExpr*, ColumnPtr>& get_index_result_column() {
135
8
        return _index_result_column;
136
8
    }
137
138
16
    const segment_v2::InvertedIndexResultBitmap* get_index_result_for_expr(const VExpr* expr) {
139
16
        auto iter = _index_result_bitmap.find(expr);
140
16
        if (iter == _index_result_bitmap.end()) {
141
0
            return nullptr;
142
0
        }
143
16
        return &iter->second;
144
16
    }
145
146
1
    void set_index_result_column_for_expr(const VExpr* expr, ColumnPtr column) {
147
1
        _index_result_column[expr] = std::move(column);
148
1
    }
149
150
15
    void set_true_for_index_status(const VExpr* expr, int column_index) {
151
15
        if (column_index < 0 || column_index >= _col_ids.size()) {
152
0
            return;
153
0
        }
154
15
        const auto& column_id = _col_ids[column_index];
155
15
        if (_expr_index_status.contains(column_id)) {
156
15
            if (_expr_index_status[column_id].contains(expr)) {
157
15
                _expr_index_status[column_id][expr] = true;
158
15
            }
159
15
        }
160
15
    }
161
162
0
    ScoreRuntimeSPtr get_score_runtime() const { return _score_runtime; }
163
164
0
    void set_analyzer_ctx_for_expr(const VExpr* expr, InvertedIndexAnalyzerCtxSPtr analyzer_ctx) {
165
0
        if (expr == nullptr || analyzer_ctx == nullptr) {
166
0
            return;
167
0
        }
168
0
        _expr_analyzer_ctx[expr] = std::move(analyzer_ctx);
169
0
    }
170
171
14
    const InvertedIndexAnalyzerCtx* get_analyzer_ctx_for_expr(const VExpr* expr) const {
172
14
        auto iter = _expr_analyzer_ctx.find(expr);
173
14
        if (iter == _expr_analyzer_ctx.end()) {
174
14
            return nullptr;
175
14
        }
176
0
        return iter->second.get();
177
14
    }
178
179
3.04k
    void set_index_query_context(segment_v2::IndexQueryContextPtr index_query_context) {
180
3.04k
        _index_query_context = index_query_context;
181
3.04k
    }
182
183
5
    const segment_v2::IndexQueryContextPtr& get_index_query_context() const {
184
5
        return _index_query_context;
185
5
    }
186
187
0
    segment_v2::Segment* get_segment() const { return _segment; }
188
189
0
    const segment_v2::ColumnIteratorOptions& get_column_iter_opts() const {
190
0
        return _column_iter_opts;
191
0
    }
192
193
private:
194
    // A reference to a vector of column IDs for the current expression's output columns.
195
    const std::vector<ColumnId>& _col_ids;
196
197
    // A reference to a vector of unique pointers to index iterators.
198
    const std::vector<std::unique_ptr<segment_v2::IndexIterator>>& _index_iterators;
199
200
    // A reference to a vector of storage name and type pairs related to schema.
201
    const std::vector<IndexFieldNameAndTypePair>& _storage_name_and_type;
202
203
    // A map of expressions to their corresponding inverted index result bitmaps.
204
    std::unordered_map<const VExpr*, segment_v2::InvertedIndexResultBitmap> _index_result_bitmap;
205
206
    // A map of expressions to their corresponding result columns.
207
    std::unordered_map<const VExpr*, ColumnPtr> _index_result_column;
208
209
    // Per-expression analyzer context for inverted index evaluation.
210
    std::unordered_map<const VExpr*, InvertedIndexAnalyzerCtxSPtr> _expr_analyzer_ctx;
211
212
    // A reference to a map of common expressions to their inverted index evaluation status.
213
    std::unordered_map<ColumnId, std::unordered_map<const VExpr*, bool>>& _expr_index_status;
214
215
    ScoreRuntimeSPtr _score_runtime;
216
217
    segment_v2::Segment* _segment = nullptr; // Ref
218
    segment_v2::ColumnIteratorOptions _column_iter_opts;
219
    segment_v2::IndexQueryContextPtr _index_query_context;
220
};
221
222
class VExprContext {
223
    ENABLE_FACTORY_CREATOR(VExprContext);
224
225
public:
226
656k
    VExprContext(VExprSPtr expr) : _root(std::move(expr)) {}
227
    ~VExprContext();
228
    [[nodiscard]] Status prepare(RuntimeState* state, const RowDescriptor& row_desc);
229
    [[nodiscard]] Status open(RuntimeState* state);
230
    [[nodiscard]] Status clone(RuntimeState* state, VExprContextSPtr& new_ctx);
231
    [[nodiscard]] Status execute(Block* block, int* result_column_id);
232
    [[nodiscard]] Status execute(const Block* block, ColumnPtr& result_column);
233
    [[nodiscard]] Status execute(const Block* block, ColumnWithTypeAndName& result_data);
234
    [[nodiscard]] DataTypePtr execute_type(const Block* block);
235
    [[nodiscard]] const std::string& expr_name() const;
236
    [[nodiscard]] bool is_blockable() const;
237
238
    [[nodiscard]] Status execute_const_expr(ColumnWithTypeAndName& result);
239
240
    double execute_cost() const;
241
242
728k
    VExprSPtr root() { return _root; }
243
0
    void set_root(const VExprSPtr& expr) { _root = expr; }
244
47
    void set_index_context(std::shared_ptr<IndexExecContext> index_context) {
245
47
        _index_context = std::move(index_context);
246
47
    }
247
248
246
    std::shared_ptr<IndexExecContext> get_index_context() const { return _index_context; }
249
250
    /// Creates a FunctionContext, and returns the index that's passed to fn_context() to
251
    /// retrieve the created context. Exprs that need a FunctionContext should call this in
252
    /// Prepare() and save the returned index. 'varargs_buffer_size', if specified, is the
253
    /// size of the varargs buffer in the created FunctionContext (see udf-internal.h).
254
    int register_function_context(RuntimeState* state, const DataTypePtr& return_type,
255
                                  const std::vector<DataTypePtr>& arg_types);
256
257
    /// Retrieves a registered FunctionContext. 'i' is the index returned by the call to
258
    /// register_function_context(). This should only be called by VExprs.
259
1.03k
    FunctionContext* fn_context(int i) {
260
1.03k
        if (i < 0 || i >= _fn_contexts.size()) {
261
2
            throw Exception(ErrorCode::INTERNAL_ERROR,
262
2
                            "fn_context index invalid, index={}, _fn_contexts.size()={}", i,
263
2
                            _fn_contexts.size());
264
2
        }
265
1.02k
        return _fn_contexts[i].get();
266
1.03k
    }
267
268
    // execute expr with inverted index which column a, b has inverted indexes
269
    //  but some situation although column b has indexes, but apply index is not useful, we should
270
    //  skip this expr, just do not apply index anymore.
271
    [[nodiscard]] Status evaluate_inverted_index(uint32_t segment_num_rows);
272
273
    [[nodiscard]] static ZoneMapFilterResult evaluate_zonemap_filter(
274
            const VExprContextSPtrs& conjuncts, const ZoneMapEvalContext& ctx);
275
    [[nodiscard]] static ZoneMapFilterResult evaluate_dictionary_filter(
276
            const VExprContextSPtrs& conjuncts, const DictionaryEvalContext& ctx);
277
    [[nodiscard]] static ZoneMapFilterResult evaluate_bloom_filter(
278
            const VExprContextSPtrs& conjuncts, const BloomFilterEvalContext& ctx);
279
280
    bool all_expr_inverted_index_evaluated();
281
282
    Status execute_filter(const Block* block, uint8_t* __restrict result_filter_data, size_t rows,
283
                          bool accept_null, bool* can_filter_all);
284
285
    [[nodiscard]] static Status filter_block(VExprContext* vexpr_ctx, Block* block);
286
287
    [[nodiscard]] static Status filter_block(const VExprContextSPtrs& expr_contexts, Block* block,
288
                                             size_t column_to_keep);
289
290
    [[nodiscard]] static Status execute_conjuncts(const VExprContextSPtrs& ctxs,
291
                                                  const std::vector<IColumn::Filter*>* filters,
292
                                                  bool accept_null, const Block* block,
293
                                                  IColumn::Filter* result_filter,
294
                                                  bool* can_filter_all);
295
296
    [[nodiscard]] static Status execute_conjuncts(const VExprContextSPtrs& conjuncts,
297
                                                  const Block* block, ColumnUInt8& null_map,
298
                                                  IColumn::Filter& result_filter);
299
300
    static Status execute_conjuncts(const VExprContextSPtrs& ctxs,
301
                                    const std::vector<IColumn::Filter*>* filters, Block* block,
302
                                    IColumn::Filter* result_filter, bool* can_filter_all);
303
304
    [[nodiscard]] static Status execute_conjuncts_and_filter_block(
305
            const VExprContextSPtrs& ctxs, Block* block, std::vector<uint32_t>& columns_to_filter,
306
            int column_to_keep);
307
308
    static Status execute_conjuncts_and_filter_block(const VExprContextSPtrs& ctxs, Block* block,
309
                                                     std::vector<uint32_t>& columns_to_filter,
310
                                                     int column_to_keep, IColumn::Filter& filter);
311
312
    [[nodiscard]] static Status get_output_block_after_execute_exprs(const VExprContextSPtrs&,
313
                                                                     const Block&, Block*,
314
                                                                     bool do_projection = false);
315
316
6
    int get_last_result_column_id() const {
317
6
        DCHECK(_last_result_column_id != -1);
318
6
        return _last_result_column_id;
319
6
    }
320
321
56
    RuntimeFilterSelectivity& get_runtime_filter_selectivity() {
322
56
        if (!_rf_selectivity) {
323
0
            throw Exception(ErrorCode::INTERNAL_ERROR, "RuntimeFilterSelectivity is null");
324
0
        }
325
56
        return *_rf_selectivity;
326
56
    }
327
328
0
    FunctionContext::FunctionStateScope get_function_state_scope() const {
329
0
        return _is_clone ? FunctionContext::THREAD_LOCAL : FunctionContext::FRAGMENT_LOCAL;
330
0
    }
331
332
    void clone_fn_contexts(VExprContext* other);
333
334
0
    VExprContext& operator=(const VExprContext& other) {
335
0
        if (this == &other) {
336
0
            return *this;
337
0
        }
338
0
339
0
        _root = other._root;
340
0
        _is_clone = other._is_clone;
341
0
        _prepared = other._prepared;
342
0
        _opened = other._opened;
343
0
344
0
        for (const auto& fn : other._fn_contexts) {
345
0
            _fn_contexts.emplace_back(fn->clone());
346
0
        }
347
0
348
0
        _last_result_column_id = other._last_result_column_id;
349
0
        _depth_num = other._depth_num;
350
0
        return *this;
351
0
    }
352
353
0
    VExprContext& operator=(VExprContext&& other) {
354
0
        _root = other._root;
355
0
        other._root = nullptr;
356
0
        _is_clone = other._is_clone;
357
0
        _prepared = other._prepared;
358
0
        _opened = other._opened;
359
0
        _fn_contexts = std::move(other._fn_contexts);
360
0
        _last_result_column_id = other._last_result_column_id;
361
0
        _depth_num = other._depth_num;
362
0
        return *this;
363
0
    }
364
365
136
    [[nodiscard]] static size_t get_memory_usage(const VExprContextSPtrs& contexts) {
366
136
        size_t usage = 0;
367
136
        std::for_each(contexts.cbegin(), contexts.cend(),
368
136
                      [&usage](auto&& context) { usage += context->_memory_usage; });
369
136
        return usage;
370
136
    }
371
372
0
    [[nodiscard]] size_t get_memory_usage() const { return _memory_usage; }
373
374
    void prepare_ann_range_search(const doris::VectorSearchUserParams& params);
375
376
    Status evaluate_ann_range_search(
377
            const std::vector<std::unique_ptr<segment_v2::IndexIterator>>& cid_to_index_iterators,
378
            const std::vector<ColumnId>& idx_to_cid,
379
            const std::vector<std::unique_ptr<segment_v2::ColumnIterator>>& column_iterators,
380
            const std::unordered_map<VExprContext*, std::unordered_map<ColumnId, VExpr*>>&
381
                    common_expr_to_slotref_map,
382
            size_t rows_of_segment, roaring::Roaring& row_bitmap,
383
            segment_v2::AnnIndexStats& ann_index_stats, bool* ann_range_search_executed);
384
385
    uint64_t get_digest(uint64_t seed) const;
386
387
private:
388
    // Close method is called in vexpr context dector, not need call expicility
389
    void close();
390
391
    static void _reset_memory_usage(const VExprContextSPtrs& contexts);
392
393
    friend class VExpr;
394
395
    /// The expr tree this context is for.
396
    VExprSPtr _root;
397
398
    /// True if this context came from a Clone() call. Used to manage FunctionStateScope.
399
    bool _is_clone = false;
400
401
    /// Variables keeping track of current state.
402
    bool _prepared = false;
403
    bool _opened = false;
404
405
    /// FunctionContexts for each registered expression. The FunctionContexts are created
406
    /// and owned by this VExprContext.
407
    std::vector<std::unique_ptr<FunctionContext>> _fn_contexts;
408
409
    int _last_result_column_id = -1;
410
411
    /// The depth of expression-tree.
412
    int _depth_num = 0;
413
414
    std::shared_ptr<IndexExecContext> _index_context;
415
    size_t _memory_usage = 0;
416
417
    segment_v2::AnnRangeSearchRuntime _ann_range_search_runtime;
418
    bool _suitable_for_ann_index = true;
419
420
    std::unique_ptr<RuntimeFilterSelectivity> _rf_selectivity =
421
            std::make_unique<RuntimeFilterSelectivity>();
422
};
423
} // namespace doris