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,92 @@ Status VFileScanner::prepare(
226
239
return Status::OK ();
227
240
}
228
241
242
+ void VFileScanner::_init_runtime_filter_partition_pruning_ctxs () {
243
+ if (_partition_slot_index_map.empty ()) {
244
+ return ;
245
+ }
246
+ _runtime_filter_partition_pruning_ctxs.clear ();
247
+ for (auto & conjunct : _conjuncts) {
248
+ auto impl = conjunct->root ()->get_impl ();
249
+ // If impl is not null, which means this a conjuncts from runtime filter.
250
+ auto expr = impl ? impl : conjunct->root ();
251
+ if (expr->get_num_children () > 0 && expr->get_child (0 )->is_slot_ref ()) {
252
+ const auto * slot_ref = static_cast <const VSlotRef*>(expr->get_child (0 ).get ());
253
+ if (_partition_slot_index_map.find (slot_ref->slot_id ()) !=
254
+ _partition_slot_index_map.end ()) {
255
+ // If the slot is partition column, add it to runtime filter partition pruning ctxs.
256
+ _runtime_filter_partition_pruning_ctxs.emplace_back (conjunct);
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ Status VFileScanner::_process_runtime_filters_partition_pruning (bool & can_filter_all) {
263
+ SCOPED_TIMER (_runtime_filter_partition_pruning_timer);
264
+ if (_runtime_filter_partition_pruning_ctxs.empty () || _partition_col_descs.empty ()) {
265
+ return Status::OK ();
266
+ }
267
+ size_t partition_value_column_size = 1 ;
268
+
269
+ // 1. Get partition key values to string columns.
270
+ std::unordered_map<SlotId, MutableColumnPtr> parititon_slot_id_to_column;
271
+ for (auto const & partition_col_desc : _partition_col_descs) {
272
+ const auto & [partition_value, partition_slot_desc] = partition_col_desc.second ;
273
+ auto test_serde = partition_slot_desc->get_data_type_ptr ()->get_serde ();
274
+ auto partition_value_column = partition_slot_desc->get_data_type_ptr ()->create_column ();
275
+ auto * col_ptr = static_cast <IColumn*>(partition_value_column.get ());
276
+ Slice slice (partition_value.data (), partition_value.size ());
277
+ int num_deserialized = 0 ;
278
+ RETURN_IF_ERROR (test_serde->deserialize_column_from_fixed_json (
279
+ *col_ptr, slice, partition_value_column_size, &num_deserialized, {}));
280
+ parititon_slot_id_to_column[partition_slot_desc->id ()] = std::move (partition_value_column);
281
+ }
282
+
283
+ // 2. Build a temp block from the partition column, then execute conjuncts and filter block.
284
+ // 2.1 Build a temp block from the partition column to match the conjuncts executing.
285
+ Block temp_block;
286
+ int index = 0 ;
287
+ bool first_cloumn_filled = false ;
288
+ for (auto const * slot_desc : _real_tuple_desc->slots ()) {
289
+ if (!slot_desc->need_materialize ()) {
290
+ // should be ignored from reading
291
+ continue ;
292
+ }
293
+ if (parititon_slot_id_to_column.find (slot_desc->id ()) !=
294
+ parititon_slot_id_to_column.end ()) {
295
+ auto data_type = slot_desc->get_data_type_ptr ();
296
+ auto partition_value_column = std::move (parititon_slot_id_to_column[slot_desc->id ()]);
297
+ if (data_type->is_nullable ()) {
298
+ temp_block.insert ({ColumnNullable::create (
299
+ std::move (partition_value_column),
300
+ ColumnUInt8::create (partition_value_column_size, 0 )),
301
+ data_type, " " });
302
+ } else {
303
+ temp_block.insert ({std::move (partition_value_column), data_type, " " });
304
+ }
305
+ if (index == 0 ) {
306
+ first_cloumn_filled = true ;
307
+ }
308
+ } else {
309
+ temp_block.insert (ColumnWithTypeAndName (slot_desc->get_empty_mutable_column (),
310
+ slot_desc->get_data_type_ptr (),
311
+ slot_desc->col_name ()));
312
+ }
313
+ index ++;
314
+ }
315
+
316
+ // 2.2 Execute conjuncts.
317
+ if (!first_cloumn_filled) {
318
+ // VExprContext.execute has an optimization, the filtering is executed when block->rows() > 0
319
+ // The following process may be tricky and time-consuming, but we have no other way.
320
+ temp_block.get_by_position (0 ).column ->assume_mutable ()->resize (partition_value_column_size);
321
+ }
322
+ IColumn::Filter result_filter (temp_block.rows (), 1 );
323
+ RETURN_IF_ERROR (VExprContext::execute_conjuncts (_runtime_filter_partition_pruning_ctxs, nullptr ,
324
+ &temp_block, &result_filter, &can_filter_all));
325
+ return Status::OK ();
326
+ }
327
+
229
328
Status VFileScanner::_process_conjuncts_for_dict_filter () {
230
329
_slot_id_to_filter_conjuncts.clear ();
231
330
_not_single_slot_filter_conjuncts.clear ();
@@ -289,6 +388,7 @@ Status VFileScanner::open(RuntimeState* state) {
289
388
RETURN_IF_ERROR (_split_source->get_next (&_first_scan_range, &_current_range));
290
389
if (_first_scan_range) {
291
390
RETURN_IF_ERROR (_init_expr_ctxes ());
391
+ _init_runtime_filter_partition_pruning_ctxs ();
292
392
} else {
293
393
// there's no scan range in split source. stop scanner directly.
294
394
_scanner_eof = true ;
@@ -771,6 +871,24 @@ Status VFileScanner::_get_next_reader() {
771
871
const TFileRangeDesc& range = _current_range;
772
872
_current_range_path = range.path ;
773
873
874
+ if (!_partition_slot_descs.empty ()) {
875
+ // we need get partition columns first for runtime filter partition pruning
876
+ RETURN_IF_ERROR (_generate_parititon_columns ());
877
+ if (_push_down_conjuncts.size () < _conjuncts.size ()) {
878
+ // there are new runtime filters, need to re-init runtime filter partition pruning ctxs
879
+ _init_runtime_filter_partition_pruning_ctxs ();
880
+ }
881
+
882
+ bool can_filter_all = false ;
883
+ RETURN_IF_ERROR (_process_runtime_filters_partition_pruning (can_filter_all));
884
+ if (can_filter_all) {
885
+ // this range can be filtered out by runtime filter partition pruning
886
+ // so we need to skip this range
887
+ COUNTER_UPDATE (_runtime_filter_partition_pruned_range_counter, 1 );
888
+ continue ;
889
+ }
890
+ }
891
+
774
892
// create reader for specific format
775
893
Status init_status;
776
894
TFileFormatType::type format_type = _params->format_type ;
@@ -1019,7 +1137,8 @@ Status VFileScanner::_get_next_reader() {
1019
1137
_missing_cols.clear ();
1020
1138
RETURN_IF_ERROR (_cur_reader->get_columns (&_name_to_col_type, &_missing_cols));
1021
1139
_cur_reader->set_push_down_agg_type (_get_push_down_agg_type ());
1022
- RETURN_IF_ERROR (_generate_fill_columns ());
1140
+ RETURN_IF_ERROR (_generate_missing_columns ());
1141
+ RETURN_IF_ERROR (_cur_reader->set_fill_columns (_partition_col_descs, _missing_col_descs));
1023
1142
if (VLOG_NOTICE_IS_ON && !_missing_cols.empty () && _is_load) {
1024
1143
fmt::memory_buffer col_buf;
1025
1144
for (auto & col : _missing_cols) {
@@ -1049,10 +1168,8 @@ Status VFileScanner::_get_next_reader() {
1049
1168
return Status::OK ();
1050
1169
}
1051
1170
1052
- Status VFileScanner::_generate_fill_columns () {
1171
+ Status VFileScanner::_generate_parititon_columns () {
1053
1172
_partition_col_descs.clear ();
1054
- _missing_col_descs.clear ();
1055
-
1056
1173
const TFileRangeDesc& range = _current_range;
1057
1174
if (range.__isset .columns_from_path && !_partition_slot_descs.empty ()) {
1058
1175
for (const auto & slot_desc : _partition_slot_descs) {
@@ -1073,7 +1190,11 @@ Status VFileScanner::_generate_fill_columns() {
1073
1190
}
1074
1191
}
1075
1192
}
1193
+ return Status::OK ();
1194
+ }
1076
1195
1196
+ Status VFileScanner::_generate_missing_columns () {
1197
+ _missing_col_descs.clear ();
1077
1198
if (!_missing_cols.empty ()) {
1078
1199
for (auto slot_desc : _real_tuple_desc->slots ()) {
1079
1200
if (!slot_desc->is_materialized ()) {
@@ -1091,8 +1212,7 @@ Status VFileScanner::_generate_fill_columns() {
1091
1212
_missing_col_descs.emplace (slot_desc->col_name (), it->second );
1092
1213
}
1093
1214
}
1094
-
1095
- return _cur_reader->set_fill_columns (_partition_col_descs, _missing_col_descs);
1215
+ return Status::OK ();
1096
1216
}
1097
1217
1098
1218
Status VFileScanner::_init_expr_ctxes () {
0 commit comments