Coverage Report

Created: 2026-10-17 14:15

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 <gen_cpp/parquet_types.h>
19
20
#include <cstddef>
21
#include <cstdint>
22
#include <map>
23
#include <memory>
24
#include <string>
25
#include <unordered_map>
26
#include <unordered_set>
27
#include <vector>
28
29
#include "common/status.h"
30
#include "core/field.h"
31
#include "core/string_ref.h"
32
#include "exprs/vexpr_fwd.h"
33
#include "format_v2/file_reader.h"
34
#include "format_v2/parquet/parquet_profile.h"
35
#include "format_v2/parquet/selection_vector.h"
36
37
namespace cctz {
38
class time_zone;
39
} // namespace cctz
40
41
namespace doris {
42
class RuntimeState;
43
namespace segment_v2 {
44
class BloomFilter;
45
struct ZoneMap;
46
} // namespace segment_v2
47
} // namespace doris
48
49
namespace doris::format::parquet {
50
51
struct ParquetColumnSchema;
52
struct ParquetFileContext;
53
struct ParquetTypeDescriptor;
54
55
namespace detail {
56
Status validate_native_bloom_filter_layout(int64_t offset, uint32_t header_size,
57
                                           int64_t payload_size, int64_t declared_length,
58
                                           size_t file_size);
59
bool can_use_native_footer_min_max(const ParquetTypeDescriptor& type_descriptor,
60
                                   const tparquet::Statistics& statistics,
61
                                   bool has_type_defined_order);
62
bool has_supported_type_defined_order(const tparquet::FileMetaData& metadata, int leaf_column_id);
63
tparquet::Statistics sanitize_native_footer_statistics(const ParquetTypeDescriptor& type_descriptor,
64
                                                       const tparquet::Statistics& statistics,
65
                                                       bool has_type_defined_order);
66
} // namespace detail
67
68
// ============================================================================
69
// ============================================================================
70
71
struct ParquetPruningStats {
72
    int64_t total_row_groups = 0;                    // total row groups in the file
73
    int64_t selected_row_groups = 0;                 // row groups selected after pruning
74
    int64_t filtered_row_groups_by_statistics = 0;   // row groups pruned by ZoneMap statistics
75
    int64_t filtered_row_groups_by_dictionary = 0;   // row groups pruned by dictionary
76
    int64_t filtered_row_groups_by_bloom_filter = 0; // row groups pruned by bloom filter
77
    int64_t filtered_row_groups_by_page_index = 0;   // row groups fully pruned by page index
78
    int64_t filtered_group_rows = 0;                 // rows in pruned row groups
79
    int64_t filtered_bytes = 0;                      // requested bytes in pruned row groups
80
    int64_t filtered_page_rows = 0;                  // rows pruned by page index
81
    int64_t selected_row_ranges = 0;                 // selected row range count
82
    int64_t page_index_read_calls = 0;               // Page Index read count
83
    int64_t bloom_filter_read_time = 0;              // Bloom filter read time (ns)
84
    int64_t bloom_filter_probe_attempts = 0;         // unique leaf Bloom probes attempted
85
    int64_t bloom_filter_probe_successes = 0;        // usable Bloom payloads decoded
86
    int64_t bloom_filter_conservative_fallbacks = 0; // unavailable/unreadable Blooms retained
87
    int64_t bloom_filter_corrupt_rejections = 0;     // malformed Blooms rejected conservatively
88
    int64_t row_group_filter_time = 0;               // row-group pruning time (ns)
89
    int64_t page_index_filter_time = 0;              // page-index pruning time (ns)
90
    int64_t read_page_index_time = 0;                // page-index read time (ns)
91
    int64_t parse_page_index_time = 0;               // lazy page-index materialization time (ns)
92
    int64_t expr_zonemap_unusable_evals = 0;         // VExpr ZoneMap unusable evaluations
93
    int64_t in_zonemap_point_check_count = 0;        // VExpr IN ZoneMap point checks
94
    int64_t in_zonemap_range_only_count = 0;         // VExpr IN ZoneMap range-only checks
95
};
96
97
struct ParquetColumnStatistics {
98
    Field min_value;             // column minimum value converted to Doris type
99
    Field max_value;             // column maximum value
100
    bool has_null = false;       // whether NULL exists
101
    bool has_not_null = false;   // whether non-NULL values exist
102
    bool has_null_count = false; // whether null_count is valid
103
    bool has_min_max = false;    // whether min/max is valid after conversion
104
105
45
    bool has_any_statistics() const { return has_null_count || has_min_max; }
106
};
107
108
struct NativeParquetPageIndex {
109
    tparquet::ColumnIndex column_index;
110
    tparquet::OffsetIndex offset_index;
111
};
112
113
enum class ParquetMetadataProbeMode {
114
    ALL,
115
    FOOTER_ONLY,
116
    EXPENSIVE_ONLY,
117
};
118
119
bool can_use_parquet_page_index(const format::FileScanRequest& request,
120
                                const RuntimeState* runtime_state);
121
122
// ============================================================================
123
// ============================================================================
124
//     VExpr ZoneMap(TransformColumnStatistics + evaluate_zonemap_filter)
125
//     -> page-index ZoneMap(evaluate_zonemap_filter)
126
//     dictionary(read_dictionary_words + evaluate_dictionary_filter)
127
//     -> bloom filter(evaluate_bloom_filter)
128
// ============================================================================
129
struct ParquetStatisticsUtils {
130
    static std::shared_ptr<segment_v2::ZoneMap> MakeZoneMap(
131
            const ParquetColumnStatistics& statistics);
132
133
    static ParquetColumnStatistics TransformColumnStatistics(
134
            const ParquetColumnSchema& column_schema, const tparquet::Statistics* statistics,
135
            int64_t column_value_count, const cctz::time_zone* timezone = nullptr,
136
            bool null_count_trusted = true);
137
138
    static bool NativeBloomFilterExcludes(const ParquetColumnSchema& column_schema, int slot_index,
139
                                          const VExprContextSPtrs& conjuncts,
140
                                          const segment_v2::BloomFilter& bloom_filter);
141
};
142
143
Status select_row_groups_by_metadata(
144
        const tparquet::FileMetaData& metadata,
145
        const std::vector<std::unique_ptr<ParquetColumnSchema>>& file_schema,
146
        const format::FileScanRequest& request, const std::vector<int>* candidate_row_groups,
147
        std::vector<int>* selected_row_groups, bool enable_bloom_filter,
148
        ParquetPruningStats* pruning_stats, const cctz::time_zone* timezone = nullptr,
149
        const RuntimeState* runtime_state = nullptr, ParquetFileContext* file_context = nullptr,
150
        const ParquetColumnReaderProfile& column_reader_profile = {},
151
        ParquetMetadataProbeMode probe_mode = ParquetMetadataProbeMode::ALL,
152
        const std::unordered_set<int>* requested_leaf_ids = nullptr);
153
154
Status select_row_group_ranges_by_native_page_index(
155
        const tparquet::FileMetaData& metadata, const tparquet::RowGroup& row_group,
156
        const std::unordered_map<int, NativeParquetPageIndex>& page_indexes,
157
        const std::vector<std::unique_ptr<ParquetColumnSchema>>& file_schema,
158
        const format::FileScanRequest& request, int64_t row_group_rows,
159
        std::vector<RowRange>* selected_ranges, std::map<int, ParquetPageSkipPlan>* page_skip_plans,
160
        ParquetPruningStats* pruning_stats, const cctz::time_zone* timezone = nullptr,
161
        const RuntimeState* runtime_state = nullptr);
162
163
} // namespace doris::format::parquet