diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/AggregatedTimeSeriesRewriter.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/AggregatedTimeSeriesRewriter.java index 28c002373e4bf..6e70e99d4c695 100644 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/AggregatedTimeSeriesRewriter.java +++ b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/AggregatedTimeSeriesRewriter.java @@ -86,6 +86,21 @@ import static com.starrocks.sql.optimizer.rule.transformation.materialization.common.AggregatePushDownUtils.getPushDownRollupFinalAggregateOpt; import static com.starrocks.sql.optimizer.rule.transformation.materialization.common.AggregatePushDownUtils.getRollupPartialAggregate; +/** + * In time-series business scenarios, metrics are aggregated based on the time dimension, with historical + * data continuously being archived (rolled up, compressed), while new data flows in real-time. + * By using Materialized Views (MVs) to speed up, different time granularity of MVs can be constructed, + * the most common being day, month, and year. However, when querying the base table (original table), + * it is hoped that the archived year, month, and day data can be used to speed up time slicing. + * + *

Implementation

+ * Place the logic of splitting time predicates in time-series scenarios + the logic of aggregation push-down into a Rule. When + * it can be rewritten, rewrite the output; otherwise, do not change the original Query. + * Reuse the aggregation push-down + rewriting capabilities, and implement aggregation push-down + rolling up based on the + * aggregation status defined by the materialized view (later, general aggregation status can be used). + * Reuse the capability of nested MV rewriting, recursively call this Rule, + * and rewrite the scope of granularity as much as possible in one go. + */ public class AggregatedTimeSeriesRewriter extends MaterializedViewRewriter { private static final Logger LOG = LogManager.getLogger(AggregatedTimeSeriesRewriter.class); diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ColumnRangePredicate.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ColumnRangePredicate.java index b79b91bdfeead..31682a6af8722 100644 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ColumnRangePredicate.java +++ b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ColumnRangePredicate.java @@ -65,6 +65,15 @@ public class ColumnRangePredicate extends RangePredicate { private TreeRangeSet canonicalColumnRanges; + public static ColumnRangePredicate FALSE = new ColumnRangePredicate(TreeRangeSet.create()); + + public ColumnRangePredicate(TreeRangeSet columnRanges) { + this.columnRanges = columnRanges; + this.expression = null; + this.columnRef = null; + this.canonicalColumnRanges = columnRanges; + } + public ColumnRangePredicate(ScalarOperator expression, TreeRangeSet columnRanges) { this.expression = expression; List columns = Utils.collect(expression, ColumnRefOperator.class); @@ -99,7 +108,7 @@ public static ColumnRangePredicate andRange( for (Range otherRange : otherRangePredicate.columnRanges.asRanges()) { // once there is a range that is not connected with the range, the result is null if (!range.isConnected(otherRange)) { - return null; + return FALSE; } Range intersection = range.intersection(otherRange); if (!intersection.isEmpty()) { @@ -107,7 +116,7 @@ public static ColumnRangePredicate andRange( } } } else { - return null; + return FALSE; } } return new ColumnRangePredicate(rangePredicate.getExpression(), TreeRangeSet.create(ranges)); diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ConstRangePredicate.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ConstRangePredicate.java deleted file mode 100644 index 1b1335a08f9c3..0000000000000 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/ConstRangePredicate.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2021-present StarRocks, Inc. All rights reserved. -// -// Licensed 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 -// -// https://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. -package com.starrocks.sql.optimizer.rule.transformation.materialization; - -import com.starrocks.sql.optimizer.operator.scalar.ConstantOperator; -import com.starrocks.sql.optimizer.operator.scalar.ScalarOperator; - -public class ConstRangePredicate extends RangePredicate { - private final boolean isAlwaysTrue; - - public ConstRangePredicate(boolean isAlwaysTrue) { - this.isAlwaysTrue = isAlwaysTrue; - } - - // convert RangePredicate to ScalarOperator - public ScalarOperator toScalarOperator() { - return isAlwaysTrue ? ConstantOperator.TRUE : ConstantOperator.FALSE; - } -} diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/PredicateExtractor.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/PredicateExtractor.java index dda2e57ae6c5a..3248d5f563d70 100644 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/PredicateExtractor.java +++ b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/materialization/PredicateExtractor.java @@ -237,8 +237,8 @@ private void mergeColumnRange( if (columnRangePredicateMap.containsKey(columnRangePredicate.getExpression())) { ColumnRangePredicate newRangePredicate = columnRangePredicateMap.get(columnRangePredicate.getExpression()); newRangePredicate = mergeOp.apply(newRangePredicate, columnRangePredicate); - if (newRangePredicate == null) { - rangePredicates.add(new ConstRangePredicate(false)); + if (newRangePredicate.equals(ColumnRangePredicate.FALSE)) { + rangePredicates.add(newRangePredicate); return; } if (newRangePredicate.isUnbounded()) {