Files
impala/common/protobuf/data_stream_service.proto
stiga-huang 374783c55e IMPALA-10898: Add runtime IN-list filters for ORC tables
ORC files have optional bloom filter indexes for each column. Since
ORC-1.7.0, the C++ reader supports pushing down predicates to skip
unreleated RowGroups. The pushed down predicates will be evaludated on
file indexes (i.e. statistics and bloom filter indexes). Note that only
EQUALS and IN-list predicates can leverage bloom filter indexes.

Currently Impala has two kinds of runtime filters: bloom filter and
min-max filter. Unfortunately they can't be converted into EQUALS or
IN-list predicates. So they can't leverage the file level bloom filter
indexes.

This patch adds runtime IN-list filters for this purpose. Currently they
are generated for the build side of a broadcast join. They will only be
applied on ORC tables and be pushed down to the ORC reader(i.e. ORC
lib). To avoid exploding the IN-list, if # of distinct values of the
build side exceeds a threshold (default to 1024), we set the filter to
ALWAYS_TRUE and clear its entry. The threshold can be configured by a
new query option, RUNTIME_IN_LIST_FILTER_ENTRY_LIMIT.

Evaluating runtime IN-list filters is much slower than evaluating
runtime bloom filters due to the current simple implementation (i.e.
std::unorder_set) and the lack of codegen. So we disable it at row
level.

For visibility, this patch addes two counters in the HdfsScanNode:
 - NumPushedDownPredicates
 - NumPushedDownRuntimeFilters
They reflect the predicates and runtime filters that are pushed down to
the ORC reader.

Currently, runtime IN-list filters are disabled by default. This patch
extends the query option, ENABLED_RUNTIME_FILTER_TYPES, to support a
comma separated list of filter types. It defaults to be "BLOOM,MIN_MAX".
Add "IN_LIST" in it to enable runtime IN-list filters.

Ran perf tests on a 3 instances cluster on my desktop using TPC-DS with
scale factor 20. It shows significant improvements in some queries:

+-----------+-------------+--------------------+--------+-------------+------------+------------+----------------+-------+----------------+---------+--------+
| Workload  | Query       | File Format        | Avg(s) | Base Avg(s) | Delta(Avg) | StdDev(%)  | Base StdDev(%) | Iters | Median Diff(%) | MW Zval | Tval   |
+-----------+-------------+--------------------+--------+-------------+------------+------------+----------------+-------+----------------+---------+--------+
| TPCDS(20) | TPCDS-Q67A  | orc / snap / block | 35.07  | 44.01       | I -20.32%  |   0.38%    |   1.38%        | 10    | I -25.69%      | -3.58   | -45.33 |
| TPCDS(20) | TPCDS-Q37   | orc / snap / block | 1.08   | 1.45        | I -25.23%  |   7.14%    |   3.09%        | 10    | I -34.09%      | -3.58   | -12.94 |
| TPCDS(20) | TPCDS-Q70A  | orc / snap / block | 6.30   | 8.60        | I -26.81%  |   5.24%    |   4.21%        | 10    | I -36.67%      | -3.58   | -14.88 |
| TPCDS(20) | TPCDS-Q16   | orc / snap / block | 1.33   | 1.85        | I -28.28%  |   4.98%    |   5.92%        | 10    | I -39.38%      | -3.58   | -12.93 |
| TPCDS(20) | TPCDS-Q18A  | orc / snap / block | 5.70   | 8.06        | I -29.25%  |   3.00%    |   4.12%        | 10    | I -40.30%      | -3.58   | -19.95 |
| TPCDS(20) | TPCDS-Q22A  | orc / snap / block | 2.01   | 2.97        | I -32.21%  |   6.12%    |   5.94%        | 10    | I -47.68%      | -3.58   | -14.05 |
| TPCDS(20) | TPCDS-Q77A  | orc / snap / block | 8.49   | 12.44       | I -31.75%  |   6.44%    |   3.96%        | 10    | I -49.71%      | -3.58   | -16.97 |
| TPCDS(20) | TPCDS-Q75   | orc / snap / block | 7.76   | 12.27       | I -36.76%  |   5.01%    |   3.87%        | 10    | I -59.56%      | -3.58   | -23.26 |
| TPCDS(20) | TPCDS-Q21   | orc / snap / block | 0.71   | 1.27        | I -44.26%  |   4.56%    |   4.24%        | 10    | I -77.31%      | -3.58   | -28.31 |
| TPCDS(20) | TPCDS-Q80A  | orc / snap / block | 9.24   | 20.42       | I -54.77%  |   4.03%    |   3.82%        | 10    | I -123.12%     | -3.58   | -40.90 |
| TPCDS(20) | TPCDS-Q39-1 | orc / snap / block | 1.07   | 2.26        | I -52.74%  | * 23.83% * |   2.60%        | 10    | I -149.68%     | -3.58   | -14.43 |
| TPCDS(20) | TPCDS-Q39-2 | orc / snap / block | 1.00   | 2.33        | I -56.95%  | * 19.53% * |   2.07%        | 10    | I -151.89%     | -3.58   | -20.81 |
+-----------+-------------+--------------------+--------+-------------+------------+------------+----------------+-------+----------------+---------+--------+
"Base Avg" is the avg of the original time. "Avg" is the current time.

However, we also see some regressions due to the suboptimal
implementation. The follow-up JIRAs will focus on improvements:
 - IMPALA-11140: Codegen InListFilter::Insert() and InListFilter::Find()
 - IMPALA-11141: Use exact data types in IN-list filters instead of
   casting data to a set of int64_t or a set of string.
 - IMPALA-11142: Consider IN-list filters in partitioned joins.

