This is an automated email from the ASF dual-hosted git repository. caogaofei pushed a commit to branch beyyes/topk in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 895819f6fdeb1de9c08f990454edaf4edd5aae63 Author: Beyyes <[email protected]> AuthorDate: Thu Jul 18 11:43:34 2024 +0800 add init --- .../iterative/rule/PushLimitThroughOffset.java | 80 ++++++++++++++++++++++ .../iterative/rule/PushLimitThroughProject.java | 58 ++++++++++++++++ .../plan/relational/planner/node/LimitNode.java | 4 ++ .../planner/optimizations/OptimizeFactory.java | 10 ++- 4 files changed, 151 insertions(+), 1 deletion(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushLimitThroughOffset.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushLimitThroughOffset.java new file mode 100644 index 00000000000..a4983813d80 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushLimitThroughOffset.java @@ -0,0 +1,80 @@ +/* + * 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 + * + * 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. + */ + +package org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule; + +import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.Rule; +import org.apache.iotdb.db.queryengine.plan.relational.planner.node.LimitNode; +import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode; +import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Capture; +import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Captures; +import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Pattern; + +import com.google.common.collect.ImmutableList; + +import static java.lang.Math.addExact; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.limit; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.offset; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.source; +import static org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Capture.newCapture; + +/** + * Transforms: + * + * <pre> + * - Limit (row count x) + * - Offset (row count y) + * </pre> + * + * Into: + * + * <pre> + * - Offset (row count y) + * - Limit (row count x+y) + * </pre> + * + * Applies to both limit with ties and limit without ties. + */ +public class PushLimitThroughOffset implements Rule<LimitNode> { + private static final Capture<OffsetNode> CHILD = newCapture(); + + private static final Pattern<LimitNode> PATTERN = + limit().with(source().matching(offset().capturedAs(CHILD))); + + @Override + public Pattern<LimitNode> getPattern() { + return PATTERN; + } + + @Override + public Result apply(LimitNode parent, Captures captures, Context context) { + OffsetNode child = captures.get(CHILD); + + long count; + try { + count = addExact(parent.getCount(), child.getCount()); + } catch (ArithmeticException e) { + return Result.empty(); + } + + return Result.ofPlanNode( + child.replaceChildren( + ImmutableList.of( + new LimitNode( + parent.getPlanNodeId(), + child.getChild(), + count, + parent.getTiesResolvingScheme())))); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushLimitThroughProject.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushLimitThroughProject.java new file mode 100644 index 00000000000..26ecef14a4c --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushLimitThroughProject.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule; + +import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.Rule; +import org.apache.iotdb.db.queryengine.plan.relational.planner.node.LimitNode; +import org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode; +import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Capture; +import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Captures; +import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Pattern; + +import static org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.Util.transpose; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.limit; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.project; +import static org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.source; +import static org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Capture.newCapture; + +public class PushLimitThroughProject implements Rule<LimitNode> { + private static final Capture<ProjectNode> CHILD = newCapture(); + + private static final Pattern<LimitNode> PATTERN = + limit() + .with( + source() + .matching( + project() + // do not push limit through identity projection which could be there for + // column pruning purposes + .matching(projectNode -> !projectNode.isIdentity()) + .capturedAs(CHILD))); + + @Override + public Pattern<LimitNode> getPattern() { + return PATTERN; + } + + @Override + public Result apply(LimitNode parent, Captures captures, Context context) { + ProjectNode projectNode = captures.get(CHILD); + return Result.ofPlanNode(transpose(parent, projectNode)); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java index a0862384d87..a620c65ff6a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java @@ -99,6 +99,10 @@ public class LimitNode extends SingleChildProcessNode { return count; } + public Optional<OrderingScheme> getTiesResolvingScheme() { + return tiesResolvingScheme; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/OptimizeFactory.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/OptimizeFactory.java index 486721b46e9..3a358a9fbfd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/OptimizeFactory.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/OptimizeFactory.java @@ -25,6 +25,8 @@ import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.Pr import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneProjectColumns; import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneSortColumns; import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneTableScanColumns; +import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PushLimitThroughOffset; +import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PushLimitThroughProject; import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.RemoveRedundantIdentityProjections; import com.google.common.collect.ImmutableList; @@ -61,6 +63,11 @@ public class OptimizeFactory { ImmutableSet.of( new InlineProjections(plannerContext), new RemoveRedundantIdentityProjections())); + Set<Rule<?>> limitPushdownRules = + ImmutableSet.of(new PushLimitThroughOffset(), new PushLimitThroughProject()); + IterativeOptimizer limitPushdownOptimizer = + new IterativeOptimizer(plannerContext, new RuleStatsRecorder(), limitPushdownRules); + this.planOptimizers = ImmutableList.of( simplifyExpressionOptimizer, @@ -69,7 +76,8 @@ public class OptimizeFactory { pushPredicateIntoTableScanOptimizer, // redo columnPrune and inlineProjections after pushPredicateIntoTableScan columnPruningOptimizer, - inlineProjectionsOptimizer); + inlineProjectionsOptimizer, + limitPushdownOptimizer); } public List<PlanOptimizer> getPlanOptimizers() {
