Coverage Report

Created: 2026-07-11 19:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format_v2/parquet/parquet_statistics.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
//   http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing,
10
// software distributed under the License is distributed on an
11
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12
// KIND, either express or implied.  See the License for the
13
// specific language governing permissions and limitations
14
// under the License.
15
16
#pragma once
17
18
#include <cstdint>
19
#include <map>
20
#include <memory>
21
#include <string>
22
#include <vector>
23
24
#include "common/status.h"
25
#include "core/field.h"
26
#include "core/string_ref.h"
27
#include "exprs/vexpr_fwd.h"
28
#include "format_v2/file_reader.h"
29
#include "format_v2/parquet/selection_vector.h"
30
31
namespace parquet {
32
class BloomFilter;
33
class FileMetaData;
34
class ParquetFileReader;
35
class Statistics;
36
} // namespace parquet
37
38
namespace cctz {
39
class time_zone;
40
} // namespace cctz
41
42
namespace doris {
43
class RuntimeState;
44
} // namespace doris
45
46
namespace doris::format::parquet {
47
48
struct ParquetColumnSchema;
49
50
// ============================================================================
51
// ============================================================================
52
53
struct ParquetDictionaryWords {
54
    std::vector<std::string> values;
55
    std::vector<StringRef> refs;
56
57
47
    void clear() {
58
47
        values.clear();
59
47
        refs.clear();
60
47
    }
61
62
47
    void build_refs() {
63
47
        refs.clear();
64
47
        refs.reserve(values.size());
65
120
        for (const auto& value : values) {
66
120
            refs.emplace_back(value.data(), value.size());
67
120
        }
68
47
    }
69
};
70
71
// Reads the PLAIN dictionary page for BYTE_ARRAY/FIXED_LEN_BYTE_ARRAY columns and owns copied
72
// dictionary bytes in `values`. Both row-group pruning and row-level dictionary predicates use this
73
// helper so they agree on dictionary id -> Doris string value mapping.
74
bool read_dictionary_words(::parquet::ParquetFileReader* file_reader, int row_group_idx,
75
                           int leaf_column_id, const ParquetColumnSchema& column_schema,
76
                           ParquetDictionaryWords* dict_words);
77
78
std::vector<Field> dictionary_fields_from_words(const ParquetDictionaryWords& dict_words);
79
80
// ============================================================================
81
// ============================================================================
82
83
struct ParquetPruningStats {
84
    int64_t total_row_groups = 0;                    // total row groups in the file
85
    int64_t selected_row_groups = 0;                 // row groups selected after pruning
86
    int64_t filtered_row_groups_by_statistics = 0;   // row groups pruned by ZoneMap statistics
87
    int64_t filtered_row_groups_by_dictionary = 0;   // row groups pruned by dictionary
88
    int64_t filtered_row_groups_by_bloom_filter = 0; // row groups pruned by bloom filter
89
    int64_t filtered_row_groups_by_page_index = 0;   // row groups fully pruned by page index
90
    int64_t filtered_group_rows = 0;                 // rows in pruned row groups
91
    int64_t filtered_page_rows = 0;                  // rows pruned by page index
92
    int64_t selected_row_ranges = 0;                 // selected row range count
93
    int64_t page_index_read_calls = 0;               // Page Index read count
94
    int64_t bloom_filter_read_time = 0;              // Bloom filter read time (ns)
95
    int64_t row_group_filter_time = 0;               // row-group pruning time (ns)
96
    int64_t page_index_filter_time = 0;              // page-index pruning time (ns)
97
    int64_t read_page_index_time = 0;                // page-index read time (ns)
98
    int64_t expr_zonemap_unusable_evals = 0;         // VExpr ZoneMap unusable evaluations
99
    int64_t in_zonemap_point_check_count = 0;        // VExpr IN ZoneMap point checks
100
    int64_t in_zonemap_range_only_count = 0;         // VExpr IN ZoneMap range-only checks
101
};
102
103
struct ParquetColumnStatistics {
104
    Field min_value;             // column minimum value converted to Doris type
105
    Field max_value;             // column maximum value
106
    bool has_null = false;       // whether NULL exists
107
    bool has_not_null = false;   // whether non-NULL values exist
108
    bool has_null_count = false; // whether null_count is valid
109
    bool has_min_max = false;    // whether min/max is valid after conversion
110
111
0
    bool has_any_statistics() const { return has_null_count || has_min_max; }
112
};
113
114
// ============================================================================
115
// ============================================================================
116
//     VExpr ZoneMap(TransformColumnStatistics + evaluate_zonemap_filter)
117
//     -> page-index ZoneMap(evaluate_zonemap_filter)
118
//     dictionary(read_dictionary_words + evaluate_dictionary_filter)
119
//     -> bloom filter(evaluate_bloom_filter)
120
// ============================================================================
121
struct ParquetStatisticsUtils {
122
    static ParquetColumnStatistics TransformColumnStatistics(
123
            const ParquetColumnSchema& column_schema,
124
            const std::shared_ptr<::parquet::Statistics>& statistics,
125
            const cctz::time_zone* timezone = nullptr);
126
127
    static bool BloomFilterExcludes(const ParquetColumnSchema& column_schema, int slot_index,
128
                                    const VExprContextSPtrs& conjuncts,
129
                                    const ::parquet::BloomFilter& bloom_filter);
130
};
131
132
Status select_row_groups_by_metadata(
133
        const ::parquet::FileMetaData& metadata, ::parquet::ParquetFileReader* file_reader,
134
        const std::vector<std::unique_ptr<ParquetColumnSchema>>& file_schema,
135
        const format::FileScanRequest& request, const std::vector<int>* candidate_row_groups,
136
        std::vector<int>* selected_row_groups, bool enable_bloom_filter,
137
        ParquetPruningStats* pruning_stats, const cctz::time_zone* timezone = nullptr,
138
        const RuntimeState* runtime_state = nullptr);
139
140
Status select_row_group_ranges_by_page_index(
141
        ::parquet::ParquetFileReader* file_reader,
142
        const std::vector<std::unique_ptr<ParquetColumnSchema>>& file_schema,
143
        const format::FileScanRequest& request, int row_group_idx, int64_t row_group_rows,
144
        std::vector<RowRange>* selected_ranges, std::map<int, ParquetPageSkipPlan>* page_skip_plans,
145
        ParquetPruningStats* pruning_stats, const cctz::time_zone* timezone = nullptr,
146
        const RuntimeState* runtime_state = nullptr);
147
148
} // namespace doris::format::parquet