[Enhancement](Nereids) Automatic compute logical properties (#10176)

Automatic compute logical properties
This commit is contained in:
924060929
2022-06-17 11:31:05 +08:00
committed by GitHub
parent 60147ad7a5
commit d51166dd2a
56 changed files with 500 additions and 243 deletions

View File

@ -24,13 +24,12 @@ import org.apache.doris.nereids.jobs.scheduler.JobStack;
import org.apache.doris.nereids.jobs.scheduler.SimpleJobScheduler;
import org.apache.doris.nereids.memo.Memo;
import org.apache.doris.nereids.rules.RuleSet;
import org.apache.doris.nereids.trees.TreeNode;
/**
* Context used in memo.
*/
public class OptimizerContext<NODE_TYPE extends TreeNode<NODE_TYPE>> {
private final Memo<NODE_TYPE> memo;
public class OptimizerContext {
private final Memo memo;
private RuleSet ruleSet;
private JobPool jobPool;
private final JobScheduler jobScheduler;
@ -40,7 +39,7 @@ public class OptimizerContext<NODE_TYPE extends TreeNode<NODE_TYPE>> {
*
* @param memo {@link Memo} reference
*/
public OptimizerContext(Memo<NODE_TYPE> memo) {
public OptimizerContext(Memo memo) {
this.memo = memo;
this.ruleSet = new RuleSet();
this.jobPool = new JobStack();
@ -63,7 +62,7 @@ public class OptimizerContext<NODE_TYPE extends TreeNode<NODE_TYPE>> {
this.ruleSet = ruleSet;
}
public Memo<NODE_TYPE> getMemo() {
public Memo getMemo() {
return memo;
}

View File

@ -23,7 +23,6 @@ import org.apache.doris.nereids.jobs.rewrite.RewriteBottomUpJob;
import org.apache.doris.nereids.memo.Group;
import org.apache.doris.nereids.memo.Memo;
import org.apache.doris.nereids.properties.PhysicalProperties;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
import org.apache.doris.qe.ConnectContext;
@ -48,10 +47,10 @@ public class Planner {
LogicalPlan plan,
PhysicalProperties outputProperties,
ConnectContext connectContext) throws AnalysisException {
Memo<Plan> memo = new Memo<>();
Memo memo = new Memo();
memo.initialize(plan);
OptimizerContext<Plan> optimizerContext = new OptimizerContext<>(memo);
OptimizerContext optimizerContext = new OptimizerContext(memo);
plannerContext = new PlannerContext(optimizerContext, connectContext, outputProperties);
plannerContext.getOptimizerContext().pushJob(

View File

@ -0,0 +1,22 @@
// 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.doris.nereids.analyzer;
/** Use to marking unbound plan and unbound expression. */
public interface Unbound {
}

View File

@ -31,7 +31,7 @@ import java.util.List;
*/
public class UnboundAlias<CHILD_TYPE extends Expression>
extends NamedExpression
implements UnaryExpression<CHILD_TYPE> {
implements UnaryExpression<CHILD_TYPE>, Unbound {
public UnboundAlias(CHILD_TYPE child) {
super(NodeType.UNBOUND_ALIAS, child);

View File

@ -21,7 +21,10 @@ import org.apache.doris.nereids.analyzer.identifier.TableIdentifier;
import org.apache.doris.nereids.exceptions.UnboundException;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.logical.LogicalLeafOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.properties.UnboundLogicalProperties;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.util.Utils;
import com.clearspring.analytics.util.Lists;
@ -32,7 +35,7 @@ import java.util.List;
/**
* Represent a relation plan node that has not been bound.
*/
public class UnboundRelation extends LogicalLeafOperator {
public class UnboundRelation extends LogicalLeafOperator implements Unbound {
private final List<String> nameParts;
public UnboundRelation(List<String> nameParts) {
@ -64,9 +67,13 @@ public class UnboundRelation extends LogicalLeafOperator {
}
@Override
public List<Slot> doComputeOutput() {
// fixme: throw unchecked exception
throw new IllegalStateException(new UnboundException("output"));
public LogicalProperties computeLogicalProperties(Plan... inputs) {
return new UnboundLogicalProperties();
}
@Override
public List<Slot> computeOutput() {
throw new UnboundException("output");
}
@Override

View File

@ -28,7 +28,7 @@ import java.util.List;
/**
* Slot has not been bound.
*/
public class UnboundSlot extends Slot {
public class UnboundSlot extends Slot implements Unbound {
private final List<String> nameParts;
public UnboundSlot(List<String> nameParts) {

View File

@ -29,7 +29,7 @@ import java.util.List;
/**
* Star expression.
*/
public class UnboundStar extends NamedExpression implements LeafExpression {
public class UnboundStar extends NamedExpression implements LeafExpression, Unbound {
private final List<String> target;
public UnboundStar(List<String> target) {

View File

@ -57,7 +57,7 @@ public class ApplyRuleJob extends Job<Plan> {
return;
}
GroupExpressionMatching<Plan> groupExpressionMatching
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(rule.getPattern(), groupExpression);
for (Plan plan : groupExpressionMatching) {
List<Plan> newPlans = rule.transform(plan, context);

View File

@ -25,7 +25,7 @@ import org.apache.doris.nereids.memo.Group;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.pattern.GroupExpressionMatching;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
@ -35,16 +35,16 @@ import java.util.Objects;
/**
* Bottom up job for rewrite, use pattern match.
*/
public class RewriteBottomUpJob<NODE_TYPE extends TreeNode<NODE_TYPE>> extends Job<NODE_TYPE> {
public class RewriteBottomUpJob extends Job<Plan> {
private final Group group;
private final List<Rule<NODE_TYPE>> rules;
private final List<Rule<Plan>> rules;
private final boolean childrenOptimized;
public RewriteBottomUpJob(Group group, List<Rule<NODE_TYPE>> rules, PlannerContext context) {
public RewriteBottomUpJob(Group group, List<Rule<Plan>> rules, PlannerContext context) {
this(group, rules, context, false);
}
private RewriteBottomUpJob(Group group, List<Rule<NODE_TYPE>> rules,
private RewriteBottomUpJob(Group group, List<Rule<Plan>> rules,
PlannerContext context, boolean childrenOptimized) {
super(JobType.BOTTOM_UP_REWRITE, context);
this.group = Objects.requireNonNull(group, "group cannot be null");
@ -57,23 +57,23 @@ public class RewriteBottomUpJob<NODE_TYPE extends TreeNode<NODE_TYPE>> extends J
GroupExpression logicalExpression = group.getLogicalExpression();
if (!childrenOptimized) {
for (Group childGroup : logicalExpression.children()) {
pushTask(new RewriteBottomUpJob<>(childGroup, rules, context, false));
pushTask(new RewriteBottomUpJob(childGroup, rules, context, false));
}
pushTask(new RewriteBottomUpJob<>(group, rules, context, true));
pushTask(new RewriteBottomUpJob(group, rules, context, true));
return;
}
List<Rule<NODE_TYPE>> validRules = getValidRules(logicalExpression, rules);
for (Rule<NODE_TYPE> rule : validRules) {
GroupExpressionMatching<NODE_TYPE> groupExpressionMatching
= new GroupExpressionMatching<>(rule.getPattern(), logicalExpression);
for (NODE_TYPE before : groupExpressionMatching) {
List<NODE_TYPE> afters = rule.transform(before, context);
List<Rule<Plan>> validRules = getValidRules(logicalExpression, rules);
for (Rule<Plan> rule : validRules) {
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(rule.getPattern(), logicalExpression);
for (Plan before : groupExpressionMatching) {
List<Plan> afters = rule.transform(before, context);
Preconditions.checkArgument(afters.size() == 1);
NODE_TYPE after = afters.get(0);
Plan after = afters.get(0);
if (after != before) {
context.getOptimizerContext().getMemo().copyIn(after, group, rule.isRewrite());
pushTask(new RewriteBottomUpJob<>(group, rules, context, false));
pushTask(new RewriteBottomUpJob(group, rules, context, false));
return;
}
}

View File

@ -24,7 +24,7 @@ import org.apache.doris.nereids.memo.Group;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.pattern.GroupExpressionMatching;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
@ -34,9 +34,9 @@ import java.util.Objects;
/**
* Top down job for rewrite, use pattern match.
*/
public class RewriteTopDownJob<NODE_TYPE extends TreeNode<NODE_TYPE>> extends Job<NODE_TYPE> {
public class RewriteTopDownJob extends Job<Plan> {
private final Group group;
private final List<Rule<NODE_TYPE>> rules;
private final List<Rule<Plan>> rules;
/**
* Constructor.
@ -45,7 +45,7 @@ public class RewriteTopDownJob<NODE_TYPE extends TreeNode<NODE_TYPE>> extends Jo
* @param rules rewrite rules
* @param context planner context
*/
public RewriteTopDownJob(Group group, List<Rule<NODE_TYPE>> rules, PlannerContext context) {
public RewriteTopDownJob(Group group, List<Rule<Plan>> rules, PlannerContext context) {
super(JobType.TOP_DOWN_REWRITE, context);
this.group = Objects.requireNonNull(group, "group cannot be null");
this.rules = Objects.requireNonNull(rules, "rules cannot be null");
@ -55,17 +55,17 @@ public class RewriteTopDownJob<NODE_TYPE extends TreeNode<NODE_TYPE>> extends Jo
public void execute() {
GroupExpression logicalExpression = group.getLogicalExpression();
List<Rule<NODE_TYPE>> validRules = getValidRules(logicalExpression, rules);
for (Rule<NODE_TYPE> rule : validRules) {
GroupExpressionMatching<NODE_TYPE> groupExpressionMatching
= new GroupExpressionMatching<>(rule.getPattern(), logicalExpression);
for (NODE_TYPE before : groupExpressionMatching) {
List<NODE_TYPE> afters = rule.transform(before, context);
List<Rule<Plan>> validRules = getValidRules(logicalExpression, rules);
for (Rule<Plan> rule : validRules) {
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(rule.getPattern(), logicalExpression);
for (Plan before : groupExpressionMatching) {
List<Plan> afters = rule.transform(before, context);
Preconditions.checkArgument(afters.size() == 1);
NODE_TYPE after = afters.get(0);
Plan after = afters.get(0);
if (after != before) {
context.getOptimizerContext().getMemo().copyIn(after, group, rule.isRewrite());
pushTask(new RewriteTopDownJob<>(group, rules, context));
pushTask(new RewriteTopDownJob(group, rules, context));
return;
}
}
@ -73,7 +73,7 @@ public class RewriteTopDownJob<NODE_TYPE extends TreeNode<NODE_TYPE>> extends Jo
}
for (Group childGroup : logicalExpression.children()) {
pushTask(new RewriteTopDownJob<>(childGroup, rules, context));
pushTask(new RewriteTopDownJob(childGroup, rules, context));
}
}
}

View File

@ -50,12 +50,13 @@ public class Group {
*
* @param groupExpression first {@link GroupExpression} in this Group
*/
public Group(GroupExpression groupExpression) {
public Group(GroupExpression groupExpression, LogicalProperties logicalProperties) {
if (groupExpression.getOperator() instanceof LogicalOperator) {
this.logicalExpressions.add(groupExpression);
} else {
this.physicalExpressions.add(groupExpression);
}
this.logicalProperties = logicalProperties;
groupExpression.setParent(this);
}
@ -101,12 +102,12 @@ public class Group {
* @param newExpression new logical group expression
* @return old logical group expression
*/
public GroupExpression rewriteLogicalExpression(
GroupExpression newExpression) {
GroupExpression oldExpression = getLogicalExpression();
public GroupExpression rewriteLogicalExpression(GroupExpression newExpression,
LogicalProperties logicalProperties) {
logicalExpressions.clear();
logicalExpressions.add(newExpression);
return oldExpression;
this.logicalProperties = logicalProperties;
return getLogicalExpression();
}
public double getCostLowerBound() {
@ -143,6 +144,10 @@ public class Group {
return logicalProperties;
}
public void setLogicalProperties(LogicalProperties logicalProperties) {
this.logicalProperties = logicalProperties;
}
public boolean isExplored() {
return isExplored;
}

View File

@ -17,7 +17,7 @@
package org.apache.doris.nereids.memo;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.Plan;
@ -30,16 +30,14 @@ import java.util.Map;
/**
* Representation for memo in cascades optimizer.
*
* @param <NODE_TYPE> should be {@link Plan} or {@link Expression}
*/
public class Memo<NODE_TYPE extends TreeNode<NODE_TYPE>> {
public class Memo {
private final List<Group> groups = Lists.newArrayList();
// we could not use Set, because Set has no get method.
private final Map<GroupExpression, GroupExpression> groupExpressions = Maps.newHashMap();
private Group root;
public void initialize(NODE_TYPE node) {
public void initialize(Plan node) {
root = copyIn(node, null, false).getParent();
}
@ -56,10 +54,10 @@ public class Memo<NODE_TYPE extends TreeNode<NODE_TYPE>> {
* @param rewrite whether to rewrite the node to the target group
* @return Reference of node in Memo
*/
public GroupExpression copyIn(NODE_TYPE node, Group target, boolean rewrite) {
public GroupExpression copyIn(Plan node, Group target, boolean rewrite) {
Preconditions.checkArgument(!rewrite || target != null);
List<Group> childrenGroups = Lists.newArrayList();
for (NODE_TYPE child : node.children()) {
for (Plan child : node.children()) {
childrenGroups.add(copyIn(child, null, rewrite).getParent());
}
if (node.getGroupExpression().isPresent() && groupExpressions.containsKey(node.getGroupExpression().get())) {
@ -67,7 +65,7 @@ public class Memo<NODE_TYPE extends TreeNode<NODE_TYPE>> {
}
GroupExpression newGroupExpression = new GroupExpression(node.getOperator());
newGroupExpression.setChildren(childrenGroups);
return insertOrRewriteGroupExpression(newGroupExpression, target, rewrite);
return insertOrRewriteGroupExpression(newGroupExpression, target, rewrite, node.getLogicalProperties());
// TODO: need to derive logical property if generate new group. currently we not copy logical plan into
}
@ -82,8 +80,8 @@ public class Memo<NODE_TYPE extends TreeNode<NODE_TYPE>> {
* @param rewrite whether to rewrite the groupExpression to target group
* @return existing groupExpression in memo or newly generated groupExpression
*/
private GroupExpression insertOrRewriteGroupExpression(
GroupExpression groupExpression, Group target, boolean rewrite) {
private GroupExpression insertOrRewriteGroupExpression(GroupExpression groupExpression, Group target,
boolean rewrite, LogicalProperties logicalProperties) {
GroupExpression existedGroupExpression = groupExpressions.get(groupExpression);
if (existedGroupExpression != null) {
if (target != null && !target.getGroupId().equals(existedGroupExpression.getParent().getGroupId())) {
@ -93,13 +91,13 @@ public class Memo<NODE_TYPE extends TreeNode<NODE_TYPE>> {
}
if (target != null) {
if (rewrite) {
GroupExpression oldExpression = target.rewriteLogicalExpression(groupExpression);
GroupExpression oldExpression = target.rewriteLogicalExpression(groupExpression, logicalProperties);
groupExpressions.remove(oldExpression);
} else {
target.addGroupExpression(groupExpression);
}
} else {
Group group = new Group(groupExpression);
Group group = new Group(groupExpression, logicalProperties);
Preconditions.checkArgument(!groups.contains(group), "new group with already exist output");
groups.add(group);
}

View File

@ -34,6 +34,7 @@ public enum OperatorType {
LOGICAL_PROJECT,
LOGICAL_FILTER,
LOGICAL_JOIN,
PLACE_HOLDER,
// physical plan
PHYSICAL_OLAP_SCAN,

View File

@ -27,7 +27,10 @@ import org.apache.doris.nereids.trees.plans.PlaceHolderPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalBinaryPlan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all logical binary operator that have two inputs.
@ -40,16 +43,20 @@ public abstract class LogicalBinaryOperator extends AbstractOperator
}
@Override
public final List<Slot> computeOutput(Plan... inputs) {
return doComputeOutput(inputs[0], inputs[1]);
public final LogicalProperties computeLogicalProperties(Plan... inputs) {
Preconditions.checkArgument(inputs.length == 2);
return new LogicalProperties(computeOutput(inputs[0], inputs[1]));
}
public abstract List<Slot> doComputeOutput(Plan left, Plan right);
public abstract List<Slot> computeOutput(Plan left, Plan right);
@Override
public LogicalBinaryPlan toTreeNode(GroupExpression groupExpression) {
LogicalProperties logicalProperties = groupExpression.getParent().getLogicalProperties();
return new LogicalBinaryPlan(this, groupExpression, logicalProperties,
new PlaceHolderPlan(), new PlaceHolderPlan());
LogicalProperties leftChildProperties = groupExpression.child(0).getLogicalProperties();
LogicalProperties rightChildProperties = groupExpression.child(1).getLogicalProperties();
return new LogicalBinaryPlan(this, Optional.of(groupExpression), Optional.of(logicalProperties),
new PlaceHolderPlan(leftChildProperties), new PlaceHolderPlan(rightChildProperties)
);
}
}

View File

@ -43,7 +43,7 @@ public class LogicalFilter extends LogicalUnaryOperator {
@Override
public List<Slot> doComputeOutput(Plan input) {
public List<Slot> computeOutput(Plan input) {
return input.getOutput();
}

View File

@ -71,7 +71,7 @@ public class LogicalJoin extends LogicalBinaryOperator {
}
@Override
public List<Slot> doComputeOutput(Plan leftInput, Plan rightInput) {
public List<Slot> computeOutput(Plan leftInput, Plan rightInput) {
switch (joinType) {
case LEFT_SEMI_JOIN:
return ImmutableList.copyOf(leftInput.getOutput());

View File

@ -21,11 +21,15 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.AbstractOperator;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.LeafPlanOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalLeafPlan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all logical operator that have no input.
@ -38,14 +42,16 @@ public abstract class LogicalLeafOperator extends AbstractOperator
}
@Override
public final List<Slot> computeOutput(Plan... inputs) {
return doComputeOutput();
public LogicalProperties computeLogicalProperties(Plan... inputs) {
Preconditions.checkArgument(inputs.length == 0);
return new LogicalProperties(computeOutput());
}
public abstract List<Slot> doComputeOutput();
public abstract List<Slot> computeOutput();
@Override
public LogicalLeafPlan toTreeNode(GroupExpression groupExpression) {
return new LogicalLeafPlan(this, groupExpression, groupExpression.getParent().getLogicalProperties());
LogicalProperties logicalProperties = groupExpression.getParent().getLogicalProperties();
return new LogicalLeafPlan(this, Optional.of(groupExpression), Optional.of(logicalProperties));
}
}

View File

@ -18,14 +18,12 @@
package org.apache.doris.nereids.operators.plans.logical;
import org.apache.doris.nereids.operators.plans.PlanOperator;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.plans.Plan;
import java.util.List;
/**
* interface for all concrete logical plan operator.
*/
public interface LogicalOperator extends PlanOperator {
List<Slot> computeOutput(Plan... inputs);
LogicalProperties computeLogicalProperties(Plan... inputs);
}

View File

@ -56,7 +56,7 @@ public class LogicalProject extends LogicalUnaryOperator {
}
@Override
public List<Slot> doComputeOutput(Plan input) {
public List<Slot> computeOutput(Plan input) {
// fixme: not throw a checked exception
return projects.stream()
.map(namedExpr -> {

View File

@ -62,7 +62,7 @@ public class LogicalRelation extends LogicalLeafOperator {
}
@Override
public List<Slot> doComputeOutput() {
public List<Slot> computeOutput() {
return table.getBaseSchema()
.stream()
.map(col -> SlotReference.fromColumn(col, qualifier))

View File

@ -27,7 +27,10 @@ import org.apache.doris.nereids.trees.plans.PlaceHolderPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalUnaryPlan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all logical operator that have one input.
@ -40,15 +43,19 @@ public abstract class LogicalUnaryOperator extends AbstractOperator
}
@Override
public final List<Slot> computeOutput(Plan... inputs) {
return doComputeOutput(inputs[0]);
public LogicalProperties computeLogicalProperties(Plan... inputs) {
Preconditions.checkArgument(inputs.length == 1);
return new LogicalProperties(computeOutput(inputs[0]));
}
public abstract List<Slot> doComputeOutput(Plan input);
public abstract List<Slot> computeOutput(Plan input);
@Override
public LogicalUnaryPlan toTreeNode(GroupExpression groupExpression) {
LogicalProperties logicalProperties = groupExpression.getParent().getLogicalProperties();
return new LogicalUnaryPlan(this, groupExpression, logicalProperties, new PlaceHolderPlan());
LogicalProperties childProperties = groupExpression.child(0).getLogicalProperties();
return new LogicalUnaryPlan(this, Optional.of(groupExpression),
Optional.of(logicalProperties), new PlaceHolderPlan(childProperties)
);
}
}

View File

@ -22,12 +22,10 @@ import org.apache.doris.nereids.operators.AbstractOperator;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.BinaryPlanOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.PlaceHolderPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalBinaryPlan;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all physical operator that have two inputs.
@ -39,19 +37,13 @@ public abstract class PhysicalBinaryOperator extends AbstractOperator
super(type);
}
@Override
public final List<Slot> computeOutputs(LogicalProperties logicalProperties, Plan... inputs) {
return doComputeOutput(logicalProperties, inputs[0], inputs[1]);
}
public List<Slot> doComputeOutput(LogicalProperties logicalProperties, Plan left, Plan right) {
return logicalProperties.getOutput();
}
@Override
public PhysicalBinaryPlan toTreeNode(GroupExpression groupExpression) {
LogicalProperties logicalProperties = groupExpression.getParent().getLogicalProperties();
return new PhysicalBinaryPlan(this, groupExpression, logicalProperties,
new PlaceHolderPlan(), new PlaceHolderPlan());
LogicalProperties leftChildProperties = groupExpression.child(0).getLogicalProperties();
LogicalProperties rightChildProperties = groupExpression.child(1).getLogicalProperties();
return new PhysicalBinaryPlan(this, Optional.of(groupExpression), logicalProperties,
new PlaceHolderPlan(leftChildProperties), new PlaceHolderPlan(rightChildProperties)
);
}
}

View File

@ -22,11 +22,9 @@ import org.apache.doris.nereids.operators.AbstractOperator;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.LeafPlanOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalLeafPlan;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all physical operator that have no input.
@ -38,17 +36,9 @@ public abstract class PhysicalLeafOperator extends AbstractOperator
super(type);
}
@Override
public final List<Slot> computeOutputs(LogicalProperties logicalProperties, Plan... inputs) {
return doComputeOutput(logicalProperties);
}
public List<Slot> doComputeOutput(LogicalProperties logicalProperties) {
return logicalProperties.getOutput();
}
@Override
public PhysicalLeafPlan toTreeNode(GroupExpression groupExpression) {
return new PhysicalLeafPlan(this, groupExpression, groupExpression.getParent().getLogicalProperties());
LogicalProperties logicalProperties = groupExpression.getParent().getLogicalProperties();
return new PhysicalLeafPlan(this, Optional.of(groupExpression), logicalProperties);
}
}

View File

@ -18,17 +18,9 @@
package org.apache.doris.nereids.operators.plans.physical;
import org.apache.doris.nereids.operators.plans.PlanOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import java.util.List;
/**
* interface for all concrete physical operator.
*/
public interface PhysicalOperator extends PlanOperator {
List<Slot> computeOutputs(LogicalProperties logicalProperties, Plan... inputs);
}

View File

@ -22,12 +22,10 @@ import org.apache.doris.nereids.operators.AbstractOperator;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.UnaryPlanOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.PlaceHolderPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalUnaryPlan;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all physical operator that have one input.
@ -39,18 +37,12 @@ public abstract class PhysicalUnaryOperator extends AbstractOperator
super(type);
}
@Override
public final List<Slot> computeOutputs(LogicalProperties logicalProperties, Plan... inputs) {
return doComputeOutput(logicalProperties, inputs[0]);
}
public List<Slot> doComputeOutput(LogicalProperties logicalProperties, Plan input) {
return logicalProperties.getOutput();
}
@Override
public PhysicalUnaryPlan toTreeNode(GroupExpression groupExpression) {
LogicalProperties logicalProperties = groupExpression.getParent().getLogicalProperties();
return new PhysicalUnaryPlan(this, groupExpression, logicalProperties, new PlaceHolderPlan());
LogicalProperties childProperties = groupExpression.child(0).getLogicalProperties();
return new PhysicalUnaryPlan(this, Optional.of(groupExpression),
logicalProperties, new PlaceHolderPlan(childProperties)
);
}
}

View File

@ -229,7 +229,8 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
if (left == null) {
left = right;
} else {
left = new LogicalBinaryPlan(new LogicalJoin(JoinType.INNER_JOIN, null), left, right);
left = new LogicalBinaryPlan(
new LogicalJoin(JoinType.INNER_JOIN, Optional.empty()), left, right);
}
left = withJoinRelations(left, relation);
}

View File

@ -19,6 +19,7 @@ package org.apache.doris.nereids.pattern;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.collect.Lists;
@ -32,17 +33,17 @@ import java.util.Objects;
* TODO: adapt ANY and MULTI
* TODO: add ut
*/
public class GroupExpressionMatching<NODE_TYPE extends TreeNode<NODE_TYPE>> implements Iterable<NODE_TYPE> {
private final Pattern<? extends NODE_TYPE, NODE_TYPE> pattern;
public class GroupExpressionMatching implements Iterable<Plan> {
private final Pattern<? extends Plan, Plan> pattern;
private final GroupExpression groupExpression;
public GroupExpressionMatching(Pattern<? extends NODE_TYPE, NODE_TYPE> pattern, GroupExpression groupExpression) {
public GroupExpressionMatching(Pattern<? extends Plan, Plan> pattern, GroupExpression groupExpression) {
this.pattern = Objects.requireNonNull(pattern);
this.groupExpression = Objects.requireNonNull(groupExpression);
}
@Override
public GroupExpressionIterator<NODE_TYPE> iterator() {
public GroupExpressionIterator<Plan> iterator() {
return new GroupExpressionIterator<>(pattern, groupExpression);
}
@ -97,7 +98,7 @@ public class GroupExpressionMatching<NODE_TYPE extends TreeNode<NODE_TYPE>> impl
for (int i = 0; i < childrenResults.size(); i++) {
children.add(childrenResults.get(i).get(childrenResultsIndex[i]));
}
NODE_TYPE result = root.newChildren(children);
NODE_TYPE result = root.withChildren(children);
results.add(result);
offset = 0;
while (true) {

View File

@ -21,6 +21,7 @@ import org.apache.doris.nereids.memo.Group;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.collect.Lists;
@ -59,18 +60,18 @@ public class GroupMatching<NODE_TYPE extends TreeNode> implements Iterable<NODE_
* @param pattern pattern to match
* @param group group to be matched
*/
public GroupIterator(Pattern<? extends NODE_TYPE, NODE_TYPE> pattern, Group group) {
public GroupIterator(Pattern<? extends Plan, Plan> pattern, Group group) {
this.pattern = pattern;
this.iterator = Lists.newArrayList();
for (GroupExpression groupExpression : group.getLogicalExpressions()) {
GroupExpressionMatching.GroupExpressionIterator<NODE_TYPE> groupExpressionIterator =
GroupExpressionMatching.GroupExpressionIterator groupExpressionIterator =
new GroupExpressionMatching(pattern, groupExpression).iterator();
if (groupExpressionIterator.hasNext()) {
this.iterator.add(groupExpressionIterator);
}
}
for (GroupExpression groupExpression : group.getPhysicalExpressions()) {
GroupExpressionMatching.GroupExpressionIterator<NODE_TYPE> groupExpressionIterator =
GroupExpressionMatching.GroupExpressionIterator groupExpressionIterator =
new GroupExpressionMatching(pattern, groupExpression).iterator();
if (groupExpressionIterator.hasNext()) {
this.iterator.add(groupExpressionIterator);

View File

@ -161,7 +161,8 @@ public class Pattern<TYPE extends NODE_TYPE, NODE_TYPE extends TreeNode<NODE_TYP
}
@Override
public Pattern<? extends NODE_TYPE, NODE_TYPE> newChildren(List<Pattern<? extends NODE_TYPE, NODE_TYPE>> children) {
public Pattern<? extends NODE_TYPE, NODE_TYPE> withChildren(
List<Pattern<? extends NODE_TYPE, NODE_TYPE>> children) {
throw new RuntimeException();
}

View File

@ -206,9 +206,9 @@ public class JavaAstBuilder extends JavaParserBaseVisitor<JavaAstNode> {
} else if (memberCtx.methodDeclaration() != null) {
methodDeclarations.add(visitMethodDeclaration(memberCtx.methodDeclaration()));
}
// find inner class
memberCtx.accept(this);
}
// find inner class
memberCtx.accept(this);
}
String className = getText(ctx.identifier());

View File

@ -36,4 +36,8 @@ public class LogicalProperties {
public List<Slot> getOutput() {
return output;
}
public LogicalProperties withOutput(List<Slot> output) {
return new LogicalProperties(output);
}
}

View File

@ -0,0 +1,40 @@
// 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.doris.nereids.properties;
import org.apache.doris.nereids.exceptions.UnboundException;
import org.apache.doris.nereids.trees.expressions.Slot;
import com.google.common.collect.ImmutableList;
import java.util.List;
/**
* LogicalPlanOperator must compute and return non-null LogicalProperties without exception,
* so UnboundRelation.computeLogicalProperties() return a UnboundLogicalProperties temporary.
*/
public class UnboundLogicalProperties extends LogicalProperties {
public UnboundLogicalProperties() {
super(ImmutableList.of());
}
@Override
public List<Slot> getOutput() {
throw new UnboundException("output");
}
}

View File

@ -24,6 +24,7 @@ import org.apache.doris.nereids.operators.Operator;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
@ -43,7 +44,7 @@ public abstract class AbstractTreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>>
public AbstractTreeNode(NodeType type, NODE_TYPE... children) {
this(type, null, children);
this(type, Optional.empty(), children);
}
/**
@ -53,10 +54,10 @@ public abstract class AbstractTreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>>
* @param groupExpression group expression related to the operator of this node
* @param children children of this node
*/
public AbstractTreeNode(NodeType type, GroupExpression groupExpression, NODE_TYPE... children) {
public AbstractTreeNode(NodeType type, Optional<GroupExpression> groupExpression, NODE_TYPE... children) {
this.type = type;
this.children = ImmutableList.copyOf(children);
this.groupExpression = Optional.ofNullable(groupExpression);
this.groupExpression = Objects.requireNonNull(groupExpression, "groupExpression can not be null");
}
@Override

View File

@ -44,5 +44,5 @@ public interface TreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>> {
int arity();
NODE_TYPE newChildren(List<NODE_TYPE> children);
NODE_TYPE withChildren(List<NODE_TYPE> children);
}

View File

@ -45,7 +45,7 @@ public class EqualTo<LEFT_CHILD_TYPE extends Expression, RIGHT_CHILD_TYPE extend
}
@Override
public EqualTo<Expression, Expression> newChildren(List<Expression> children) {
public EqualTo<Expression, Expression> withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new EqualTo<>(children.get(0), children.get(1));
}

View File

@ -61,7 +61,7 @@ public abstract class Expression extends AbstractTreeNode<Expression> {
}
@Override
public Expression newChildren(List<Expression> children) {
public Expression withChildren(List<Expression> children) {
throw new RuntimeException();
}

View File

@ -50,7 +50,7 @@ public class GreaterThan<LEFT_CHILD_TYPE extends Expression, RIGHT_CHILD_TYPE ex
}
@Override
public GreaterThan<Expression, Expression> newChildren(List<Expression> children) {
public GreaterThan<Expression, Expression> withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new GreaterThan<>(children.get(0), children.get(1));
}

View File

@ -50,7 +50,7 @@ public class GreaterThanEqual<LEFT_CHILD_TYPE extends Expression, RIGHT_CHILD_TY
}
@Override
public GreaterThanEqual<Expression, Expression> newChildren(List<Expression> children) {
public GreaterThanEqual<Expression, Expression> withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new GreaterThanEqual<>(children.get(0), children.get(1));
}

View File

@ -50,7 +50,7 @@ public class LessThan<LEFT_CHILD_TYPE extends Expression, RIGHT_CHILD_TYPE exten
}
@Override
public LessThan<Expression, Expression> newChildren(List<Expression> children) {
public LessThan<Expression, Expression> withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new LessThan<>(children.get(0), children.get(1));
}

View File

@ -50,7 +50,7 @@ public class LessThanEqual<LEFT_CHILD_TYPE extends Expression, RIGHT_CHILD_TYPE
}
@Override
public LessThanEqual<Expression, Expression> newChildren(List<Expression> children) {
public LessThanEqual<Expression, Expression> withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new LessThanEqual<>(children.get(0), children.get(1));
}

View File

@ -47,7 +47,7 @@ public class Not<CHILD_TYPE extends Expression> extends Expression
}
@Override
public Not<Expression> newChildren(List<Expression> children) {
public Not<Expression> withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 1);
return new Not<>(children.get(0));
}

View File

@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.plans;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.PlanOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.AbstractTreeNode;
import org.apache.doris.nereids.trees.NodeType;
@ -27,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* Abstract class for all concrete plan node.
@ -36,14 +38,18 @@ public abstract class AbstractPlan<OP_TYPE extends PlanOperator>
public final OP_TYPE operator;
public AbstractPlan(NodeType type, OP_TYPE operator, Plan... children) {
super(type, children);
this.operator = Objects.requireNonNull(operator, "operator can not be null");
protected final LogicalProperties logicalProperties;
public AbstractPlan(NodeType type, OP_TYPE operator, LogicalProperties logicalProperties, Plan... children) {
this(type, operator, Optional.empty(), logicalProperties, children);
}
public AbstractPlan(NodeType type, OP_TYPE operator, GroupExpression groupExpression, Plan... children) {
/** all parameter constructor. */
public AbstractPlan(NodeType type, OP_TYPE operator, Optional<GroupExpression> groupExpression,
LogicalProperties logicalProperties, Plan... children) {
super(type, groupExpression, children);
this.operator = Objects.requireNonNull(operator, "operator can not be null");
this.logicalProperties = Objects.requireNonNull(logicalProperties, "logicalProperties can not be null");
}
@Override

View File

@ -18,12 +18,17 @@
package org.apache.doris.nereids.trees.plans;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.LeafPlanOperator;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.logical.LogicalLeafOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.logical.LogicalLeafPlan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
@ -31,7 +36,30 @@ import java.util.Optional;
* Used in {@link org.apache.doris.nereids.pattern.GroupExpressionMatching.GroupExpressionIterator},
* as a place-holder when do match root.
*/
public class PlaceHolderPlan implements LeafPlan {
public class PlaceHolderPlan extends LogicalLeafPlan<PlaceHolderPlan.PlaceHolderOperator> {
/** PlaceHolderOperator. */
public static class PlaceHolderOperator extends LogicalLeafOperator {
private final LogicalProperties logicalProperties;
public PlaceHolderOperator(LogicalProperties logicalProperties) {
super(OperatorType.PLACE_HOLDER);
this.logicalProperties = Objects.requireNonNull(logicalProperties, "logicalProperties can not be null");
}
@Override
public List<Slot> computeOutput() {
throw new IllegalStateException("PlaceholderOperator can not compute output");
}
@Override
public LogicalProperties computeLogicalProperties(Plan... inputs) {
throw new IllegalStateException("PlaceholderOperator can not compute logical properties");
}
}
public PlaceHolderPlan(LogicalProperties logicalProperties) {
super(new PlaceHolderOperator(logicalProperties), Optional.empty(), Optional.of(logicalProperties));
}
@Override
public Optional<GroupExpression> getGroupExpression() {
@ -44,37 +72,13 @@ public class PlaceHolderPlan implements LeafPlan {
}
@Override
public Plan newChildren(List children) {
public PlaceHolderPlan withOutput(List<Slot> output) {
throw new RuntimeException();
}
@Override
public LeafPlanOperator getOperator() {
throw new RuntimeException();
}
@Override
public LogicalProperties getLogicalProperties() {
throw new RuntimeException();
}
@Override
public List<Slot> getOutput() {
throw new RuntimeException();
}
@Override
public String treeString() {
throw new RuntimeException();
}
@Override
public List<Plan> children() {
throw new RuntimeException();
}
@Override
public Plan child(int index) {
throw new RuntimeException();
public PlaceHolderPlan withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 0);
return new PlaceHolderPlan(logicalProperties);
}
}

View File

@ -37,4 +37,5 @@ public interface Plan extends TreeNode<Plan> {
String treeString();
Plan withOutput(List<Slot> output);
}

View File

@ -25,8 +25,8 @@ import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.AbstractPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all concrete logical plan.
@ -34,17 +34,19 @@ import java.util.List;
public abstract class AbstractLogicalPlan<OP_TYPE extends LogicalOperator>
extends AbstractPlan<OP_TYPE> implements LogicalPlan {
protected final LogicalProperties logicalProperties;
public AbstractLogicalPlan(NodeType type, OP_TYPE operator, Plan... children) {
super(type, operator, children);
this.logicalProperties = new LogicalProperties(Collections.emptyList());
super(type, operator, operator.computeLogicalProperties(children), children);
}
public AbstractLogicalPlan(NodeType type, OP_TYPE operator,
GroupExpression groupExpression, LogicalProperties logicalProperties, Plan... children) {
super(type, operator, groupExpression, children);
this.logicalProperties = logicalProperties;
Optional<LogicalProperties> logicalProperties, Plan... children) {
super(type, operator, logicalProperties.orElseGet(() -> operator.computeLogicalProperties(children)), children);
}
public AbstractLogicalPlan(NodeType type, OP_TYPE operator, Optional<GroupExpression> groupExpression,
Optional<LogicalProperties> logicalProperties, Plan... children) {
super(type, operator, groupExpression,
logicalProperties.orElseGet(() -> operator.computeLogicalProperties(children)), children);
}
@Override

View File

@ -21,12 +21,14 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.logical.LogicalBinaryOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.BinaryPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all logical plan that have two children.
@ -39,18 +41,29 @@ public class LogicalBinaryPlan<
implements BinaryPlan<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
public LogicalBinaryPlan(OP_TYPE operator, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(NodeType.LOGICAL, operator, leftChild, rightChild);
super(NodeType.LOGICAL, operator, Optional.empty(), leftChild, rightChild);
}
public LogicalBinaryPlan(OP_TYPE operator, GroupExpression groupExpression, LogicalProperties logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
public LogicalBinaryPlan(OP_TYPE operator, Optional<LogicalProperties> logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(NodeType.LOGICAL, operator, logicalProperties, leftChild, rightChild);
}
public LogicalBinaryPlan(OP_TYPE operator, Optional<GroupExpression> groupExpression,
Optional<LogicalProperties> logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(NodeType.LOGICAL, operator, groupExpression, logicalProperties, leftChild, rightChild);
}
@Override
public LogicalBinaryPlan<OP_TYPE, Plan, Plan> newChildren(List<Plan> children) {
public LogicalBinaryPlan<OP_TYPE, Plan, Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 2);
return new LogicalBinaryPlan(operator, groupExpression.orElse(null),
logicalProperties, children.get(0), children.get(1));
return new LogicalBinaryPlan(operator, groupExpression, Optional.empty(),
children.get(0), children.get(1));
}
@Override
public LogicalBinaryPlan<OP_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> withOutput(List<Slot> output) {
return new LogicalBinaryPlan<>(operator, groupExpression,
Optional.of(logicalProperties.withOutput(output)), left(), right());
}
}

View File

@ -21,12 +21,14 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.logical.LogicalLeafOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.LeafPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all logical plan that have no child.
@ -39,13 +41,24 @@ public class LogicalLeafPlan<OP_TYPE extends LogicalLeafOperator>
super(NodeType.LOGICAL, operator);
}
public LogicalLeafPlan(OP_TYPE operator, GroupExpression groupExpression, LogicalProperties logicalProperties) {
public LogicalLeafPlan(OP_TYPE operator, Optional<LogicalProperties> logicalProperties) {
super(NodeType.LOGICAL, operator, logicalProperties);
}
public LogicalLeafPlan(OP_TYPE operator, Optional<GroupExpression> groupExpression,
Optional<LogicalProperties> logicalProperties) {
super(NodeType.LOGICAL, operator, groupExpression, logicalProperties);
}
@Override
public LogicalLeafPlan<OP_TYPE> newChildren(List<Plan> children) {
public LogicalLeafPlan<OP_TYPE> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 0);
return new LogicalLeafPlan(operator, groupExpression.orElse(null), logicalProperties);
return new LogicalLeafPlan(operator, groupExpression, Optional.empty());
}
@Override
public LogicalLeafPlan<OP_TYPE> withOutput(List<Slot> output) {
return new LogicalLeafPlan<>(operator, groupExpression,
Optional.of(logicalProperties.withOutput(output)));
}
}

View File

@ -32,7 +32,7 @@ public interface LogicalPlan extends Plan {
LogicalOperator getOperator();
@Override
LogicalPlan newChildren(List<Plan> children);
LogicalPlan withChildren(List<Plan> children);
/**
* Map a [[LogicalPlan]] to another [[LogicalPlan]] if the passed context exists using the

View File

@ -21,12 +21,14 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.logical.LogicalUnaryOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.UnaryPlan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all logical plan that have one child.
@ -39,14 +41,20 @@ public class LogicalUnaryPlan<OP_TYPE extends LogicalUnaryOperator, CHILD_TYPE e
super(NodeType.LOGICAL, operator, child);
}
public LogicalUnaryPlan(OP_TYPE operator, GroupExpression groupExpression, LogicalProperties logicalProperties,
CHILD_TYPE child) {
public LogicalUnaryPlan(OP_TYPE operator, Optional<GroupExpression> groupExpression,
Optional<LogicalProperties> logicalProperties, CHILD_TYPE child) {
super(NodeType.LOGICAL, operator, groupExpression, logicalProperties, child);
}
@Override
public LogicalUnaryPlan<OP_TYPE, Plan> newChildren(List<Plan> children) {
public LogicalUnaryPlan<OP_TYPE, Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 1);
return new LogicalUnaryPlan(operator, groupExpression.orElse(null), logicalProperties, children.get(0));
return new LogicalUnaryPlan(operator, groupExpression, Optional.empty(), children.get(0));
}
@Override
public LogicalUnaryPlan<OP_TYPE, CHILD_TYPE> withOutput(List<Slot> output) {
return new LogicalUnaryPlan<>(operator, groupExpression,
Optional.of(logicalProperties.withOutput(output)), child());
}
}

View File

@ -27,7 +27,7 @@ import org.apache.doris.nereids.trees.plans.AbstractPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* Abstract class for all concrete physical plan.
@ -36,7 +36,6 @@ public abstract class AbstractPhysicalPlan<OP_TYPE extends PhysicalOperator>
extends AbstractPlan<OP_TYPE>
implements PhysicalPlan {
protected final LogicalProperties logicalProperties;
protected final PhysicalProperties physicalProperties;
/**
@ -44,8 +43,7 @@ public abstract class AbstractPhysicalPlan<OP_TYPE extends PhysicalOperator>
*/
public AbstractPhysicalPlan(NodeType type, OP_TYPE operator,
LogicalProperties logicalProperties, Plan... children) {
super(type, operator, children);
this.logicalProperties = Objects.requireNonNull(logicalProperties, "logicalProperties can not be null");
super(type, operator, logicalProperties, children);
// TODO: compute physical properties
this.physicalProperties = new PhysicalProperties();
}
@ -59,10 +57,9 @@ public abstract class AbstractPhysicalPlan<OP_TYPE extends PhysicalOperator>
* @param logicalProperties logical properties of this plan
* @param children children of this plan
*/
public AbstractPhysicalPlan(NodeType type, OP_TYPE operator, GroupExpression groupExpression,
public AbstractPhysicalPlan(NodeType type, OP_TYPE operator, Optional<GroupExpression> groupExpression,
LogicalProperties logicalProperties, Plan... children) {
super(type, operator, groupExpression, children);
this.logicalProperties = Objects.requireNonNull(logicalProperties, "logicalProperties can not be null");
super(type, operator, groupExpression, logicalProperties, children);
// TODO: compute physical properties
this.physicalProperties = new PhysicalProperties();
}

View File

@ -21,12 +21,14 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.physical.PhysicalBinaryOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.BinaryPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all physical plan that have two children.
@ -43,15 +45,21 @@ public class PhysicalBinaryPlan<
super(NodeType.PHYSICAL, operator, logicalProperties, leftChild, rightChild);
}
public PhysicalBinaryPlan(OP_TYPE operator, GroupExpression groupExpression, LogicalProperties logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
public PhysicalBinaryPlan(OP_TYPE operator, Optional<GroupExpression> groupExpression,
LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(NodeType.PHYSICAL, operator, groupExpression, logicalProperties, leftChild, rightChild);
}
@Override
public PhysicalBinaryPlan<OP_TYPE, Plan, Plan> newChildren(List<Plan> children) {
public PhysicalBinaryPlan<OP_TYPE, Plan, Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 2);
return new PhysicalBinaryPlan(operator, groupExpression.orElse(null), logicalProperties,
children.get(0), children.get(1));
return new PhysicalBinaryPlan(operator, groupExpression, logicalProperties,
children.get(0), children.get(1));
}
@Override
public PhysicalBinaryPlan<OP_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> withOutput(List<Slot> output) {
LogicalProperties logicalProperties = new LogicalProperties(output);
return new PhysicalBinaryPlan<>(operator, groupExpression, logicalProperties, left(), right());
}
}

View File

@ -21,12 +21,14 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.physical.PhysicalLeafOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.LeafPlan;
import org.apache.doris.nereids.trees.plans.Plan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all physical plan that have no child.
@ -39,13 +41,20 @@ public class PhysicalLeafPlan<OP_TYPE extends PhysicalLeafOperator>
super(NodeType.PHYSICAL, operator, logicalProperties);
}
public PhysicalLeafPlan(OP_TYPE operator, GroupExpression groupExpression, LogicalProperties logicalProperties) {
public PhysicalLeafPlan(OP_TYPE operator, Optional<GroupExpression> groupExpression,
LogicalProperties logicalProperties) {
super(NodeType.PHYSICAL, operator, groupExpression, logicalProperties);
}
@Override
public PhysicalLeafPlan<OP_TYPE> newChildren(List<Plan> children) {
public PhysicalLeafPlan<OP_TYPE> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 0);
return new PhysicalLeafPlan(operator, groupExpression.orElse(null), logicalProperties);
return new PhysicalLeafPlan(operator, groupExpression, logicalProperties);
}
@Override
public PhysicalLeafPlan<OP_TYPE> withOutput(List<Slot> output) {
LogicalProperties logicalProperties = new LogicalProperties(output);
return new PhysicalLeafPlan<>(operator, groupExpression, logicalProperties);
}
}

View File

@ -21,12 +21,14 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.operators.plans.physical.PhysicalUnaryOperator;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.NodeType;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.UnaryPlan;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Abstract class for all physical plan that have one child.
@ -39,15 +41,20 @@ public class PhysicalUnaryPlan<OP_TYPE extends PhysicalUnaryOperator, CHILD_TYPE
super(NodeType.PHYSICAL, operator, logicalProperties, child);
}
public PhysicalUnaryPlan(OP_TYPE operator, GroupExpression groupExpression, LogicalProperties logicalProperties,
CHILD_TYPE child) {
public PhysicalUnaryPlan(OP_TYPE operator, Optional<GroupExpression> groupExpression,
LogicalProperties logicalProperties, CHILD_TYPE child) {
super(NodeType.PHYSICAL, operator, groupExpression, logicalProperties, child);
}
@Override
public PhysicalUnaryPlan<OP_TYPE, Plan> newChildren(List<Plan> children) {
public PhysicalUnaryPlan<OP_TYPE, Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 1);
return new PhysicalUnaryPlan(operator, groupExpression.orElse(null),
logicalProperties, (Plan) children.get(0));
return new PhysicalUnaryPlan(operator, groupExpression, logicalProperties, children.get(0));
}
@Override
public PhysicalUnaryPlan<OP_TYPE, CHILD_TYPE> withOutput(List<Slot> output) {
LogicalProperties logicalProperties = new LogicalProperties(output);
return new PhysicalUnaryPlan<>(operator, groupExpression, logicalProperties, child());
}
}

View File

@ -17,7 +17,9 @@
package org.apache.doris.nereids.jobs;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.Table;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.nereids.OptimizerContext;
import org.apache.doris.nereids.PlannerContext;
@ -33,9 +35,14 @@ import org.apache.doris.nereids.properties.PhysicalProperties;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.Plans;
import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.StringType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -47,7 +54,10 @@ public class RewriteTopDownJobTest implements Plans {
@Override
public Rule<Plan> build() {
return unboundRelation().then(unboundRelation -> plan(
new LogicalRelation(new OlapTable(), Lists.newArrayList("test"))
new LogicalRelation(new Table(0, "test", Table.TableType.OLAP, ImmutableList.of(
new Column("id", Type.INT),
new Column("name", Type.STRING)
)), Lists.newArrayList("test"))
)).toRule(RuleType.BINDING_UNBOUND_RELATION_RULE);
}
}
@ -56,24 +66,37 @@ public class RewriteTopDownJobTest implements Plans {
public void testSimplestScene() throws AnalysisException {
UnboundRelation unboundRelation = new UnboundRelation(Lists.newArrayList("test"));
Plan leaf = plan(unboundRelation);
LogicalProject project = new LogicalProject(Lists.newArrayList());
LogicalProject project = new LogicalProject(ImmutableList.of(
new SlotReference("name", StringType.INSTANCE, true, ImmutableList.of("test")))
);
Plan root = plan(project, leaf);
Memo<Plan> memo = new Memo();
Memo memo = new Memo();
memo.initialize(root);
OptimizerContext<Plan> optimizerContext = new OptimizerContext<>(memo);
OptimizerContext optimizerContext = new OptimizerContext(memo);
PlannerContext plannerContext = new PlannerContext(optimizerContext, null, new PhysicalProperties());
List<Rule<Plan>> fakeRules = Lists.newArrayList(new FakeRule().build());
RewriteTopDownJob<Plan> rewriteTopDownJob = new RewriteTopDownJob<>(memo.getRoot(), fakeRules, plannerContext);
RewriteTopDownJob rewriteTopDownJob = new RewriteTopDownJob(memo.getRoot(), fakeRules, plannerContext);
plannerContext.getOptimizerContext().pushJob(rewriteTopDownJob);
plannerContext.getOptimizerContext().getJobScheduler().executeJobPool(plannerContext);
Group rootGroup = memo.getRoot();
Assertions.assertEquals(1, rootGroup.getLogicalExpressions().size());
GroupExpression rootGroupExpression = rootGroup.getLogicalExpression();
List<Slot> output = rootGroup.getLogicalProperties().getOutput();
Assertions.assertEquals(output.size(), 1);
Assertions.assertEquals(output.get(0).getName(), "name");
Assertions.assertEquals(output.get(0).getDataType(), StringType.INSTANCE);
Assertions.assertEquals(1, rootGroupExpression.children().size());
Assertions.assertEquals(OperatorType.LOGICAL_PROJECT, rootGroupExpression.getOperator().getType());
Group leafGroup = rootGroupExpression.child(0);
output = leafGroup.getLogicalProperties().getOutput();
Assertions.assertEquals(output.size(), 2);
Assertions.assertEquals(output.get(0).getName(), "id");
Assertions.assertEquals(output.get(0).getDataType(), IntegerType.INSTANCE);
Assertions.assertEquals(output.get(1).getName(), "name");
Assertions.assertEquals(output.get(1).getDataType(), StringType.INSTANCE);
Assertions.assertEquals(1, leafGroup.getLogicalExpressions().size());
GroupExpression leafGroupExpression = leafGroup.getLogicalExpression();
Assertions.assertEquals(OperatorType.LOGICAL_BOUND_RELATION, leafGroupExpression.getOperator().getType());

View File

@ -38,10 +38,10 @@ public class GroupExpressionMatchingTest implements Plans {
UnboundRelation unboundRelation = new UnboundRelation(Lists.newArrayList("test"));
Plan plan = plan(unboundRelation);
Memo<Plan> memo = new Memo<>();
Memo memo = new Memo();
memo.initialize(plan);
GroupExpressionMatching<Plan> groupExpressionMatching
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(pattern, memo.getRoot().getLogicalExpression());
Iterator<Plan> iterator = groupExpressionMatching.iterator();
@ -60,15 +60,15 @@ public class GroupExpressionMatchingTest implements Plans {
Plan leaf = plan(unboundRelation);
LogicalProject project = new LogicalProject(Lists.newArrayList());
Plan root = plan(project, leaf);
Memo<Plan> memo = new Memo();
Memo memo = new Memo();
memo.initialize(root);
UnboundRelation anotherUnboundRelation = new UnboundRelation(Lists.newArrayList("test2"));
Plan anotherLeaf = plan(anotherUnboundRelation);
memo.copyIn(anotherLeaf, memo.getRoot().getLogicalExpression().child(0), false);
GroupExpressionMatching<Plan> groupExpressionMatching
= new GroupExpressionMatching<>(pattern, memo.getRoot().getLogicalExpression());
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(pattern, memo.getRoot().getLogicalExpression());
Iterator<Plan> iterator = groupExpressionMatching.iterator();
Assertions.assertTrue(iterator.hasNext());
@ -93,15 +93,15 @@ public class GroupExpressionMatchingTest implements Plans {
Plan leaf = plan(unboundRelation);
LogicalProject project = new LogicalProject(Lists.newArrayList());
Plan root = plan(project, leaf);
Memo<Plan> memo = new Memo();
Memo memo = new Memo();
memo.initialize(root);
UnboundRelation anotherUnboundRelation = new UnboundRelation(Lists.newArrayList("test2"));
Plan anotherLeaf = plan(anotherUnboundRelation);
memo.copyIn(anotherLeaf, memo.getRoot().getLogicalExpression().child(0), false);
GroupExpressionMatching<Plan> groupExpressionMatching
= new GroupExpressionMatching<>(pattern, memo.getRoot().getLogicalExpression());
GroupExpressionMatching groupExpressionMatching
= new GroupExpressionMatching(pattern, memo.getRoot().getLogicalExpression());
Iterator<Plan> iterator = groupExpressionMatching.iterator();
Assertions.assertTrue(iterator.hasNext());

View File

@ -0,0 +1,102 @@
// 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.doris.nereids.plan;
import org.apache.doris.catalog.AggregateType;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.Table;
import org.apache.doris.catalog.Type;
import org.apache.doris.nereids.analyzer.UnboundRelation;
import org.apache.doris.nereids.exceptions.UnboundException;
import org.apache.doris.nereids.operators.OperatorType;
import org.apache.doris.nereids.operators.plans.logical.LogicalRelation;
import org.apache.doris.nereids.operators.plans.physical.PhysicalScan;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plans;
import org.apache.doris.nereids.trees.plans.logical.LogicalLeafPlan;
import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.StringType;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import java.util.List;
public class TestPlanOutput implements Plans {
@Test
public void testComputeOutput() {
Table table = new Table(0L, "a", Table.TableType.OLAP, ImmutableList.<Column>of(
new Column("id", Type.INT, true, AggregateType.NONE, "0", ""),
new Column("name", Type.STRING, true, AggregateType.NONE, "", "")
));
LogicalLeafPlan<LogicalRelation> relationPlan = plan(
new LogicalRelation(table, ImmutableList.of("a"))
);
List<Slot> output = relationPlan.getOutput();
Assertions.assertTrue(output.size() == 2);
Assertions.assertEquals(output.get(0).getName(), "id");
Assertions.assertEquals(output.get(0).getQualifiedName(), "a.id");
Assertions.assertEquals(output.get(0).getDataType(), IntegerType.INSTANCE);
Assertions.assertEquals(output.get(1).getName(), "name");
Assertions.assertEquals(output.get(1).getQualifiedName(), "a.name");
Assertions.assertEquals(output.get(1).getDataType(), StringType.INSTANCE);
}
@Test
public void testLazyComputeOutput() {
// not throw exception when create new UnboundRelation
LogicalLeafPlan<UnboundRelation> relationPlan = plan(
new UnboundRelation(ImmutableList.of("a"))
);
try {
// throw exception when getOutput
relationPlan.getOutput();
throw new IllegalStateException("Expect an UnboundException but no exception");
} catch (UnboundException e) {
// correct exception
}
}
@Test
public void testWithOutput() {
Table table = new Table(0L, "a", Table.TableType.OLAP, ImmutableList.of(
new Column("id", Type.INT, true, AggregateType.NONE, "0", ""),
new Column("name", Type.STRING, true, AggregateType.NONE, "", "")
));
LogicalLeafPlan<LogicalRelation> relationPlan = plan(
new LogicalRelation(table, ImmutableList.of("a"))
);
List<Slot> output = relationPlan.getOutput();
// column prune
LogicalLeafPlan<LogicalRelation> newPlan = relationPlan.withOutput(ImmutableList.of(output.get(0)));
output = newPlan.getOutput();
Assertions.assertTrue(output.size() == 1);
Assertions.assertEquals(output.get(0).getName(), "id");
Assertions.assertEquals(output.get(0).getQualifiedName(), "a.id");
Assertions.assertEquals(output.get(0).getDataType(), IntegerType.INSTANCE);
}
@Test(expected = NullPointerException.class)
public void testPhysicalPlanMustHaveLogicalProperties() {
plan(new PhysicalScan(OperatorType.PHYSICAL_OLAP_SCAN, ImmutableList.of("tbl")) {}, null);
}
}