Tests:
 - Test IN-list filter on string, date and all integer types
 - Test IN-list filter with NULL
 - Test IN-list filter on complex exprs targets

Change-Id: I25080628233799aa0b6be18d5a832f1385414501
Reviewed-on: http://gerrit.cloudera.org:8080/18141
Reviewed-by: Qifan Chen <qchen@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
2022-03-03 00:21:06 +00:00

181 lines
5.8 KiB
Protocol Buffer

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
syntax="proto2";
package impala;
import "common.proto";
import "row_batch.proto";
import "kudu/rpc/rpc_header.proto";
// All fields are required in V1.
message TransmitDataRequestPB {
// The fragment instance id of the receiver.
optional UniqueIdPB dest_fragment_instance_id = 1;
// Sender instance id, unique within a fragment.
optional int32 sender_id = 2;
// PlanNodeId of the exchange node which owns the receiver.
optional int32 dest_node_id = 3;
// The header which contains the meta-data of the row batch.
optional RowBatchHeaderPB row_batch_header = 4;
// The sidecar index of tuple offsets' buffer which is an array of int32 containing the
// offsets of tuples into the buffer pointed to by tuple data's sidecar below. There are
// num_rows * num_tuples_per_row offsets in total. An offset of -1 records a NULL.
optional int32 tuple_offsets_sidecar_idx = 5;
// The sidecar index of the tuple's data which is a (compressed) row batch.
// The details of the row batch (e.g. # of rows) is in 'row_batch_header' above.
optional int32 tuple_data_sidecar_idx = 6;
}
// All fields are required in V1.
message TransmitDataResponsePB {
// Status::OK() on success; Error status on failure.
optional StatusPB status = 1;
// Latency for response in the receiving daemon in nanoseconds.
optional int64 receiver_latency_ns = 2;
}
// All fields are required in V1.
message EndDataStreamRequestPB {
// The fragment instance id of the receiver.
optional UniqueIdPB dest_fragment_instance_id = 1;
// Sender instance id, unique within a fragment.
optional int32 sender_id = 2;
// PlanNodeId of the exchange node which owns the receiver.
optional int32 dest_node_id = 3;
}
// All fields are required in V1.
message EndDataStreamResponsePB {
optional StatusPB status = 1;
// Latency for response in the receiving daemon in nanoseconds.
optional int64 receiver_latency_ns = 2;
}
message BloomFilterPB {
// Log_2 of the bufferpool space required for this filter.
// See BloomFilter::BloomFilter() for details.
optional int32 log_bufferpool_space = 1;
// If always_true or always_false is true, 'directory' and 'log_bufferpool_space' are
// not meaningful.
optional bool always_true = 2;
optional bool always_false = 3;
// The sidecar index associated with the directory of a Bloom filter.
// A directory is a list of buckets representing the Bloom Filter contents,
// laid out contiguously in one string for efficiency of (de)serialisation.
// See BloomFilter::Bucket and BloomFilter::directory_.
optional int32 directory_sidecar_idx = 4;
}
message MinMaxFilterPB {
// If true, filter allows all elements to pass and 'min'/'max' will not be set.
optional bool always_true = 1;
// If true, filter doesn't allow any elements to pass and 'min'/'max' will not be set.
optional bool always_false = 2;
optional ColumnValuePB min = 3;
optional ColumnValuePB max = 4;
}
message InListFilterPB {
optional bool always_true = 1;
optional bool contains_null = 2;
repeated ColumnValuePB value = 3;
}
message UpdateFilterParamsPB {
// Filter ID, unique within a query.
optional int32 filter_id = 1;
// Query that this filter is for.
optional UniqueIdPB query_id = 2;
optional BloomFilterPB bloom_filter = 3;
optional MinMaxFilterPB min_max_filter = 4;
optional InListFilterPB in_list_filter = 5;
}
message UpdateFilterResultPB {
optional StatusPB status = 1;
// Latency for response in the receiving daemon in nanoseconds.
optional int64 receiver_latency_ns = 2;
}
message PublishFilterParamsPB {
// Filter ID, unique within a query.
optional int32 filter_id = 1;
// Query that this filter is for.
optional UniqueIdPB dst_query_id = 2;
// Actual bloom_filter payload
optional BloomFilterPB bloom_filter = 3;
// Actual min_max_filter payload
optional MinMaxFilterPB min_max_filter = 4;
// Actual in_list_filter payload
optional InListFilterPB in_list_filter = 5;
}
message PublishFilterResultPB {
optional StatusPB status = 1;
// Latency for response in the receiving daemon in nanoseconds.
optional int64 receiver_latency_ns = 2;
}
// Handles data transmission between fragment instances.
service DataStreamService {
// Override the default authorization method.
option (kudu.rpc.default_authz_method) = "Authorize";
// Called by sender to transmit a single row batch. Returns error indication
// if params.fragmentId or params.destNodeId are unknown or if data couldn't
// be read.
rpc TransmitData(TransmitDataRequestPB) returns (TransmitDataResponsePB);
// Called by a sender to close the channel between fragment instances.
rpc EndDataStream(EndDataStreamRequestPB) returns (EndDataStreamResponsePB);
// Called by fragment instances that produce local runtime filters to deliver them to
// the coordinator for aggregation and broadcast.
rpc UpdateFilter(UpdateFilterParamsPB) returns (UpdateFilterResultPB);
// Called by the coordinator to deliver global runtime filters to fragments for
// application at plan nodes.
rpc PublishFilter(PublishFilterParamsPB) returns (PublishFilterResultPB);
}