You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by li...@apache.org on 2022/05/08 08:56:08 UTC

[incubator-doris] branch master updated: [Enhancement](Optimizer) Optimize nereids tree node structure (#9446)

This is an automated email from the ASF dual-hosted git repository.

lingmiao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 52a2db18c0 [Enhancement](Optimizer) Optimize nereids tree node structure (#9446)
52a2db18c0 is described below

commit 52a2db18c025a6c96e10ff7ff93b4377ad8c0494
Author: 924060929 <92...@qq.com>
AuthorDate: Sun May 8 16:56:00 2022 +0800

    [Enhancement](Optimizer) Optimize nereids tree node structure (#9446)
    
    This pr optimize nereids tree node structure for generic parameter and Nary abstract tree node.
    It can facilitate the use of pattern match framework.
---
 .gitignore                                         |  1 +
 .../doris/nereids/analyzer/UnboundAlias.java       | 13 ++--
 .../doris/nereids/analyzer/UnboundRelation.java    |  2 +-
 .../apache/doris/nereids/analyzer/UnboundSlot.java |  4 +-
 .../apache/doris/nereids/analyzer/UnboundStar.java |  3 +-
 .../doris/nereids/jobs/cascades/ApplyRuleJob.java  |  3 +-
 .../nereids/jobs/cascades/ExplorePlanJob.java      |  6 +-
 .../nereids/jobs/cascades/OptimizePlanJob.java     |  6 +-
 .../java/org/apache/doris/nereids/memo/Group.java  |  5 +-
 .../java/org/apache/doris/nereids/memo/Memo.java   |  2 +-
 .../org/apache/doris/nereids/pattern/Pattern.java  | 11 ++-
 .../analysis/AnalysisUnboundRelationRule.java      |  4 +-
 .../implementation/LogicalJoinToHashJoinRule.java  | 17 +++--
 .../trees/{TreeNode.java => AbstractTreeNode.java} | 46 ++++++-------
 .../logical/LogicalUnary.java => BinaryNode.java}  | 26 ++++----
 .../logical/LogicalLeaf.java => LeafNode.java}     | 14 ++--
 .../org/apache/doris/nereids/trees/TreeNode.java   | 43 ++----------
 .../{expressions/Slot.java => UnaryNode.java}      | 20 +++---
 .../{Expression.java => AbstractExpression.java}   | 23 +++++--
 .../doris/nereids/trees/expressions/Alias.java     | 18 +++--
 .../{Slot.java => BinaryExpression.java}           | 18 ++---
 .../nereids/trees/expressions/BinaryPredicate.java | 21 +++---
 .../nereids/trees/expressions/Expression.java      | 32 +++++----
 .../expressions/{Slot.java => LeafExpression.java} | 15 ++---
 .../doris/nereids/trees/expressions/Literal.java   |  2 +-
 .../nereids/trees/expressions/NamedExpression.java | 40 ++++++-----
 .../doris/nereids/trees/expressions/Slot.java      |  7 +-
 .../nereids/trees/expressions/SlotReference.java   |  4 +-
 .../{Slot.java => UnaryExpression.java}            | 17 ++---
 .../trees/plans/{Plan.java => AbstractPlan.java}   | 47 +++++++------
 .../{logical/LogicalUnary.java => BinaryPlan.java} | 27 ++++----
 .../{logical/LogicalLeaf.java => LeafPlan.java}    | 20 ++++--
 .../org/apache/doris/nereids/trees/plans/Plan.java | 78 +++-------------------
 .../{logical/LogicalUnary.java => UnaryPlan.java}  | 27 ++++----
 .../{LogicalLeaf.java => AbstractLogicalPlan.java} | 16 ++---
 .../nereids/trees/plans/logical/LogicalBinary.java | 37 +++-------
 .../nereids/trees/plans/logical/LogicalFilter.java |  7 +-
 .../nereids/trees/plans/logical/LogicalJoin.java   |  9 ++-
 .../nereids/trees/plans/logical/LogicalLeaf.java   | 13 ++--
 .../nereids/trees/plans/logical/LogicalPlan.java   | 15 +++--
 .../trees/plans/logical/LogicalProject.java        |  9 ++-
 .../trees/plans/logical/LogicalRelation.java       |  3 +-
 .../nereids/trees/plans/logical/LogicalUnary.java  | 23 +++----
 ...PhysicalPlan.java => AbstractPhysicalPlan.java} | 13 ++--
 .../{PhysicalPlan.java => PhysicalBinary.java}     | 30 +++------
 .../plans/physical/PhysicalBroadcastHashJoin.java  | 13 +++-
 .../trees/plans/physical/PhysicalFilter.java       |  9 ++-
 .../PhysicalLeaf.java}                             | 17 +++--
 .../trees/plans/physical/PhysicalOlapScan.java     |  2 +-
 .../nereids/trees/plans/physical/PhysicalPlan.java | 25 ++-----
 .../trees/plans/physical/PhysicalProject.java      |  9 ++-
 .../nereids/trees/plans/physical/PhysicalScan.java |  4 +-
 .../PhysicalUnary.java}                            | 20 +++---
 53 files changed, 414 insertions(+), 482 deletions(-)

diff --git a/.gitignore b/.gitignore
index 9a42e446d6..b4ca5eea74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ samples/doris-demo/remote-udf-cpp-demo/function_server_demo
 
 # FE
 fe/mocked/
+fe/fe-core/gen/
 fe/fe-core/src/main/resources/static/
 
 # BE
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java
index 0681381003..e86923fa8a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java
@@ -22,18 +22,19 @@ import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.UnaryExpression;
 
 import java.util.List;
 
 /**
  * Expression for unbound alias.
  */
