Coverage Report

Created: 2026-08-17 23:49

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