Coverage Report

Created: 2026-10-13 23:22

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