-public class UnboundAlias extends NamedExpression {
-    private final Expression child;
+public class UnboundAlias<CHILD_TYPE extends Expression<CHILD_TYPE>>
+        extends UnaryExpression<UnboundAlias<CHILD_TYPE>, CHILD_TYPE>
+        implements NamedExpression<UnboundAlias<CHILD_TYPE>> {
 
-    public UnboundAlias(Expression child) {
-        super(NodeType.UNBOUND_ALIAS);
-        this.child = child;
+    public UnboundAlias(CHILD_TYPE child) {
+        super(NodeType.UNBOUND_ALIAS, child);
     }
 
     @Override
@@ -58,6 +59,6 @@ public class UnboundAlias extends NamedExpression {
 
     @Override
     public String toString() {
-        return "UnboundAlias(" + child + ", None)";
+        return "UnboundAlias(" + child() + ", None)";
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
index 45a91682ed..57cce5345f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
@@ -32,7 +32,7 @@ import java.util.List;
 /**
  * Represent a relation plan node that has not been bound.
  */
-public class UnboundRelation extends LogicalLeaf {
+public class UnboundRelation extends LogicalLeaf<UnboundRelation> {
     private final List<String> nameParts;
 
     public UnboundRelation(List<String> nameParts) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java
index 739dac5333..230d015d3a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java
@@ -21,14 +21,14 @@ import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.util.Utils;
 
-import com.alibaba.google.common.collect.Lists;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
 /**
  * Slot has not been bound.
  */
-public class UnboundSlot extends Slot {
+public class UnboundSlot extends Slot<UnboundSlot> {
     private final List<String> nameParts;
 
     public UnboundSlot(List<String> nameParts) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java
index 6b345c59ff..d94d1df637 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java
@@ -18,6 +18,7 @@
 package org.apache.doris.nereids.analyzer;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.LeafExpression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.util.Utils;
 
@@ -28,7 +29,7 @@ import java.util.List;
 /**
  * Star expression.
  */
-public class UnboundStar extends NamedExpression {
+public class UnboundStar extends LeafExpression<UnboundStar> implements NamedExpression<UnboundStar> {
     private final List<String> target;
 
     public UnboundStar(List<String> target) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
index 69dba02425..627594a694 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
@@ -25,6 +25,7 @@ import org.apache.doris.nereids.memo.PlanReference;
 import org.apache.doris.nereids.pattern.PatternMatching;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 
 import java.util.List;
 
@@ -67,7 +68,7 @@ public class ApplyRuleJob extends Job {
                 PlanReference newReference = context.getOptimizerContext().getMemo()
                         .newPlanReference(newPlan, planReference.getParent());
                 // TODO need to check return is a new Reference, other wise will be into a dead loop
-                if (newPlan.isLogical()) {
+                if (newPlan instanceof LogicalPlan) {
                     pushTask(new DeriveStatsJob(newReference, context));
                     if (exploredOnly) {
                         pushTask(new ExplorePlanJob(newReference, context));
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java
index a987f6825d..9c84534ad1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java
@@ -53,9 +53,9 @@ public class ExplorePlanJob extends Job {
 
         for (Rule rule : explorationRules) {
             pushTask(new ApplyRuleJob(planReference, rule, context));
-            for (int i = 0; i < rule.getPattern().getChildren().size(); ++i) {
-                Pattern childPattern = rule.getPattern().getChild(i);
-                if (!childPattern.getChildren().isEmpty()) {
+            for (int i = 0; i < rule.getPattern().children().size(); ++i) {
+                Pattern childPattern = rule.getPattern().child(i);
+                if (!childPattern.children().isEmpty()) {
                     Group childSet = planReference.getChildren().get(i);
                     pushTask(new ExploreGroupJob(childSet, context));
                 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java
index b9e2e38324..e3337b06b0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java
@@ -57,9 +57,9 @@ public class OptimizePlanJob extends Job {
 
             // If child_pattern has any more children (i.e non-leaf), then we will explore the
             // child before applying the rule. (assumes task pool is effectively a stack)
-            for (int i = 0; i < rule.getPattern().getChildren().size(); ++i) {
-                Pattern childPattern = rule.getPattern().getChild(i);
-                if (!childPattern.getChildren().isEmpty()) {
+            for (int i = 0; i < rule.getPattern().children().size(); ++i) {
+                Pattern childPattern = rule.getPattern().child(i);
+                if (!childPattern.children().isEmpty()) {
                     Group childSet = planReference.getChildren().get(i);
                     pushTask(new ExploreGroupJob(childSet, context));
                 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
index 8e64d36190..8a4555548e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
@@ -21,6 +21,7 @@ import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 
 import com.clearspring.analytics.util.Lists;
 import org.springframework.util.CollectionUtils;
@@ -49,7 +50,7 @@ public class Group {
      * @param planReference first {@link PlanReference} in this Group
      */
     public Group(PlanReference planReference) {
-        if (planReference.getPlan().isLogical()) {
+        if (planReference.getPlan() instanceof LogicalPlan) {
             this.logicalPlanList.add(planReference);
         } else {
             this.physicalPlanList.add(planReference);
@@ -74,7 +75,7 @@ public class Group {
      * @return added {@link PlanReference}
      */
     public PlanReference addPlanReference(PlanReference planReference) {
-        if (planReference.getPlan().isLogical()) {
+        if (planReference.getPlan() instanceof LogicalPlan) {
             logicalPlanList.add(planReference);
         } else {
             physicalPlanList.add(planReference);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
index 0da9a4dcdb..a5ce5432bb 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
@@ -53,7 +53,7 @@ public class Memo {
             return plan.getPlanReference();
         }
         List<PlanReference> childReferences = Lists.newArrayList();
-        for (Plan<?> childrenPlan : plan.getChildren()) {
+        for (Plan<?> childrenPlan : plan.children()) {
             childReferences.add(newPlanReference(childrenPlan, null));
         }
         PlanReference newPlanReference = new PlanReference(plan);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
index 42467e155c..ae166af3e8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
@@ -17,8 +17,8 @@
 
 package org.apache.doris.nereids.pattern;
 
+import org.apache.doris.nereids.trees.AbstractTreeNode;
 import org.apache.doris.nereids.trees.NodeType;
-import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.trees.plans.Plan;
 
 import java.util.Objects;
@@ -26,7 +26,7 @@ import java.util.Objects;
 /**
  * Pattern node used in pattern matching.
  */
-public class Pattern extends TreeNode<Pattern> {
+public class Pattern extends AbstractTreeNode<Pattern> {
     public static final Pattern PATTERN_MULTI_LEAF_INSTANCE = new Pattern(NodeType.PATTERN_MULTI_LEAF);
     public static final Pattern PATTERN_LEAF_INSTANCE = new Pattern(NodeType.PATTERN_LEAF);
 
@@ -39,11 +39,8 @@ public class Pattern extends TreeNode<Pattern> {
      * @param children sub pattern
      */
     public Pattern(NodeType nodeType, Pattern... children) {
-        super(NodeType.PATTERN);
+        super(NodeType.PATTERN, children);
         this.nodeType = nodeType;
-        for (Pattern child : children) {
-            addChild(child);
-        }
     }
 
     /**
@@ -66,7 +63,7 @@ public class Pattern extends TreeNode<Pattern> {
             return false;
         }
 
-        if (plan.getChildren().size() < this.getChildren().size() && children.contains(PATTERN_MULTI_LEAF_INSTANCE)) {
+        if (plan.children().size() < this.children().size() && children.contains(PATTERN_MULTI_LEAF_INSTANCE)) {
             return false;
         }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java
index 329d43db02..5444196b11 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java
@@ -29,8 +29,8 @@ import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
 
-import com.alibaba.google.common.collect.ImmutableList;
-import com.alibaba.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java
index 796114ec44..9f93ee267c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java
@@ -17,15 +17,12 @@
 
 package org.apache.doris.nereids.rules.implementation;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.doris.nereids.PlannerContext;
 import org.apache.doris.nereids.pattern.Pattern;
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
-import org.apache.doris.nereids.trees.plans.physical.PhysicalBroadcastHashJoin;
-
-import com.google.common.collect.Lists;
 
 import java.util.List;
 
@@ -45,10 +42,12 @@ public class LogicalJoinToHashJoinRule extends ImplementationRule {
 
     @Override
     public List<Plan<?>> transform(Plan<?> plan, PlannerContext context) {
-        LogicalJoin originPlan = (LogicalJoin) plan;
-        PhysicalBroadcastHashJoin physicalBroadcastHashJoin = new PhysicalBroadcastHashJoin(
-                originPlan.getJoinType(),
-                originPlan.getOnClause());
-        return Lists.newArrayList(physicalBroadcastHashJoin);
+        // LogicalJoin originPlan = (LogicalJoin) plan;
+        // PhysicalBroadcastHashJoin physicalBroadcastHashJoin = new PhysicalBroadcastHashJoin(
+        //         originPlan.getJoinType(),
+        //         originPlan.getOnClause(),
+        //         );
+        // return Lists.newArrayList(physicalBroadcastHashJoin);
+        return ImmutableList.of();
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java
similarity index 52%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java
index 9ffa6b2c24..5236742398 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java
@@ -17,50 +17,44 @@
 
 package org.apache.doris.nereids.trees;
 
-import com.google.common.collect.Lists;
+
+import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 
 /**
- * Abstract class for all node in Nereids, include plan node and expression.
+ * Abstract class for plan node in Nereids, include plan node and expression.
  *
- * @param <NodeType> either {@link org.apache.doris.nereids.trees.plans.Plan}
+ * @param <NODE_TYPE> either {@link org.apache.doris.nereids.trees.plans.Plan}
  *                 or {@link org.apache.doris.nereids.trees.expressions.Expression}
  */
-public abstract class TreeNode<NodeType extends TreeNode<NodeType>> {
-    protected final org.apache.doris.nereids.trees.NodeType type;
-    protected List<NodeType> children = Lists.newArrayList();
+public abstract class AbstractTreeNode<NODE_TYPE extends AbstractTreeNode<NODE_TYPE>>
+        implements TreeNode<NODE_TYPE> {
+
+    protected final NodeType type;
+    protected final List<TreeNode> children;
 
-    public TreeNode(org.apache.doris.nereids.trees.NodeType type) {
+    public AbstractTreeNode(NodeType type, TreeNode... children) {
         this.type = type;
+        this.children = ImmutableList.copyOf(children);
     }
 
-    public NodeType getChild(int i) {
-        return children.get(i);
+    public AbstractTreeNode(NodeType type, List<NODE_TYPE> children) {
+        this.type = type;
+        this.children = ImmutableList.copyOf(children);
     }
 
-    public void addChild(NodeType child) {
-        children.add(child);
+    @Override
+    public <CHILD_TYPE extends TreeNode<CHILD_TYPE>> List<CHILD_TYPE> children() {
+        return (List) children;
     }
 
-    public List<NodeType> getChildren() {
-        return children;
+    @Override
+    public <CHILD_TYPE extends TreeNode<CHILD_TYPE>> CHILD_TYPE child(int index) {
+        return (CHILD_TYPE) children.get(index);
     }
 
     public int arity() {
         return children.size();
     }
-
-    public void replaceChild(int index, NodeType child) {
-        children.remove(index);
-        children.add(index, child);
-    }
-
-    public void removeAllChildren() {
-        children.clear();
-    }
-
-    public void setChildren(List<NodeType> children) {
-        this.children = children;
-    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/BinaryNode.java
similarity index 60%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/BinaryNode.java
index fec54ab5f5..4f8fdc592d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/BinaryNode.java
@@ -15,25 +15,27 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
-
-import org.apache.doris.nereids.trees.NodeType;
+package org.apache.doris.nereids.trees;
 
 /**
- * Abstract class for all logical plan that have on child.
+ * interface for all tree node that have two children.
  */
-public abstract class LogicalUnary extends LogicalPlan {
-    public LogicalUnary(NodeType type, LogicalPlan child) {
-        super(type);
-        addChild(child);
+public interface BinaryNode<
+            NODE_TYPE extends BinaryNode<NODE_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE extends TreeNode<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends TreeNode<RIGHT_CHILD_TYPE>>
+        extends TreeNode<NODE_TYPE> {
+
+    default LEFT_CHILD_TYPE left() {
+        return child(0);
     }
 
-    public LogicalPlan child() {
-        return getChild(0);
+    default RIGHT_CHILD_TYPE right() {
+        return child(1);
     }
 
     @Override
-    public int arity() {
-        return 1;
+    default int arity() {
+        return 2;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/LeafNode.java
similarity index 73%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/LeafNode.java
index 93c1227eb5..f2bfa75b5f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/LeafNode.java
@@ -15,20 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
-
-import org.apache.doris.nereids.trees.NodeType;
+package org.apache.doris.nereids.trees;
 
 /**
- * Abstract class for all plan node that have no child.
+ * Abstract class for all tree node that have no child.
  */
-public abstract class LogicalLeaf extends LogicalPlan {
-    public LogicalLeaf(NodeType type) {
-        super(type);
-    }
-
+public interface LeafNode<NODE_TYPE extends LeafNode<NODE_TYPE>> extends TreeNode<NODE_TYPE> {
     @Override
-    public int arity() {
+    default int arity() {
         return 0;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
index 9ffa6b2c24..d3d0fd7acf 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
@@ -17,50 +17,19 @@
 
 package org.apache.doris.nereids.trees;
 
-import com.google.common.collect.Lists;
-
 import java.util.List;
 
 /**
- * Abstract class for all node in Nereids, include plan node and expression.
+ * interface for all node in Nereids, include plan node and expression.
  *
- * @param <NodeType> either {@link org.apache.doris.nereids.trees.plans.Plan}
+ * @param <NODE_TYPE> either {@link org.apache.doris.nereids.trees.plans.Plan}
  *                 or {@link org.apache.doris.nereids.trees.expressions.Expression}
  */
-public abstract class TreeNode<NodeType extends TreeNode<NodeType>> {
-    protected final org.apache.doris.nereids.trees.NodeType type;
-    protected List<NodeType> children = Lists.newArrayList();
-
-    public TreeNode(org.apache.doris.nereids.trees.NodeType type) {
-        this.type = type;
-    }
-
-    public NodeType getChild(int i) {
-        return children.get(i);
-    }
-
-    public void addChild(NodeType child) {
-        children.add(child);
-    }
-
-    public List<NodeType> getChildren() {
-        return children;
-    }
-
-    public int arity() {
-        return children.size();
-    }
+public interface TreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>> {
 
-    public void replaceChild(int index, NodeType child) {
-        children.remove(index);
-        children.add(index, child);
-    }
+    <CHILD_TYPE extends TreeNode<CHILD_TYPE>> List<CHILD_TYPE> children();
 
-    public void removeAllChildren() {
-        children.clear();
-    }
+    <CHILD_TYPE extends TreeNode<CHILD_TYPE>> CHILD_TYPE child(int index);
 
-    public void setChildren(List<NodeType> children) {
-        this.children = children;
-    }
+    int arity();
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/UnaryNode.java
similarity index 69%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/UnaryNode.java
index 8102361d29..d7d2efb459 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/UnaryNode.java
@@ -15,20 +15,22 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.expressions;
-
-import org.apache.doris.nereids.trees.NodeType;
+package org.apache.doris.nereids.trees;
 
 /**
- * Abstract class for all slot in expression.
+ * interface for all tree node that have one child.
  */
-public abstract class Slot extends NamedExpression {
-    public Slot(NodeType type) {
-        super(type);
+public interface UnaryNode<
+            NODE_TYPE extends UnaryNode<NODE_TYPE, CHILD_TYPE>,
+            CHILD_TYPE extends TreeNode<CHILD_TYPE>>
+        extends TreeNode<NODE_TYPE> {
+
+    default CHILD_TYPE child() {
+        return child(0);
     }
 
     @Override
-    public Slot toAttribute() {
-        return this;
+    default int arity() {
+        return 1;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AbstractExpression.java
similarity index 71%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AbstractExpression.java
index 8edad09673..6996a66cc2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AbstractExpression.java
@@ -18,16 +18,21 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.AbstractTreeNode;
 import org.apache.doris.nereids.trees.NodeType;
-import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.types.DataType;
 
+import java.util.List;
+
 /**
  * Abstract class for all Expression in Nereids.
  */
-public abstract class Expression extends TreeNode<Expression> {
-    public Expression(NodeType type) {
-        super(type);
+public abstract class AbstractExpression<EXPR_TYPE extends AbstractExpression<EXPR_TYPE>>
+        extends AbstractTreeNode<EXPR_TYPE>
+        implements Expression<EXPR_TYPE> {
+
+    public AbstractExpression(NodeType type, Expression... children) {
+        super(type, children);
     }
 
     public DataType getDataType() throws UnboundException {
@@ -41,4 +46,14 @@ public abstract class Expression extends TreeNode<Expression> {
     public boolean nullable() throws UnboundException {
         throw new UnboundException("nullable");
     }
+
+    @Override
+    public List<Expression> children() {
+        return (List) children;
+    }
+
+    @Override
+    public Expression child(int index) {
+        return (Expression) children.get(index);
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java
index 3fdd644b10..68fab2561f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java
@@ -27,7 +27,10 @@ import java.util.List;
 /**
  * Expression for alias, such as col1 as c1.
  */
-public class Alias extends NamedExpression {
+public class Alias<CHILD_TYPE extends Expression<CHILD_TYPE>>
+        extends UnaryExpression<Alias<CHILD_TYPE>, CHILD_TYPE>
+        implements NamedExpression<Alias<CHILD_TYPE>> {
+
     private final ExprId exprId;
     private final String name;
     private final List<String> qualifier;
@@ -38,16 +41,11 @@ public class Alias extends NamedExpression {
      * @param child expression that alias represents for
      * @param name alias name
      */
-    public Alias(Expression child, String name) {
-        super(NodeType.ALIAS);
-        exprId = NamedExpression.newExprId();
+    public Alias(CHILD_TYPE child, String name) {
+        super(NodeType.ALIAS, child);
+        exprId = NamedExpressionUtils.newExprId();
         this.name = name;
         qualifier = Lists.newArrayList();
-        addChild(child);
-    }
-
-    public Expression child() {
-        return getChild(0);
     }
 
     @Override
@@ -66,7 +64,7 @@ public class Alias extends NamedExpression {
     }
 
     @Override
-    public Slot toAttribute() throws UnboundException {
+    public Slot toSlot() throws UnboundException {
         return new SlotReference(exprId, name, child().getDataType(), child().nullable(), qualifier);
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryExpression.java
similarity index 59%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryExpression.java
index 8102361d29..e22f344279 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryExpression.java
@@ -17,18 +17,20 @@
 
 package org.apache.doris.nereids.trees.expressions;
 
+import org.apache.doris.nereids.trees.BinaryNode;
 import org.apache.doris.nereids.trees.NodeType;
 
 /**
- * Abstract class for all slot in expression.
+ * Abstract class for all expression that have two children.
  */
-public abstract class Slot extends NamedExpression {
-    public Slot(NodeType type) {
-        super(type);
-    }
+public abstract class BinaryExpression<
+            EXPR_TYPE extends BinaryExpression<EXPR_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE extends Expression<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Expression<RIGHT_CHILD_TYPE>>
+        extends AbstractExpression<EXPR_TYPE>
+        implements BinaryNode<EXPR_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
 
-    @Override
-    public Slot toAttribute() {
-        return this;
+    public BinaryExpression(NodeType type, LEFT_CHILD_TYPE left, RIGHT_CHILD_TYPE right) {
+        super(type, left, right);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java
index 5c7bd69255..b036496a55 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java
@@ -26,7 +26,12 @@ import org.apache.doris.nereids.types.DataType;
 /**
  * Binary predicate expression.
  */
-public class BinaryPredicate extends Expression {
+public class BinaryPredicate<
+            LEFT_CHILD_TYPE extends Expression<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Expression<RIGHT_CHILD_TYPE>>
+        extends BinaryExpression<BinaryPredicate<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
+
     private final Operator operator;
 
     /**
@@ -82,19 +87,9 @@ public class BinaryPredicate extends Expression {
      * @param right right child of binary predicate
      * @param operator operator of binary predicate
      */
-    public BinaryPredicate(Expression left, Expression right, Operator operator) {
-        super(NodeType.BINARY_PREDICATE);
+    public BinaryPredicate(LEFT_CHILD_TYPE left, RIGHT_CHILD_TYPE right, Operator operator) {
+        super(NodeType.BINARY_PREDICATE, left, right);
         this.operator = operator;
-        addChild(left);
-        addChild(right);
-    }
-
-    public Expression left() {
-        return getChild(0);
-    }
-
-    public Expression right() {
-        return getChild(1);
     }
 
     public Operator getOperator() {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
index 8edad09673..6783102fa7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
@@ -18,27 +18,25 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
-import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.types.DataType;
 
+import java.util.List;
+
 /**
  * Abstract class for all Expression in Nereids.
  */
-public abstract class Expression extends TreeNode<Expression> {
-    public Expression(NodeType type) {
-        super(type);
-    }
-
-    public DataType getDataType() throws UnboundException {
-        throw new UnboundException("dataType");
-    }
-
-    public String sql() throws UnboundException {
-        throw new UnboundException("sql");
-    }
-
-    public boolean nullable() throws UnboundException {
-        throw new UnboundException("nullable");
-    }
+public interface Expression<EXPR_TYPE extends Expression<EXPR_TYPE>> extends TreeNode<EXPR_TYPE> {
+
+    DataType getDataType() throws UnboundException;
+
+    String sql() throws UnboundException;
+
+    boolean nullable() throws UnboundException;
+
+    @Override
+    List<Expression> children();
+
+    @Override
+    Expression child(int index);
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/LeafExpression.java
similarity index 74%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/LeafExpression.java
index 8102361d29..7fc5f1d6de 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/LeafExpression.java
@@ -17,18 +17,17 @@
 
 package org.apache.doris.nereids.trees.expressions;
 
+import org.apache.doris.nereids.trees.LeafNode;
 import org.apache.doris.nereids.trees.NodeType;
 
 /**
- * Abstract class for all slot in expression.
+ * Abstract class for all expression that have no child.
  */
-public abstract class Slot extends NamedExpression {
-    public Slot(NodeType type) {
-        super(type);
-    }
+public abstract class LeafExpression<EXPR_TYPE extends LeafExpression<EXPR_TYPE>>
+        extends AbstractExpression<EXPR_TYPE>
+        implements LeafNode<EXPR_TYPE> {
 
-    @Override
-    public Slot toAttribute() {
-        return this;
+    public LeafExpression(NodeType type) {
+        super(type);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java
index 187127caf5..21fce728f7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java
@@ -30,7 +30,7 @@ import org.apache.doris.nereids.types.StringType;
 /**
  * All data type literal expression in Nereids.
  */
-public class Literal extends Expression {
+public class Literal extends LeafExpression<Literal> {
     private final DataType dataType;
     private final Object value;
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java
index bbcc6b0d3c..1001ba7205 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java
@@ -18,7 +18,6 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
-import org.apache.doris.nereids.trees.NodeType;
 
 import org.apache.commons.collections.CollectionUtils;
 
@@ -29,31 +28,28 @@ import java.util.concurrent.atomic.AtomicLong;
 /**
  * Expression in Nereids that having name.
  */
-public abstract class NamedExpression extends Expression {
-    private static final AtomicLong CURRENT_ID = new AtomicLong();
-    private static final UUID JVM_ID = UUID.randomUUID();
+public interface NamedExpression<EXPR_TYPE extends NamedExpression<EXPR_TYPE>>
+        extends Expression<EXPR_TYPE> {
 
-    public NamedExpression(NodeType type) {
-        super(type);
-    }
+    @Override
+    Expression child(int index);
 
-    public static ExprId newExprId() {
-        return new ExprId(CURRENT_ID.getAndIncrement(), JVM_ID);
-    }
+    @Override
+    List<Expression> children();
 
-    public Slot toAttribute() throws UnboundException {
-        throw new UnboundException("toAttribute");
+    default Slot toSlot() throws UnboundException {
+        throw new UnboundException("toSlot");
     }
 
-    public String getName() throws UnboundException {
+    default String getName() throws UnboundException {
         throw new UnboundException("name");
     }
 
-    public ExprId getExprId() throws UnboundException {
+    default ExprId getExprId() throws UnboundException {
         throw new UnboundException("exprId");
     }
 
-    public List<String> getQualifier() throws UnboundException {
+    default List<String> getQualifier() throws UnboundException {
         throw new UnboundException("qualifier");
     }
 
@@ -63,11 +59,23 @@ public abstract class NamedExpression extends Expression {
      * @return qualified name
      * @throws UnboundException throw this exception if this expression is unbound
      */
-    public String getQualifiedName() throws UnboundException {
+    default String getQualifiedName() throws UnboundException {
         String qualifiedName = "";
         if (CollectionUtils.isNotEmpty(getQualifier())) {
             qualifiedName = String.join(".", getQualifier()) + ".";
         }
         return qualifiedName + getName();
     }
+
+    /**
+     * Tool class for generate next ExprId.
+     */
+    class NamedExpressionUtils {
+        static final UUID JVM_ID = UUID.randomUUID();
+        private static final AtomicLong CURRENT_ID = new AtomicLong();
+
+        static ExprId newExprId() {
+            return new ExprId(CURRENT_ID.getAndIncrement(), JVM_ID);
+        }
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
index 8102361d29..62f18e994c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
@@ -22,13 +22,16 @@ import org.apache.doris.nereids.trees.NodeType;
 /**
  * Abstract class for all slot in expression.
  */
-public abstract class Slot extends NamedExpression {
+public abstract class Slot<EXPR_TYPE extends Slot<EXPR_TYPE>>
+        extends LeafExpression<EXPR_TYPE>
+        implements NamedExpression<EXPR_TYPE> {
+
     public Slot(NodeType type) {
         super(type);
     }
 
     @Override
-    public Slot toAttribute() {
+    public Slot toSlot() {
         return this;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
index 97329a50a1..b4d76ac136 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
@@ -30,7 +30,7 @@ import java.util.Objects;
 /**
  * Reference to slot in expression.
  */
-public class SlotReference extends Slot {
+public class SlotReference extends Slot<SlotReference> {
     private final ExprId exprId;
     private final String name;
     private final List<String> qualifier;
@@ -38,7 +38,7 @@ public class SlotReference extends Slot {
     private final boolean nullable;
 
     public SlotReference(String name, DataType dataType, boolean nullable, List<String> qualifier) {
-        this(NamedExpression.newExprId(), name, dataType, nullable, qualifier);
+        this(NamedExpressionUtils.newExprId(), name, dataType, nullable, qualifier);
     }
 
     /**
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/UnaryExpression.java
similarity index 66%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/UnaryExpression.java
index 8102361d29..dcec019145 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/UnaryExpression.java
@@ -18,17 +18,18 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.UnaryNode;
 
 /**
- * Abstract class for all slot in expression.
+ * Abstract class for all expression that have one child.
  */
-public abstract class Slot extends NamedExpression {
-    public Slot(NodeType type) {
-        super(type);
-    }
+public abstract class UnaryExpression<
+            EXPR_TYPE extends UnaryExpression<EXPR_TYPE, CHILD_TYPE>,
+            CHILD_TYPE extends Expression<CHILD_TYPE>>
+        extends AbstractExpression<EXPR_TYPE>
+        implements UnaryNode<EXPR_TYPE, CHILD_TYPE> {
 
-    @Override
-    public Slot toAttribute() {
-        return this;
+    public UnaryExpression(NodeType type, CHILD_TYPE child) {
+        super(type, child);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
similarity index 77%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
index e458226f73..501edb6f69 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
@@ -19,67 +19,72 @@ package org.apache.doris.nereids.trees.plans;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.memo.PlanReference;
+import org.apache.doris.nereids.trees.AbstractTreeNode;
 import org.apache.doris.nereids.trees.NodeType;
-import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.trees.expressions.Slot;
 
-import com.alibaba.google.common.collect.Lists;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Abstract class for all plan node.
+ * Abstract class for all concrete plan node.
  *
- * @param <PlanType> either {@link org.apache.doris.nereids.trees.plans.logical.LogicalPlan}
+ * @param <PLAN_TYPE> either {@link org.apache.doris.nereids.trees.plans.logical.LogicalPlan}
  *                  or {@link org.apache.doris.nereids.trees.plans.physical.PhysicalPlan}
  */
-public abstract class Plan<PlanType extends Plan<PlanType>> extends TreeNode<PlanType> {
+public abstract class AbstractPlan<PLAN_TYPE extends AbstractPlan<PLAN_TYPE>>
+        extends AbstractTreeNode<PLAN_TYPE> implements Plan<PLAN_TYPE> {
 
-    protected final boolean isPhysical;
     protected PlanReference planReference;
-    protected List<Slot> output = Lists.newArrayList();
+    protected List<Slot> output;
 
-    public Plan(NodeType type, boolean isPhysical) {
-        super(type);
-        this.isPhysical = isPhysical;
+    public AbstractPlan(NodeType type, Plan...children) {
+        super(type, children);
     }
 
-    public org.apache.doris.nereids.trees.NodeType getType() {
+    @Override
+    public NodeType getType() {
         return type;
     }
 
-    public boolean isPhysical() {
-        return isPhysical;
-    }
-
-    public boolean isLogical() {
-        return !isPhysical;
-    }
-
+    @Override
     public abstract List<Slot> getOutput() throws UnboundException;
 
+    @Override
     public PlanReference getPlanReference() {
         return planReference;
     }
 
+    @Override
     public void setPlanReference(PlanReference planReference) {
         this.planReference = planReference;
     }
 
+    @Override
+    public List<Plan> children() {
+        return (List) children;
+    }
+
+    @Override
+    public Plan child(int index) {
+        return (Plan) children.get(index);
+    }
+
     /**
      * Get tree like string describing query plan.
      *
      * @return tree like string describing query plan
      */
+    @Override
     public String treeString() {
         List<String> lines = new ArrayList<>();
         treeString(lines, 0, new ArrayList<>(), this);
         return StringUtils.join(lines, "\n");
     }
 
-    private void treeString(List<String> lines, int depth, List<Boolean> lastChildren, Plan<PlanType> plan) {
+    private void treeString(List<String> lines, int depth, List<Boolean> lastChildren, Plan<PLAN_TYPE> plan) {
         StringBuilder sb = new StringBuilder();
         if (depth > 0) {
             if (lastChildren.size() > 1) {
@@ -95,7 +100,7 @@ public abstract class Plan<PlanType extends Plan<PlanType>> extends TreeNode<Pla
         sb.append(plan.toString());
         lines.add(sb.toString());
 
-        List<PlanType> children = plan.getChildren();
+        List<Plan> children = plan.children();
         for (int i = 0; i < children.size(); i++) {
             List<Boolean> newLasts = new ArrayList<>(lastChildren);
             newLasts.add(i + 1 == children.size());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/BinaryPlan.java
similarity index 59%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/BinaryPlan.java
index fec54ab5f5..9bd1df54b2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/BinaryPlan.java
@@ -15,25 +15,24 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
+package org.apache.doris.nereids.trees.plans;
 
-import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.BinaryNode;
+
+import java.util.List;
 
 /**
- * Abstract class for all logical plan that have on child.
+ * interface for all plan that have two children.
  */
-public abstract class LogicalUnary extends LogicalPlan {
-    public LogicalUnary(NodeType type, LogicalPlan child) {
-        super(type);
-        addChild(child);
-    }
+public interface BinaryPlan<
+            PLAN_TYPE extends BinaryPlan<PLAN_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE extends Plan<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Plan<RIGHT_CHILD_TYPE>>
+        extends Plan<PLAN_TYPE>, BinaryNode<PLAN_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
 
-    public LogicalPlan child() {
-        return getChild(0);
-    }
+    @Override
+    List<Plan> children();
 
     @Override
-    public int arity() {
-        return 1;
-    }
+    Plan child(int index);
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/LeafPlan.java
similarity index 72%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/LeafPlan.java
index 93c1227eb5..2749d96fc5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/LeafPlan.java
@@ -15,20 +15,26 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
+package org.apache.doris.nereids.trees.plans;
 
-import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.LeafNode;
+
+import java.util.List;
 
 /**
  * Abstract class for all plan node that have no child.
  */
-public abstract class LogicalLeaf extends LogicalPlan {
-    public LogicalLeaf(NodeType type) {
-        super(type);
-    }
+public interface LeafPlan<PLAN_TYPE extends LeafPlan<PLAN_TYPE>>
+        extends Plan<PLAN_TYPE>, LeafNode<PLAN_TYPE> {
+
+    @Override
+    List<Plan> children();
+
+    @Override
+    Plan child(int index);
 
     @Override
-    public int arity() {
+    default int arity() {
         return 0;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
index e458226f73..1f07641152 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
@@ -23,83 +23,25 @@ import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.trees.expressions.Slot;
 
-import com.alibaba.google.common.collect.Lists;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Abstract class for all plan node.
- *
- * @param <PlanType> either {@link org.apache.doris.nereids.trees.plans.logical.LogicalPlan}
- *                  or {@link org.apache.doris.nereids.trees.plans.physical.PhysicalPlan}
  */
-public abstract class Plan<PlanType extends Plan<PlanType>> extends TreeNode<PlanType> {
-
-    protected final boolean isPhysical;
-    protected PlanReference planReference;
-    protected List<Slot> output = Lists.newArrayList();
-
-    public Plan(NodeType type, boolean isPhysical) {
-        super(type);
-        this.isPhysical = isPhysical;
-    }
-
-    public org.apache.doris.nereids.trees.NodeType getType() {
-        return type;
-    }
-
-    public boolean isPhysical() {
-        return isPhysical;
-    }
-
-    public boolean isLogical() {
-        return !isPhysical;
-    }
+public interface Plan<PLAN_TYPE extends Plan<PLAN_TYPE>> extends TreeNode<PLAN_TYPE> {
+    NodeType getType();
 
-    public abstract List<Slot> getOutput() throws UnboundException;
+    List<Slot> getOutput() throws UnboundException;
 
-    public PlanReference getPlanReference() {
-        return planReference;
-    }
+    PlanReference getPlanReference();
 
-    public void setPlanReference(PlanReference planReference) {
-        this.planReference = planReference;
-    }
+    void setPlanReference(PlanReference planReference);
 
-    /**
-     * Get tree like string describing query plan.
-     *
-     * @return tree like string describing query plan
-     */
-    public String treeString() {
-        List<String> lines = new ArrayList<>();
-        treeString(lines, 0, new ArrayList<>(), this);
-        return StringUtils.join(lines, "\n");
-    }
+    String treeString();
 
-    private void treeString(List<String> lines, int depth, List<Boolean> lastChildren, Plan<PlanType> plan) {
-        StringBuilder sb = new StringBuilder();
-        if (depth > 0) {
-            if (lastChildren.size() > 1) {
-                for (int i = 0; i < lastChildren.size() - 1; i++) {
-                    sb.append(lastChildren.get(i) ? "   " : "|  ");
-                }
-            }
-            if (lastChildren.size() > 0) {
-                Boolean last = lastChildren.get(lastChildren.size() - 1);
-                sb.append(last ? "+--" : "|--");
-            }
-        }
-        sb.append(plan.toString());
-        lines.add(sb.toString());
+    @Override
+    List<Plan> children();
 
-        List<PlanType> children = plan.getChildren();
-        for (int i = 0; i < children.size(); i++) {
-            List<Boolean> newLasts = new ArrayList<>(lastChildren);
-            newLasts.add(i + 1 == children.size());
-            treeString(lines, depth + 1, newLasts, children.get(i));
-        }
-    }
+    @Override
+    Plan child(int index);
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/UnaryPlan.java
similarity index 63%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/UnaryPlan.java
index fec54ab5f5..4ed3c73b75 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/UnaryPlan.java
@@ -15,25 +15,28 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
+package org.apache.doris.nereids.trees.plans;
 
-import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.UnaryNode;
+
+import java.util.List;
 
 /**
- * Abstract class for all logical plan that have on child.
+ * interface for all plan node that have one child.
  */
-public abstract class LogicalUnary extends LogicalPlan {
-    public LogicalUnary(NodeType type, LogicalPlan child) {
-        super(type);
-        addChild(child);
-    }
+public interface UnaryPlan<
+            PLAN_TYPE extends UnaryPlan<PLAN_TYPE, CHILD_TYPE>,
+            CHILD_TYPE extends Plan<CHILD_TYPE>>
+        extends Plan<PLAN_TYPE>, UnaryNode<PLAN_TYPE, CHILD_TYPE> {
 
-    public LogicalPlan child() {
-        return getChild(0);
-    }
+    @Override
+    List<Plan> children();
+
+    @Override
+    Plan child(int index);
 
     @Override
-    public int arity() {
+    default int arity() {
         return 1;
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
similarity index 68%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
index 93c1227eb5..28ef99f0c4 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
@@ -18,17 +18,17 @@
 package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.AbstractPlan;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 /**
- * Abstract class for all plan node that have no child.
+ * Abstract class for all concrete logical plan.
  */
-public abstract class LogicalLeaf extends LogicalPlan {
-    public LogicalLeaf(NodeType type) {
-        super(type);
-    }
+public abstract class AbstractLogicalPlan<PLAN_TYPE extends AbstractLogicalPlan<PLAN_TYPE>>
+        extends AbstractPlan<PLAN_TYPE>
+        implements LogicalPlan<PLAN_TYPE> {
 
-    @Override
-    public int arity() {
-        return 0;
+    public AbstractLogicalPlan(NodeType type, Plan... children) {
+        super(type, children);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
index d266a6188f..1b3b34ab8d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
@@ -18,35 +18,20 @@
 package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.BinaryPlan;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 /**
- * Abstract class for all {@link LogicalPlan} that have two children.
+ * Abstract class for all logical plan that have two children.
  */
-public abstract class LogicalBinary extends LogicalPlan {
+public abstract class LogicalBinary<
+            PLAN_TYPE extends LogicalBinary<PLAN_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE extends Plan<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Plan<RIGHT_CHILD_TYPE>>
+        extends AbstractLogicalPlan<PLAN_TYPE>
+        implements BinaryPlan<PLAN_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
 
-    /**
-     * Constructor for LogicalBinary.
-     *
-     * @param type type for this plan.
-     * @param left left child for LogicalBinary
-     * @param right right child for LogicalBinary
-     */
-    public LogicalBinary(NodeType type, LogicalPlan left, LogicalPlan right) {
-        super(type);
-        addChild(left);
-        addChild(right);
-    }
-
-    public LogicalPlan left() {
-        return getChild(0);
-    }
-
-    public LogicalPlan right() {
-        return getChild(1);
-    }
-
-    @Override
-    public int arity() {
-        return 2;
+    public LogicalBinary(NodeType type, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
+        super(type, leftChild, rightChild);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
index e0f467f415..8c8e2739a9 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
@@ -21,16 +21,19 @@ import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 import java.util.List;
 
 /**
  * Logical filter plan node.
  */
-public class LogicalFilter extends LogicalUnary {
+public class LogicalFilter<CHILD_TYPE extends Plan<CHILD_TYPE>>
+         extends LogicalUnary<LogicalFilter<CHILD_TYPE>, CHILD_TYPE> {
+
     private final Expression predicates;
 
-    public LogicalFilter(Expression predicates, LogicalPlan child) {
+    public LogicalFilter(Expression predicates, CHILD_TYPE child) {
         super(NodeType.LOGICAL_FILTER, child);
         this.predicates = predicates;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
index a5346485dd..c1473dcbfd 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -31,7 +32,11 @@ import java.util.List;
 /**
  * Logical join plan node.
  */
-public class LogicalJoin extends LogicalBinary {
+public class LogicalJoin<
+            LEFT_CHILD_TYPE extends Plan<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Plan<RIGHT_CHILD_TYPE>>
+        extends LogicalBinary<LogicalJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
+
     private final JoinType joinType;
     private final Expression onClause;
 
@@ -43,7 +48,7 @@ public class LogicalJoin extends LogicalBinary {
      * @param left left child of join node
      * @param right right child of join node
      */
-    public LogicalJoin(JoinType joinType, Expression onClause, LogicalPlan left, LogicalPlan right) {
+    public LogicalJoin(JoinType joinType, Expression onClause, LEFT_CHILD_TYPE left, RIGHT_CHILD_TYPE right) {
         super(NodeType.LOGICAL_JOIN, left, right);
         this.joinType = joinType;
         this.onClause = onClause;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
index 93c1227eb5..0afd7a3c4d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
@@ -18,17 +18,16 @@
 package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.LeafPlan;
 
 /**
- * Abstract class for all plan node that have no child.
+ * Abstract class for all logical plan that have no child.
  */
-public abstract class LogicalLeaf extends LogicalPlan {
+public abstract class LogicalLeaf<PLAN_TYPE extends LogicalLeaf<PLAN_TYPE>>
+        extends AbstractLogicalPlan<PLAN_TYPE>
+        implements LeafPlan<PLAN_TYPE> {
+
     public LogicalLeaf(NodeType type) {
         super(type);
     }
-
-    @Override
-    public int arity() {
-        return 0;
-    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
index 1434808607..838b495ce6 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
@@ -17,24 +17,27 @@
 
 package org.apache.doris.nereids.trees.plans.logical;
 
-import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.plans.Plan;
 
+import java.util.List;
 import java.util.function.BiFunction;
 
 /**
  * Abstract class for all logical plan in Nereids.
  */
-public abstract class LogicalPlan extends Plan<LogicalPlan> {
-    public LogicalPlan(NodeType type) {
-        super(type, false);
-    }
+public interface LogicalPlan<PLAN_TYPE extends LogicalPlan<PLAN_TYPE>> extends Plan<PLAN_TYPE> {
+
+    @Override
+    List<Plan> children();
+
+    @Override
+    Plan child(int index);
 
     /**
      * Map a [[LogicalPlan]] to another [[LogicalPlan]] if the passed context exists using the
      * passed function. The original plan is returned when the context does not exist.
      */
-    public <C> LogicalPlan optionalMap(C ctx, BiFunction<C, LogicalPlan, LogicalPlan> f) {
+    default <C> LogicalPlan optionalMap(C ctx, BiFunction<C, LogicalPlan, LogicalPlan> f) {
         if (ctx != null) {
             return f.apply(ctx, this);
         } else {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
index 4afa96ba70..5417f17861 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 import com.google.common.collect.Lists;
 import org.apache.commons.lang3.StringUtils;
@@ -30,7 +31,9 @@ import java.util.List;
 /**
  * Logical project plan node.
  */
-public class LogicalProject extends LogicalUnary {
+public class LogicalProject<CHILD_TYPE extends Plan<CHILD_TYPE>>
+        extends LogicalUnary<LogicalProject<CHILD_TYPE>, CHILD_TYPE> {
+
     private final List<? extends NamedExpression> projects;
 
     /**
@@ -39,7 +42,7 @@ public class LogicalProject extends LogicalUnary {
      * @param projects project list
      * @param child child plan node
      */
-    public LogicalProject(List<? extends NamedExpression> projects, LogicalPlan child) {
+    public LogicalProject(List<? extends NamedExpression> projects, CHILD_TYPE child) {
         super(NodeType.LOGICAL_PROJECT, child);
         this.projects = projects;
         updateOutput();
@@ -63,7 +66,7 @@ public class LogicalProject extends LogicalUnary {
         output = Lists.newArrayListWithCapacity(projects.size());
         for (NamedExpression projection : projects) {
             try {
-                output.add(projection.toAttribute());
+                output.add(projection.toSlot());
             } catch (UnboundException e) {
                 output.clear();
                 break;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
index 135ba10ef5..b991415a98 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
@@ -30,7 +30,8 @@ import java.util.stream.Collectors;
 /**
  * Logical relation plan node.
  */
-public class LogicalRelation extends LogicalLeaf {
+public class LogicalRelation extends LogicalLeaf<LogicalRelation> {
+
     private final Table table;
     private final List<String> qualifier;
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
index fec54ab5f5..bf51bc53bb 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
@@ -18,22 +18,19 @@
 package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.UnaryPlan;
 
 /**
- * Abstract class for all logical plan that have on child.
+ * Abstract class for all logical plan that have one child.
  */
-public abstract class LogicalUnary extends LogicalPlan {
-    public LogicalUnary(NodeType type, LogicalPlan child) {
-        super(type);
-        addChild(child);
-    }
-
-    public LogicalPlan child() {
-        return getChild(0);
-    }
+public abstract class LogicalUnary<
+            PLAN_TYPE extends LogicalUnary<PLAN_TYPE, CHILD_TYPE>,
+            CHILD_TYPE extends Plan<CHILD_TYPE>>
+        extends AbstractLogicalPlan<PLAN_TYPE>
+        implements UnaryPlan<PLAN_TYPE, CHILD_TYPE> {
 
-    @Override
-    public int arity() {
-        return 1;
+    public LogicalUnary(NodeType type, CHILD_TYPE child) {
+        super(type, child);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
similarity index 79%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
index e3cf733850..336fce0447 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
@@ -21,21 +21,26 @@ import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.properties.PhysicalProperties;
 import org.apache.doris.nereids.trees.NodeType;
 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.List;
 
 /**
- * Abstract class for all physical plan node.
+ * Abstract class for all concrete physical plan.
  */
-public abstract class PhysicalPlan extends Plan<PhysicalPlan> {
+public abstract class AbstractPhysicalPlan<PLAN_TYPE extends AbstractPhysicalPlan<PLAN_TYPE>>
+        extends AbstractPlan<PLAN_TYPE>
+        implements PhysicalPlan<PLAN_TYPE> {
+
     protected LogicalProperties logicalProperties;
     protected PhysicalProperties physicalProperties;
 
-    public PhysicalPlan(NodeType type) {
-        super(type, true);
+    public AbstractPhysicalPlan(NodeType type, Plan... children) {
+        super(type, children);
     }
 
+    @Override
     public void setLogicalProperties(LogicalProperties logicalProperties) {
         this.logicalProperties = logicalProperties;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java
similarity index 57%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java
index e3cf733850..da4967176a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java
@@ -17,31 +17,21 @@
 
 package org.apache.doris.nereids.trees.plans.physical;
 
-import org.apache.doris.nereids.properties.LogicalProperties;
-import org.apache.doris.nereids.properties.PhysicalProperties;
 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 java.util.List;
-
 /**
- * Abstract class for all physical plan node.
+ * Abstract class for all physical plan that have two children.
  */
-public abstract class PhysicalPlan extends Plan<PhysicalPlan> {
-    protected LogicalProperties logicalProperties;
-    protected PhysicalProperties physicalProperties;
-
-    public PhysicalPlan(NodeType type) {
-        super(type, true);
-    }
-
-    public void setLogicalProperties(LogicalProperties logicalProperties) {
-        this.logicalProperties = logicalProperties;
-    }
+public abstract class PhysicalBinary<
+            PLAN_TYPE extends PhysicalBinary<PLAN_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE extends Plan<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Plan<RIGHT_CHILD_TYPE>>
+        extends AbstractPhysicalPlan<PLAN_TYPE>
+        implements BinaryPlan<PLAN_TYPE, LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
 
-    @Override
-    public List<Slot> getOutput() {
-        return logicalProperties.getOutput();
+    public PhysicalBinary(NodeType type, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
+        super(type, leftChild, rightChild);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java
index e26102c842..347725623b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.trees.plans.physical;
 import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 import org.apache.commons.lang3.StringUtils;
 
@@ -28,7 +29,12 @@ import java.util.Optional;
 /**
  * Physical node represents broadcast hash join.
  */
-public class PhysicalBroadcastHashJoin extends PhysicalPlan {
+public class PhysicalBroadcastHashJoin<
+            LEFT_CHILD_TYPE extends Plan<LEFT_CHILD_TYPE>,
+            RIGHT_CHILD_TYPE extends Plan<RIGHT_CHILD_TYPE>>
+        extends PhysicalBinary<PhysicalBroadcastHashJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE>,
+            LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
+
     private final JoinType joinType;
     private final Expression onClause;
 
@@ -38,8 +44,9 @@ public class PhysicalBroadcastHashJoin extends PhysicalPlan {
      * @param joinType logical join type in Nereids
      * @param onClause on clause expression
      */
-    public PhysicalBroadcastHashJoin(JoinType joinType, Expression onClause) {
-        super(NodeType.PHYSICAL_BROADCAST_HASH_JOIN);
+    public PhysicalBroadcastHashJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild,
+                                     Expression onClause) {
+        super(NodeType.PHYSICAL_BROADCAST_HASH_JOIN, leftChild, rightChild);
         this.joinType = joinType;
         this.onClause = onClause;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
index 454c105b1d..aa47c633e5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
@@ -19,15 +19,18 @@ package org.apache.doris.nereids.trees.plans.physical;
 
 import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 /**
  * Physical filter plan node.
  */
-public class PhysicalFilter extends PhysicalPlan {
+public class PhysicalFilter<CHILD_TYPE extends Plan<CHILD_TYPE>>
+        extends PhysicalUnary<PhysicalFilter<CHILD_TYPE>, CHILD_TYPE> {
+
     private final Expression predicates;
 
-    public PhysicalFilter(Expression predicates) {
-        super(NodeType.PHYSICAL_FILTER);
+    public PhysicalFilter(Expression predicates, CHILD_TYPE child) {
+        super(NodeType.PHYSICAL_FILTER, child);
         this.predicates = predicates;
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java
similarity index 70%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java
index 93c1227eb5..5138bea6d3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java
@@ -15,20 +15,19 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
+package org.apache.doris.nereids.trees.plans.physical;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.LeafPlan;
 
 /**
- * Abstract class for all plan node that have no child.
+ * Abstract class for all physical plan that have no child.
  */
-public abstract class LogicalLeaf extends LogicalPlan {
-    public LogicalLeaf(NodeType type) {
-        super(type);
-    }
+public abstract class PhysicalLeaf<PLAN_TYPE extends PhysicalLeaf<PLAN_TYPE>>
+        extends AbstractPhysicalPlan<PLAN_TYPE>
+        implements LeafPlan<PLAN_TYPE> {
 
-    @Override
-    public int arity() {
-        return 0;
+    public PhysicalLeaf(NodeType type) {
+        super(type);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
index 6a133f117c..4507591a93 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
@@ -29,7 +29,7 @@ import java.util.List;
 /**
  * Physical olap scan plan node.
  */
-public class PhysicalOlapScan extends PhysicalScan {
+public class PhysicalOlapScan extends PhysicalScan<PhysicalOlapScan> {
     private final long selectedIndexId;
     private final List<Long> selectedTabletId;
     private final List<Long> selectedPartitionId;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
index e3cf733850..e62d37786c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
@@ -18,30 +18,19 @@
 package org.apache.doris.nereids.trees.plans.physical;
 
 import org.apache.doris.nereids.properties.LogicalProperties;
-import org.apache.doris.nereids.properties.PhysicalProperties;
-import org.apache.doris.nereids.trees.NodeType;
-import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.Plan;
 
 import java.util.List;
 
 /**
- * Abstract class for all physical plan node.
+ * interface for all physical plan.
  */
-public abstract class PhysicalPlan extends Plan<PhysicalPlan> {
-    protected LogicalProperties logicalProperties;
-    protected PhysicalProperties physicalProperties;
-
-    public PhysicalPlan(NodeType type) {
-        super(type, true);
-    }
-
-    public void setLogicalProperties(LogicalProperties logicalProperties) {
-        this.logicalProperties = logicalProperties;
-    }
+public interface PhysicalPlan<PLAN_TYPE extends PhysicalPlan<PLAN_TYPE>> extends Plan<PLAN_TYPE> {
+    @Override
+    List<Plan> children();
 
     @Override
-    public List<Slot> getOutput() {
-        return logicalProperties.getOutput();
-    }
+    Plan child(int index);
+
+    void setLogicalProperties(LogicalProperties logicalProperties);
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
index 79438ac946..4e8733cd4b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.plans.physical;
 
 import org.apache.doris.nereids.trees.NodeType;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.plans.Plan;
 
 import org.apache.commons.lang3.StringUtils;
 
@@ -27,11 +28,13 @@ import java.util.List;
 /**
  * Physical project plan node.
  */
-public class PhysicalProject extends PhysicalPlan {
+public class PhysicalProject<CHILD_TYPE extends Plan<CHILD_TYPE>>
+        extends PhysicalUnary<PhysicalProject<CHILD_TYPE>, CHILD_TYPE> {
+
     private final List<? extends NamedExpression> projects;
 
-    public PhysicalProject(List<? extends NamedExpression> projects) {
-        super(NodeType.PHYSICAL_PROJECT);
+    public PhysicalProject(List<? extends NamedExpression> projects, CHILD_TYPE child) {
+        super(NodeType.PHYSICAL_PROJECT, child);
         this.projects = projects;
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java
index 5d8430d773..250932cbff 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java
@@ -25,7 +25,9 @@ import java.util.List;
 /**
  * Abstract class for all physical scan node.
  */
-public abstract class PhysicalScan extends PhysicalPlan {
+public abstract class PhysicalScan<PLAN_TYPE extends PhysicalScan<PLAN_TYPE>>
+        extends PhysicalLeaf<PLAN_TYPE> {
+
     protected final Table table;
     protected final List<String> qualifier;
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java
similarity index 60%
copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java
index 93c1227eb5..03305653ab 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java
@@ -15,20 +15,22 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans.logical;
+package org.apache.doris.nereids.trees.plans.physical;
 
 import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.UnaryPlan;
 
 /**
- * Abstract class for all plan node that have no child.
+ * Abstract class for all physical plan that have one child.
  */
-public abstract class LogicalLeaf extends LogicalPlan {
-    public LogicalLeaf(NodeType type) {
-        super(type);
-    }
+public abstract class PhysicalUnary<
+            PLAN_TYPE extends PhysicalUnary<PLAN_TYPE, CHILD_TYPE>,
+            CHILD_TYPE extends Plan<CHILD_TYPE>>
+        extends AbstractPhysicalPlan<PLAN_TYPE>
+        implements UnaryPlan<PLAN_TYPE, CHILD_TYPE> {
 
-    @Override
-    public int arity() {
-        return 0;
+    public PhysicalUnary(NodeType type, CHILD_TYPE child) {
+        super(type, child);
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org