22
22
#include < gen_cpp/Metrics_types.h>
23
23
#include < gen_cpp/PaloInternalService_types.h>
24
24
#include < gen_cpp/PlanNodes_types.h>
25
+ #include < glog/logging.h>
25
26
26
27
#include < algorithm>
27
28
#include < boost/iterator/iterator_facade.hpp>
28
29
#include < iterator>
29
30
#include < map>
30
31
#include < ostream>
31
32
#include < tuple>
33
+ #include < unordered_map>
32
34
#include < utility>
33
35
34
36
#include " common/compiler_util.h" // IWYU pragma: keep
35
37
#include " common/config.h"
36
38
#include " common/logging.h"
37
39
#include " common/object_pool.h"
40
+ #include " common/status.h"
38
41
#include " io/cache/block/block_file_cache_profile.h"
39
42
#include " runtime/descriptors.h"
40
43
#include " runtime/runtime_state.h"
41
44
#include " runtime/types.h"
45
+ #include " util/runtime_profile.h"
42
46
#include " vec/aggregate_functions/aggregate_function.h"
43
47
#include " vec/columns/column.h"
44
48
#include " vec/columns/column_nullable.h"
@@ -167,6 +171,10 @@ Status VFileScanner::prepare(
167
171
_file_counter = ADD_COUNTER (_parent->_scanner_profile , " FileNumber" , TUnit::UNIT);
168
172
_has_fully_rf_file_counter =
169
173
ADD_COUNTER (_parent->_scanner_profile , " HasFullyRfFileNumber" , TUnit::UNIT);
174
+ _runtime_filter_partition_pruning_timer = ADD_TIMER (
175
+ _parent->scanner_profile (), " FileScannerRuntimeFilterPartitionPruningTime" );
176
+ _runtime_filter_partition_pruned_range_counter = ADD_COUNTER (
177
+ _parent->scanner_profile (), " RuntimeFilterPartitionPrunedRangeNum" , TUnit::UNIT);
170
178
} else {
171
179
_get_block_timer = ADD_TIMER (_local_state->scanner_profile (), " FileScannerGetBlockTime" );
172
180
_open_reader_timer =
@@ -187,6 +195,11 @@ Status VFileScanner::prepare(
187
195
_file_counter = ADD_COUNTER (_local_state->scanner_profile (), " FileNumber" , TUnit::UNIT);
188
196
_has_fully_rf_file_counter =
189
197
ADD_COUNTER (_local_state->scanner_profile (), " HasFullyRfFileNumber" , TUnit::UNIT);
198
+ _runtime_filter_partition_pruning_timer = ADD_TIMER (
199
+ _local_state->scanner_profile (), " FileScannerRuntimeFilterPartitionPruningTime" );
200
+ _runtime_filter_partition_pruned_range_counter =
201
+ ADD_COUNTER (_local_state->scanner_profile (), " RuntimeFilterPartitionPrunedRangeNum" ,
202
+ TUnit::UNIT);
190
203
}
191
204
192
205
_file_cache_statistics.reset (new io::FileCacheStatistics ());
@@ -226,6 +239,89 @@ Status VFileScanner::prepare(
226
239
return Status::OK ();
227
240
}
228
241
242
+ void VFileScanner::_init_runtime_filter_partition_pruning_ctxs () {
243
+ _runtime_filter_partition_pruning_ctxs.clear ();
244
+ for (auto & conjunct : _conjuncts) {
245
+ auto impl = conjunct->root ()->get_impl ();
246
+ if (impl) {
247
+ // If impl is not null, which means this a conjuncts from runtime filter.
248
+ DCHECK (impl->get_num_children () > 0 && impl->get_child (0 )->is_slot_ref ());
249
+ const auto * slot_ref = static_cast <const VSlotRef*>(impl->get_child (0 ).get ());
250
+ if (_partition_slot_index_map.find (slot_ref->slot_id ()) !=
251
+ _partition_slot_index_map.end ()) {
252
+ // If the slot is partition column, add it to runtime filter partition pruning ctxs.
253
+ _runtime_filter_partition_pruning_ctxs.emplace_back (conjunct);
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+ Status VFileScanner::_process_runtime_filters_partition_pruning (bool & can_filter_all) {
260
+ SCOPED_TIMER (_runtime_filter_partition_pruning_timer);
261
+ if (_runtime_filter_partition_pruning_ctxs.empty () || _partition_col_descs.empty ()) {
262
+ return Status::OK ();
263
+ }
264
+ size_t partition_value_column_size = 0 ;
265
+
266
+ // 1. Get partition key values to string columns.
267
+ std::unordered_map<SlotId, MutableColumnPtr> parititon_slot_id_to_column;
268
+ for (auto const & partition_col_desc : _partition_col_descs) {
269
+ auto partiton_data = std::get<0 >(partition_col_desc.second );
270
+ const auto * partiton_slot_desc = std::get<1 >(partition_col_desc.second );
271
+ auto partition_value_column = ColumnString::create ();
272
+ partition_value_column->insert_data (partiton_data.c_str (), partiton_data.size ());
273
+ partition_value_column_size = partition_value_column->size ();
274
+ parititon_slot_id_to_column[partiton_slot_desc->id ()] = std::move (partition_value_column);
275
+ }
276
+
277
+ // 2. Build a temp block from the partition column, then execute conjuncts and filter block.
278
+ // 2.1 Build a temp block from the partition column to match the conjuncts executing.
279
+ Block temp_block;
280
+ int index = 0 ;
281
+ bool first_cloumn_filled = false ;
282
+ for (auto const * slot_desc : _real_tuple_desc->slots ()) {
283
+ if (!slot_desc->need_materialize ()) {
284
+ // should be ignored from reading
285
+ continue ;
286
+ }
287
+ if (parititon_slot_id_to_column.find (slot_desc->id ()) !=
288
+ parititon_slot_id_to_column.end ()) {
289
+ auto data_type = slot_desc->get_data_type_ptr ();
290
+ auto partition_value_column = std::move (parititon_slot_id_to_column[slot_desc->id ()]);
291
+ if (data_type->is_nullable ()) {
292
+ temp_block.insert (
293
+ {ColumnNullable::create (
294
+ std::move (partition_value_column),
295
+ ColumnUInt8::create (partition_value_column_size, 0 )),
296
+ std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>()),
297
+ " " });
298
+ } else {
299
+ temp_block.insert ({std::move (partition_value_column),
300
+ std::make_shared<DataTypeString>(), " " });
301
+ }
302
+ if (index == 0 ) {
303
+ first_cloumn_filled = true ;
304
+ }
305
+ } else {
306
+ temp_block.insert (ColumnWithTypeAndName (slot_desc->get_empty_mutable_column (),
307
+ slot_desc->get_data_type_ptr (),
308
+ slot_desc->col_name ()));
309
+ }
310
+ index ++;
311
+ }
312
+
313
+ // 2.2 Execute conjuncts.
314
+ if (!first_cloumn_filled) {
315
+ // VExprContext.execute has an optimization, the filtering is executed when block->rows() > 0
316
+ // The following process may be tricky and time-consuming, but we have no other way.
317
+ temp_block.get_by_position (0 ).column ->assume_mutable ()->resize (partition_value_column_size);
318
+ }
319
+ IColumn::Filter result_filter (temp_block.rows (), 1 );
320
+ RETURN_IF_ERROR (VExprContext::execute_conjuncts (_runtime_filter_partition_pruning_ctxs, nullptr ,
321
+ &temp_block, &result_filter, &can_filter_all));
322
+ return Status::OK ();
323
+ }
324
+
229
325
Status VFileScanner::_process_conjuncts_for_dict_filter () {
230
326
_slot_id_to_filter_conjuncts.clear ();
231
327
_not_single_slot_filter_conjuncts.clear ();
@@ -289,6 +385,7 @@ Status VFileScanner::open(RuntimeState* state) {
289
385
RETURN_IF_ERROR (_split_source->get_next (&_first_scan_range, &_current_range));
290
386
if (_first_scan_range) {
291
387
RETURN_IF_ERROR (_init_expr_ctxes ());
388
+ _init_runtime_filter_partition_pruning_ctxs ();
292
389
} else {
293
390
// there's no scan range in split source. stop scanner directly.
294
391
_scanner_eof = true ;
@@ -771,6 +868,24 @@ Status VFileScanner::_get_next_reader() {
771
868
const TFileRangeDesc& range = _current_range;
772
869
_current_range_path = range.path ;
773
870
871
+ if (!_partition_slot_descs.empty ()) {
872
+ // we need get partition columns first for runtime filter partition pruning
873
+ RETURN_IF_ERROR (_generate_parititon_columns ());
874
+ if (_push_down_conjuncts.size () < _conjuncts.size ()) {
875
+ // there are new runtime filters, need to re-init runtime filter partition pruning ctxs
876
+ _init_runtime_filter_partition_pruning_ctxs ();
877
+ }
878
+
879
+ bool can_filter_all = false ;
880
+ RETURN_IF_ERROR (_process_runtime_filters_partition_pruning (can_filter_all));
881
+ if (can_filter_all) {
882
+ // this range can be filtered out by runtime filter partition pruning
883
+ // so we need to skip this range
884
+ COUNTER_UPDATE (_runtime_filter_partition_pruned_range_counter, 1 );
885
+ continue ;
886
+ }
887
+ }
888
+
774
889
// create reader for specific format
775
890
Status init_status;
776
891
TFileFormatType::type format_type = _params->format_type ;
@@ -1019,7 +1134,8 @@ Status VFileScanner::_get_next_reader() {
1019
1134
_missing_cols.clear ();
1020
1135
RETURN_IF_ERROR (_cur_reader->get_columns (&_name_to_col_type, &_missing_cols));
1021
1136
_cur_reader->set_push_down_agg_type (_get_push_down_agg_type ());
1022
- RETURN_IF_ERROR (_generate_fill_columns ());
1137
+ RETURN_IF_ERROR (_generate_missing_columns ());
1138
+ RETURN_IF_ERROR (_cur_reader->set_fill_columns (_partition_col_descs, _missing_col_descs));
1023
1139
if (VLOG_NOTICE_IS_ON && !_missing_cols.empty () && _is_load) {
1024
1140
fmt::memory_buffer col_buf;
1025
1141
for (auto & col : _missing_cols) {
@@ -1049,10 +1165,8 @@ Status VFileScanner::_get_next_reader() {
1049
1165
return Status::OK ();
1050
1166
}
1051
1167
1052
- Status VFileScanner::_generate_fill_columns () {
1168
+ Status VFileScanner::_generate_parititon_columns () {
1053
1169
_partition_col_descs.clear ();
1054
- _missing_col_descs.clear ();
1055
-
1056
1170
const TFileRangeDesc& range = _current_range;
1057
1171
if (range.__isset .columns_from_path && !_partition_slot_descs.empty ()) {
1058
1172
for (const auto & slot_desc : _partition_slot_descs) {
@@ -1073,7 +1187,11 @@ Status VFileScanner::_generate_fill_columns() {
1073
1187
}
1074
1188
}
1075
1189
}
1190
+ return Status::OK ();
1191
+ }
1076
1192
1193
+ Status VFileScanner::_generate_missing_columns () {
1194
+ _missing_col_descs.clear ();
1077
1195
if (!_missing_cols.empty ()) {
1078
1196
for (auto slot_desc : _real_tuple_desc->slots ()) {
1079
1197
if (!slot_desc->is_materialized ()) {
@@ -1091,8 +1209,7 @@ Status VFileScanner::_generate_fill_columns() {
1091
1209
_missing_col_descs.emplace (slot_desc->col_name (), it->second );
1092
1210
}
1093
1211
}
1094
-
1095
- return _cur_reader->set_fill_columns (_partition_col_descs, _missing_col_descs);
1212
+ return Status::OK ();
1096
1213
}
1097
1214
1098
1215
Status VFileScanner::_init_expr_ctxes () {
0 commit comments