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

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


The following commit(s) were added to refs/heads/master by this push:
     new fde474609e [feature](Nereids) Add dphyp job (#14485)
fde474609e is described below

commit fde474609efc4108af2af45f316cb5de5aefe4c9
Author: 谢健 <jianx...@gmail.com>
AuthorDate: Thu Nov 24 15:50:05 2022 +0800

    [feature](Nereids) Add dphyp job (#14485)
---
 .../org/apache/doris/nereids/NereidsPlanner.java   |   7 -
 .../org/apache/doris/nereids/jobs/JobType.java     |   4 +-
 .../doris/nereids/jobs/joinorder/JoinOrderJob.java |  98 ++++++++++++
 .../joinorder}/hypergraph/CircleDetector.java      |   9 +-
 .../joinorder}/hypergraph/Edge.java                |   4 +-
 .../joinorder}/hypergraph/GraphSimplifier.java     | 164 +++++++++++++++++----
 .../joinorder}/hypergraph/HyperGraph.java          | 115 ++++-----------
 .../joinorder}/hypergraph/Node.java                |  42 +++---
 .../joinorder}/hypergraph/SubgraphEnumerator.java  |  56 ++++---
 .../hypergraph/bitmap/BitSetIterator.java          |   2 +-
 .../joinorder}/hypergraph/bitmap/Bitmap.java       |   2 +-
 .../hypergraph/bitmap/ReverseBitSetIterator.java   |   2 +-
 .../hypergraph/bitmap/SubsetIterator.java          |   2 +-
 .../hypergraph/receiver/AbstractReceiver.java      |  12 +-
 .../joinorder}/hypergraph/receiver/Counter.java    |  33 ++++-
 .../hypergraph/receiver/PlanReceiver.java          | 140 ++++++++++++++++++
 .../java/org/apache/doris/nereids/memo/Group.java  |   5 +
 .../apache/doris/nereids/memo/GroupExpression.java |   5 +
 .../rules/joinreorder/HyperGraphJoinReorder.java   |  48 ------
 .../HyperGraphJoinReorderGroupLeft.java            |  48 ------
 .../HyperGraphJoinReorderGroupRight.java           |  47 ------
 .../joinreorder/hypergraph/receiver/PlanTable.java |  57 -------
 .../joinorder/JoinOrderJobTest.java}               |  22 +--
 .../joinorder}/hypergraph/BitSetTest.java          |   6 +-
 .../joinorder}/hypergraph/CircleDetectorTest.java  |   2 +-
 .../joinorder}/hypergraph/GraphSimplifierTest.java |  41 ++++--
 .../joinorder}/hypergraph/HyperGraphTest.java      |   2 +-
 .../hypergraph/SubgraphEnumeratorTest.java         |   8 +-
 .../HyperGraphJoinReorderGroupRightTest.java       |  52 -------
 .../joinreorder/HyperGraphJoinReorderTest.java     |  56 -------
 .../doris/nereids/util/HyperGraphBuilder.java      |  75 ++++------
 .../org/apache/doris/nereids/util/PlanChecker.java |  37 +++--
 32 files changed, 628 insertions(+), 575 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
index 34a088d799..acaf27ddb1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java
@@ -28,13 +28,11 @@ import 
org.apache.doris.nereids.glue.translator.PlanTranslatorContext;
 import org.apache.doris.nereids.jobs.batch.NereidsRewriteJobExecutor;
 import org.apache.doris.nereids.jobs.batch.OptimizeRulesJob;
 import org.apache.doris.nereids.jobs.cascades.DeriveStatsJob;
-import org.apache.doris.nereids.jobs.rewrite.RewriteTopDownJob;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.processor.post.PlanPostProcessors;
 import org.apache.doris.nereids.processor.pre.PlanPreprocessors;
 import org.apache.doris.nereids.properties.PhysicalProperties;
-import org.apache.doris.nereids.rules.joinreorder.HyperGraphJoinReorder;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.plans.Plan;
 import 
org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
@@ -213,11 +211,6 @@ public class NereidsPlanner extends Planner {
     }
 
     private void joinReorder() {
-        new RewriteTopDownJob(
-            getRoot(),
-            (new HyperGraphJoinReorder()).buildRules(),
-            cascadesContext.getCurrentJobContext()
-        ).execute();
     }
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java
index 528109babb..03681c58ee 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java
@@ -30,6 +30,6 @@ public enum JobType {
     DERIVE_STATS,
     TOP_DOWN_REWRITE,
     VISITOR_REWRITE,
-    BOTTOM_UP_REWRITE
-    ;
+    BOTTOM_UP_REWRITE,
+    JOIN_ORDER;
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java
new file mode 100644
index 0000000000..4b5e20ad0d
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java
@@ -0,0 +1,98 @@
+// 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.jobs.joinorder;
+
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobContext;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.GraphSimplifier;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.HyperGraph;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.SubgraphEnumerator;
+import 
org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver.PlanReceiver;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.GroupExpression;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Join Order job with DPHyp
+ */
+public class JoinOrderJob extends Job {
+    private final Group group;
+
+    public JoinOrderJob(Group group, JobContext context) {
+        super(JobType.JOIN_ORDER, context);
+        this.group = group;
+    }
+
+    @Override
+    public void execute() throws AnalysisException {
+        Preconditions.checkArgument(!group.isJoinGroup());
+        GroupExpression rootExpr = group.getLogicalExpression();
+        int arity = rootExpr.arity();
+        for (int i = 0; i < arity; i++) {
+            rootExpr.setChild(i, optimizePlan(rootExpr.child(i)));
+        }
+    }
+
+    private Group optimizePlan(Group group) {
+        if (group.isJoinGroup()) {
+            return optimizeJoin(group);
+        }
+        GroupExpression rootExpr = group.getLogicalExpression();
+        int arity = rootExpr.arity();
+        for (int i = 0; i < arity; i++) {
+            rootExpr.setChild(i, optimizePlan(rootExpr.child(i)));
+        }
+        return group;
+    }
+
+    private Group optimizeJoin(Group group) {
+        HyperGraph hyperGraph = new HyperGraph();
+        buildGraph(group, hyperGraph);
+        // Right now, we just hardcode the limit with 10000, maybe we need a 
better way to set it
+        int limit = 10000;
+        PlanReceiver planReceiver = new PlanReceiver(limit);
+        SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(planReceiver, hyperGraph);
+        if (!subgraphEnumerator.enumerate()) {
+            GraphSimplifier graphSimplifier = new GraphSimplifier(hyperGraph);
+            graphSimplifier.simplifyGraph(limit);
+            if (!subgraphEnumerator.enumerate()) {
+                throw new RuntimeException("DPHyp can not enumerate all sub 
graphs with limit=" + limit);
+            }
+        }
+        return planReceiver.getBestPlan(hyperGraph.getNodesMap());
+    }
+
+    /**
+     * build a hyperGraph for the root group
+     *
+     * @param group root group, should be join type
+     * @param hyperGraph build hyperGraph
+     */
+    public void buildGraph(Group group, HyperGraph hyperGraph) {
+        if (!group.isJoinGroup()) {
+            hyperGraph.addNode(optimizePlan(group));
+            return;
+        }
+        buildGraph(group.getLogicalExpression().child(0), hyperGraph);
+        buildGraph(group.getLogicalExpression().child(1), hyperGraph);
+        hyperGraph.addEdge(group);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/CircleDetector.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CircleDetector.java
similarity index 94%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/CircleDetector.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CircleDetector.java
index 7cdcb16073..7f97904cf6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/CircleDetector.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CircleDetector.java
@@ -15,9 +15,9 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
 
 import com.google.common.base.Preconditions;
 
@@ -39,8 +39,8 @@ public class CircleDetector {
     List<Integer> nodes = new ArrayList<>();
     // stored the dependency of each node
     List<BitSet> directedEdges = new ArrayList<>();
+    // the nodes are after than this node
     List<BitSet> subNodes = new ArrayList<>();
-    // whether the node has been visited in dfs
 
     CircleDetector(int size) {
         for (int i = 0; i < size; i++) {
@@ -67,9 +67,10 @@ public class CircleDetector {
         int order1 = orders.get(node1);
         int order2 = orders.get(node2);
         if (order1 >= order2) {
-            shift(order2, order1 + 1, subNodes.get(order2));
+            shift(order2, order1 + 1, subNodes.get(node2));
         }
         for (BitSet nodes : subNodes) {
+            // add all subNodes which contains node1 into subNodes of node2.
             if (Bitmap.get(nodes, node1)) {
                 Bitmap.or(nodes, subNodes.get(node2));
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/Edge.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/Edge.java
similarity index 96%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/Edge.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/Edge.java
index 835f599751..576e7910c6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/Edge.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/Edge.java
@@ -15,9 +15,9 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/GraphSimplifier.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java
similarity index 76%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/GraphSimplifier.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java
index b341289ae0..88c35d479c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/GraphSimplifier.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java
@@ -15,12 +15,13 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver.Counter;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.PhysicalProperties;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
 import org.apache.doris.nereids.stats.StatsCalculator;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -34,6 +35,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Optional;
 import java.util.PriorityQueue;
+import java.util.Stack;
+import javax.annotation.Nullable;
 
 /**
  * GraphSimplifier is used to simplify HyperGraph {@link HyperGraph}
@@ -41,6 +44,8 @@ import java.util.PriorityQueue;
 public class GraphSimplifier {
     // Note that each index in the graph simplifier is the half of the actual 
index
     private final int edgeSize;
+    // Detect the circle when order join
+    private CircleDetector circleDetector;
     // This is used for cache the intermediate results when calculate the 
benefit
     // Note that we store it for the after. Because if we put B after A (t1 
Join_A t2 Join_B t3),
     // B is changed. Therefore, Any step that involves B need to be 
recalculated.
@@ -48,14 +53,20 @@ public class GraphSimplifier {
     private PriorityQueue<BestSimplification> priorityQueue = new 
PriorityQueue<>();
     // The graph we are simplifying
     private HyperGraph graph;
-    // Detect the circle when order join
-    private CircleDetector circleDetector;
     // It cached the plan in simplification. we don't store it in hyper graph,
     // because it's just used for simulating join. In fact, the graph 
simplifier
     // just generate the partial order of join operator.
     private HashMap<BitSet, Plan> cachePlan = new HashMap<>();
 
-    GraphSimplifier(HyperGraph graph) {
+    private Stack<SimplificationStep> appliedSteps = new 
Stack<SimplificationStep>();
+    private Stack<SimplificationStep> unAppliedSteps = new 
Stack<SimplificationStep>();
+
+    /**
+     * Create a graph simplifier
+     *
+     * @param graph create a graph simplifier to simplify the graph
+     */
+    public GraphSimplifier(HyperGraph graph) {
         this.graph = graph;
         edgeSize = graph.getEdges().size();
         for (int i = 0; i < edgeSize; i++) {
@@ -78,6 +89,30 @@ public class GraphSimplifier {
         }
     }
 
+    /**
+     * Check whether all edge has been ordered
+     *
+     * @return if true, all edges has a total order
+     */
+    public boolean isTotalOrder() {
+        for (int i = 0; i < edgeSize; i++) {
+            for (int j = i + 1; j < edgeSize; j++) {
+                Edge edge1 = graph.getEdge(i);
+                Edge edge2 = graph.getEdge(j);
+                List<BitSet> superset = new ArrayList<>();
+                tryGetSuperset(edge1.getLeft(), edge2.getLeft(), superset);
+                tryGetSuperset(edge1.getLeft(), edge2.getRight(), superset);
+                tryGetSuperset(edge1.getRight(), edge2.getLeft(), superset);
+                tryGetSuperset(edge1.getRight(), edge2.getRight(), superset);
+                if (!circleDetector.checkCircleWithEdge(i, j) && 
!circleDetector.checkCircleWithEdge(j, i)
+                        && !edge2.isSub(edge1) && !edge1.isSub(edge2) && 
!superset.isEmpty()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     /**
      * This function will repeatedly apply simplification steps util the 
number of csg-cmp pair
      * is under the limit.
@@ -87,10 +122,45 @@ public class GraphSimplifier {
      * @param limit the limit number of the csg-cmp pair
      */
     public boolean simplifyGraph(int limit) {
-        // Now we only support simplify graph until the hyperGraph only 
contains one plan
-        Preconditions.checkArgument(limit == 1);
-        while (applySimplificationStep()) {
+        Preconditions.checkArgument(limit >= 1);
+        initFirstStep();
+        int lowerBound = 0;
+        int upperBound = 1;
+
+        // Try to probe the largest number of steps to satisfy the limit
+        int numApplySteps = 0;
+        Counter counter = new Counter(limit);
+        SubgraphEnumerator enumerator = new SubgraphEnumerator(counter, graph);
+        while (true) {
+            while (numApplySteps < upperBound) {
+                if (!applySimplificationStep()) {
+                    // If we have done all steps but still has more sub graphs
+                    // Just return
+                    if (!enumerator.enumerate()) {
+                        return false;
+                    }
+                    break;
+                }
+                numApplySteps += 1;
+            }
+            if (numApplySteps < upperBound || enumerator.enumerate()) {
+                break;
+            }
+            upperBound *= 2;
         }
+
+        // Try to search the lowest number of steps to satisfy the limit
+        upperBound = numApplySteps + 1;
+        while (lowerBound < upperBound) {
+            int mid = lowerBound + (upperBound - lowerBound) / 2;
+            applyStepsWithNum(mid);
+            if (enumerator.enumerate()) {
+                upperBound = mid;
+            } else {
+                lowerBound = mid + 1;
+            }
+        }
+        applyStepsWithNum(upperBound);
         return true;
     }
 
@@ -100,26 +170,62 @@ public class GraphSimplifier {
      * @return If there is no other steps, return false.
      */
     public boolean applySimplificationStep() {
-        if (priorityQueue.isEmpty()) {
+        boolean needProcessNeighbor = unAppliedSteps.isEmpty();
+        SimplificationStep bestStep = fetchSimplificationStep();
+        if (bestStep == null) {
             return false;
         }
+        appliedSteps.push(bestStep);
+        Preconditions.checkArgument(
+                cachePlan.containsKey(bestStep.newLeft) && 
cachePlan.containsKey(bestStep.newRight),
+                String.format("%s - %s", bestStep.newLeft, bestStep.newRight));
+        graph.modifyEdge(bestStep.afterIndex, bestStep.newLeft, 
bestStep.newRight);
+        if (needProcessNeighbor) {
+            processNeighbors(bestStep.afterIndex, 0, edgeSize);
+        }
+        return true;
+    }
+
+    private boolean unApplySimplificationStep() {
+        Preconditions.checkArgument(appliedSteps.size() > 0);
+        SimplificationStep bestStep = appliedSteps.pop();
+        unAppliedSteps.push(bestStep);
+        graph.modifyEdge(bestStep.afterIndex, bestStep.oldLeft, 
bestStep.oldRight);
+        // Note we don't need to delete this edge in circleDetector, because 
we don't need to
+        // recalculate neighbors until all steps applied
+        return true;
+    }
+
+    private @Nullable SimplificationStep fetchSimplificationStep() {
+        if (!unAppliedSteps.isEmpty()) {
+            return unAppliedSteps.pop();
+        }
+        if (priorityQueue.isEmpty()) {
+            return null;
+        }
         BestSimplification bestSimplification = priorityQueue.poll();
         bestSimplification.isInQueue = false;
         SimplificationStep bestStep = bestSimplification.getStep();
-        while (!circleDetector.tryAddDirectedEdge(bestStep.beforeIndex, 
bestStep.afterIndex)) {
+        while (bestSimplification.bestNeighbor == -1 || 
!circleDetector.tryAddDirectedEdge(bestStep.beforeIndex,
+                bestStep.afterIndex)) {
             if (priorityQueue.isEmpty()) {
-                return false;
+                return null;
             }
             bestSimplification = priorityQueue.poll();
             bestSimplification.isInQueue = false;
+            processNeighbors(bestStep.afterIndex, 0, edgeSize);
             bestStep = bestSimplification.getStep();
         }
-        Preconditions.checkArgument(
-                cachePlan.containsKey(bestStep.newLeft) && 
cachePlan.containsKey(bestStep.newRight),
-                String.format("%s - %s", bestStep.newLeft, bestStep.newRight));
-        graph.modifyEdge(bestStep.afterIndex, bestStep.newLeft, 
bestStep.newRight);
-        processNeighbors(bestStep.afterIndex, 0, edgeSize);
-        return true;
+        return bestStep;
+    }
+
+    private void applyStepsWithNum(int num) {
+        while (appliedSteps.size() < num) {
+            applySimplificationStep();
+        }
+        while (appliedSteps.size() > num) {
+            unApplySimplificationStep();
+        }
     }
 
     /**
@@ -148,11 +254,11 @@ public class GraphSimplifier {
         }
 
         // Go through the neighbors with higher index, we only need to 
recalculate all related steps
+        BestSimplification bestSimplification = 
simplifications.get(edgeIndex1);
+        bestSimplification.bestNeighbor = -1;
         for (int edgeIndex2 = Integer.max(beginIndex, edgeIndex1 + 1); 
edgeIndex2 < endIndex; edgeIndex2 += 1) {
-            BestSimplification bestSimplification = 
simplifications.get(edgeIndex1);
             Optional<SimplificationStep> optionalStep = 
makeSimplificationStep(edgeIndex1, edgeIndex2);
             if (optionalStep.isPresent()) {
-                bestSimplification.bestNeighbor = -1;
                 trySetSimplificationStep(optionalStep.get(), 
bestSimplification, edgeIndex1, edgeIndex2);
             }
         }
@@ -160,7 +266,8 @@ public class GraphSimplifier {
 
     private boolean trySetSimplificationStep(SimplificationStep step, 
BestSimplification bestSimplification,
             int index, int neighborIndex) {
-        if (bestSimplification.bestNeighbor == -1 || 
bestSimplification.getBenefit() <= step.getBenefit()) {
+        if (bestSimplification.bestNeighbor == -1 || 
bestSimplification.isInQueue == false
+                || bestSimplification.getBenefit() <= step.getBenefit()) {
             bestSimplification.bestNeighbor = neighborIndex;
             bestSimplification.setStep(step);
             updatePriorityQueue(index);
@@ -284,14 +391,14 @@ public class GraphSimplifier {
             }
             // choose edge1Before2
             step = new SimplificationStep(benefit, edgeIndex1, edgeIndex2, 
edge1Before2.getLeft(),
-                    edge1Before2.getRight());
+                    edge1Before2.getRight(), 
graph.getEdge(edgeIndex2).getLeft(), graph.getEdge(edgeIndex2).getRight());
         } else {
             if (cost2Before1 != 0) {
                 benefit = cost1Before2 / cost2Before1;
             }
             // choose edge2Before1
             step = new SimplificationStep(benefit, edgeIndex2, edgeIndex1, 
edge2Before1.getLeft(),
-                    edge2Before1.getRight());
+                    edge2Before1.getRight(), 
graph.getEdge(edgeIndex1).getLeft(), graph.getEdge(edgeIndex1).getRight());
         }
         return step;
     }
@@ -308,8 +415,8 @@ public class GraphSimplifier {
     }
 
     private double getSimpleCost(Plan plan) {
-        if (plan instanceof GroupPlan) {
-            return ((GroupPlan) plan).getGroup().getStatistics().getRowCount();
+        if (!(plan instanceof LogicalJoin)) {
+            return 
plan.getGroupExpression().get().getOwnerGroup().getStatistics().getRowCount();
         }
         return 
plan.getGroupExpression().get().getCostByProperties(PhysicalProperties.ANY);
     }
@@ -360,11 +467,16 @@ public class GraphSimplifier {
         int afterIndex;
         BitSet newLeft;
         BitSet newRight;
+        BitSet oldLeft;
+        BitSet oldRight;
 
-        SimplificationStep(double benefit, int beforeIndex, int afterIndex, 
BitSet newLeft, BitSet newRight) {
+        SimplificationStep(double benefit, int beforeIndex, int afterIndex, 
BitSet newLeft, BitSet newRight,
+                BitSet oldLeft, BitSet oldRight) {
             this.afterIndex = afterIndex;
             this.beforeIndex = beforeIndex;
             this.benefit = benefit;
+            this.oldLeft = oldLeft;
+            this.oldRight = oldRight;
             this.newLeft = newLeft;
             this.newRight = newRight;
         }
@@ -381,7 +493,7 @@ public class GraphSimplifier {
 
         @Override
         public String toString() {
-            return String.format("%d -> %d %.2f : %s-%s", beforeIndex, 
afterIndex, benefit, newLeft, newRight);
+            return String.format("%d -> %d", beforeIndex, afterIndex);
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/HyperGraph.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java
similarity index 76%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/HyperGraph.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java
index 15f00a3bf6..3155bfec9a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/HyperGraph.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java
@@ -15,16 +15,15 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
-import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -41,13 +40,6 @@ import java.util.Set;
 public class HyperGraph {
     private List<Edge> edges = new ArrayList<>();
     private List<Node> nodes = new ArrayList<>();
-    private Plan bestPlan;
-
-    public static HyperGraph fromPlan(Plan plan) {
-        HyperGraph graph = new HyperGraph();
-        graph.buildGraph(plan);
-        return graph;
-    }
 
     public List<Edge> getEdges() {
         return edges;
@@ -57,6 +49,10 @@ public class HyperGraph {
         return nodes;
     }
 
+    public BitSet getNodesMap() {
+        return Bitmap.newBitmapBetween(0, nodes.size());
+    }
+
     public Edge getEdge(int index) {
         return edges.get(index);
     }
@@ -65,86 +61,26 @@ public class HyperGraph {
         return nodes.get(index);
     }
 
-    /**
-     * Extract the best plan of HyperGraph
-     *
-     * @return return the best plan
-     */
-    public Plan toPlan() {
-        return bestPlan;
-    }
-
-    public boolean simplify() {
-        GraphSimplifier graphSimplifier = new GraphSimplifier(this);
-        graphSimplifier.initFirstStep();
-        return graphSimplifier.simplifyGraph(1);
-    }
-
-    /**
-     * Try to enumerate all csg-cmp pairs and get the best plan
-     *
-     * @return whether enumerate successfully
-     */
-    public boolean emitPlan() {
-        return false;
-    }
-
-    public boolean optimize() {
-        return simplify() && emitPlan();
-    }
-
     public void splitEdgesForNodes() {
         for (Node node : nodes) {
             node.splitEdges();
         }
     }
 
-    private void buildGraph(Plan plan) {
-        if ((plan instanceof LogicalProject && plan.child(0) instanceof 
GroupPlan)
-                || plan instanceof GroupPlan) {
-            nodes.add(new Node(nodes.size(), plan));
-            return;
-        }
-
-        LogicalJoin<? extends Plan, ? extends Plan> join;
-        if (plan instanceof LogicalProject) {
-            LogicalProject<? extends Plan> project = (LogicalProject<? extends 
Plan>) plan;
-            join = (LogicalJoin<? extends Plan, ? extends Plan>) 
project.child();
-
-            // Handle project
-            // Ignore the projection expression just using for selection 
column.
-            // TODO: how to handle Alias and complex project expression
-        } else {
-            join = (LogicalJoin<? extends Plan, ? extends Plan>) plan;
-        }
-
-        // Now we only support inner join with Inside-Project
-        // TODO: Other joins can be added according CD-C algorithm
-        if (join.getJoinType() != JoinType.INNER_JOIN) {
-            Node node = new Node(nodes.size(), plan);
-            nodes.add(node);
-            return;
-        }
-
-        buildGraph(join.left());
-        buildGraph(join.right());
-        addEdge(join);
-    }
-
-    private BitSet findNodes(Set<Slot> slots) {
-        BitSet bitSet = Bitmap.newBitmap();
-        for (Node node : nodes) {
-            for (Slot slot : node.getPlan().getOutput()) {
-                if (slots.contains(slot)) {
-                    Bitmap.set(bitSet, node.getIndex());
-                    break;
-                }
-            }
-        }
-        return bitSet;
+    public void addNode(Group group) {
+        Preconditions.checkArgument(!group.isJoinGroup());
+        // TODO: replace plan with group expression or others
+        nodes.add(new Node(nodes.size(), group));
     }
 
-    private void addEdge(LogicalJoin<? extends Plan, ? extends Plan> join) {
+    /**
+     * try to add edge for join group
+     *
+     * @param group The join group
+     */
+    public void addEdge(Group group) {
+        Preconditions.checkArgument(group.isJoinGroup());
+        LogicalJoin<? extends Plan, ? extends Plan> join = (LogicalJoin) 
group.getLogicalExpression().getPlan();
         for (Expression expression : join.getExpressions()) {
             LogicalJoin singleJoin = new LogicalJoin(join.getJoinType(), 
ImmutableList.of(expression), join.left(),
                     join.right());
@@ -165,6 +101,19 @@ public class HyperGraph {
         // We don't implement this trick now.
     }
 
+    private BitSet findNodes(Set<Slot> slots) {
+        BitSet bitSet = Bitmap.newBitmap();
+        for (Node node : nodes) {
+            for (Slot slot : node.getPlan().getOutput()) {
+                if (slots.contains(slot)) {
+                    Bitmap.set(bitSet, node.getIndex());
+                    break;
+                }
+            }
+        }
+        return bitSet;
+    }
+
     /**
      * Graph simplifier need to update the edge for join ordering
      *
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/Node.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/Node.java
similarity index 79%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/Node.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/Node.java
index 51712e24f2..8eb4bb843e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/Node.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/Node.java
@@ -15,14 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
-import org.apache.doris.nereids.trees.plans.GroupPlan;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.trees.plans.Plan;
 
-import com.google.common.base.Preconditions;
-
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
@@ -33,7 +31,7 @@ import javax.annotation.Nullable;
  */
 public class Node {
     private final int index;
-    private Plan plan;
+    private Group group;
     private List<Edge> edges = new ArrayList<>();
     // We split these into simple edges (only one node on each side) and 
complex edges (others)
     // because we can often quickly discard all simple edges by testing the 
set of interesting nodes
@@ -43,8 +41,8 @@ public class Node {
     private List<Edge> simpleEdges = new ArrayList<>();
     private BitSet complexNeighborhood = new BitSet();
 
-    public Node(int index, Plan plan) {
-        this.plan = plan;
+    public Node(int index, Group group) {
+        this.group = group;
         this.index = index;
     }
 
@@ -65,7 +63,11 @@ public class Node {
             throw new RuntimeException(String.format("There is no simple Edge 
<%d - %s>", index, nodes));
         } else if (Bitmap.isOverlap(complexNeighborhood, nodes)) {
             for (Edge edge : complexEdges) {
-                if (Bitmap.isSubset(edge.getLeft(), nodes) || 
Bitmap.isSubset(edge.getRight(), nodes)) {
+                // TODO: Right now we check all edges. But due to the simple 
cmp, we can only check that the edge with
+                // one side that equal to this node
+                if ((Bitmap.isSubset(edge.getLeft(), nodes) && 
Bitmap.isSubset(edge.getRight(),
+                        Bitmap.newBitmap(index))) || 
(Bitmap.isSubset(edge.getRight(), nodes) && Bitmap.isSubset(
+                        edge.getLeft(), Bitmap.newBitmap(index)))) {
                     return edge;
                 }
             }
@@ -82,12 +84,12 @@ public class Node {
     }
 
     public Plan getPlan() {
-        return plan;
+        return group.getLogicalExpression().getPlan();
     }
 
-    public void setPlan(Plan plan) {
-        this.plan = plan;
-    }
+    //    public void setPlan(Plan plan) {
+    //        this.plan = plan;
+    //    }
 
     public List<Edge> getComplexEdges() {
         return complexEdges;
@@ -137,6 +139,10 @@ public class Node {
      * by graph simplifier.
      */
     public void splitEdges() {
+        simpleEdges.clear();
+        Bitmap.clear(simpleNeighborhood);
+        complexEdges.clear();
+        Bitmap.clear(complexNeighborhood);
         for (Edge edge : edges) {
             if (edge.isSimple()) {
                 simpleEdges.add(edge);
@@ -153,12 +159,14 @@ public class Node {
     }
 
     public String getName() {
-        Preconditions.checkArgument(plan instanceof GroupPlan, "Each node is a 
group plan in child");
-        return ((GroupPlan) 
plan).getGroup().getLogicalExpression().getPlan().getType().name() + index;
+        return getPlan().getType().name() + index;
     }
 
     public double getRowCount() {
-        Preconditions.checkArgument(plan instanceof GroupPlan, "Each node is a 
group plan in child");
-        return ((GroupPlan) plan).getGroup().getStatistics().getRowCount();
+        return group.getStatistics().getRowCount();
+    }
+
+    public Group getGroup() {
+        return group;
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/SubgraphEnumerator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/SubgraphEnumerator.java
similarity index 80%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/SubgraphEnumerator.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/SubgraphEnumerator.java
index d17cd06f1c..03be7bf34c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/SubgraphEnumerator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/SubgraphEnumerator.java
@@ -15,11 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
-import 
org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.SubsetIterator;
-import 
org.apache.doris.nereids.rules.joinreorder.hypergraph.receiver.AbstractReceiver;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import 
org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.SubsetIterator;
+import 
org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver.AbstractReceiver;
 
 import java.util.BitSet;
 import java.util.List;
@@ -35,7 +35,7 @@ public class SubgraphEnumerator {
     //The enumerated hyperGraph
     HyperGraph hyperGraph;
 
-    SubgraphEnumerator(AbstractReceiver receiver, HyperGraph hyperGraph) {
+    public SubgraphEnumerator(AbstractReceiver receiver, HyperGraph 
hyperGraph) {
         this.receiver = receiver;
         this.hyperGraph = hyperGraph;
     }
@@ -46,10 +46,11 @@ public class SubgraphEnumerator {
      * @return whether the hyperGraph is enumerated successfully
      */
     public boolean enumerate() {
+        receiver.reset();
         List<Node> nodes = hyperGraph.getNodes();
         // Init all nodes in Receiver
         for (Node node : nodes) {
-            receiver.addPlan(node.getBitSet(), node.getPlan());
+            receiver.addGroup(node.getBitSet(), node.getGroup());
         }
         hyperGraph.splitEdgesForNodes();
         int size = nodes.size();
@@ -59,32 +60,38 @@ public class SubgraphEnumerator {
         for (int i = size - 2; i >= 0; i--) {
             BitSet csg = Bitmap.newBitmap(i);
             Bitmap.unset(forbiddenNodes, i);
-            emitCsg(csg);
-            enumerateCsgRec(csg, Bitmap.newBitmap(forbiddenNodes));
+            if (!emitCsg(csg) || !enumerateCsgRec(csg, 
Bitmap.newBitmap(forbiddenNodes))) {
+                return false;
+            }
         }
         return true;
     }
 
     // The general purpose of EnumerateCsgRec is to extend a given set csg, 
which
     // induces a connected subgraph of G to a larger set with the same 
property.
-    private void enumerateCsgRec(BitSet csg, BitSet forbiddenNodes) {
+    private boolean enumerateCsgRec(BitSet csg, BitSet forbiddenNodes) {
         BitSet neighborhood = calcNeighborhood(csg, forbiddenNodes);
         SubsetIterator subsetIterator = Bitmap.getSubsetIterator(neighborhood);
         for (BitSet subset : subsetIterator) {
             BitSet newCsg = Bitmap.newBitmapUnion(csg, subset);
             if (receiver.contain(newCsg)) {
-                emitCsg(newCsg);
+                if (!emitCsg(newCsg)) {
+                    return false;
+                }
             }
         }
         Bitmap.or(forbiddenNodes, neighborhood);
         subsetIterator.reset();
         for (BitSet subset : subsetIterator) {
             BitSet newCsg = Bitmap.newBitmapUnion(csg, subset);
-            enumerateCsgRec(newCsg, Bitmap.newBitmap(forbiddenNodes));
+            if (!enumerateCsgRec(newCsg, Bitmap.newBitmap(forbiddenNodes))) {
+                return false;
+            }
         }
+        return true;
     }
 
-    private void enumerateCmpRec(BitSet csg, BitSet cmp, BitSet 
forbiddenNodes) {
+    private boolean enumerateCmpRec(BitSet csg, BitSet cmp, BitSet 
forbiddenNodes) {
         BitSet neighborhood = calcNeighborhood(cmp, forbiddenNodes);
         SubsetIterator subsetIterator = new SubsetIterator(neighborhood);
         for (BitSet subset : subsetIterator) {
@@ -96,7 +103,9 @@ public class SubgraphEnumerator {
                 for (Edge edge : hyperGraph.getEdges()) {
                     if (Bitmap.isSubset(edge.getLeft(), csg) && 
Bitmap.isSubset(edge.getRight(), newCmp) || (
                             Bitmap.isSubset(edge.getLeft(), newCmp) && 
Bitmap.isSubset(edge.getRight(), csg))) {
-                        receiver.emitCsgCmp(csg, newCmp, edge);
+                        if (!receiver.emitCsgCmp(csg, newCmp, edge)) {
+                            return false;
+                        }
                         break;
                     }
                 }
@@ -106,24 +115,30 @@ public class SubgraphEnumerator {
         subsetIterator.reset();
         for (BitSet subset : subsetIterator) {
             BitSet newCmp = Bitmap.newBitmapUnion(cmp, subset);
-            enumerateCmpRec(csg, newCmp, Bitmap.newBitmap(forbiddenNodes));
+            if (!enumerateCmpRec(csg, newCmp, 
Bitmap.newBitmap(forbiddenNodes))) {
+                return false;
+            }
         }
+        return true;
     }
 
     // EmitCsg takes as an argument a non-empty, proper subset csg of 
HyperGraph , which
     // induces a connected subgraph. It is then responsible to generate the 
seeds for
     // all cmp such that (csg, cmp) becomes a csg-cmp-pair.
-    private void emitCsg(BitSet csg) {
+    private boolean emitCsg(BitSet csg) {
         BitSet forbiddenNodes = Bitmap.newBitmapBetween(0, 
Bitmap.nextSetBit(csg, 0));
         Bitmap.or(forbiddenNodes, csg);
         BitSet neighborhoods = calcNeighborhood(csg, 
Bitmap.newBitmap(forbiddenNodes));
+
         for (int nodeIndex : Bitmap.getReverseIterator(neighborhoods)) {
             BitSet cmp = Bitmap.newBitmap(nodeIndex);
             // whether there is an edge between csg and cmp
             Node cmpNode = hyperGraph.getNode(nodeIndex);
             Edge edge = cmpNode.tryGetEdgeWith(csg);
             if (edge != null) {
-                receiver.emitCsgCmp(csg, cmp, edge);
+                if (!receiver.emitCsgCmp(csg, cmp, edge)) {
+                    return false;
+                }
             }
 
             // In order to avoid enumerate repeated cmp, e.g.,
@@ -138,8 +153,11 @@ public class SubgraphEnumerator {
             BitSet newForbiddenNodes = Bitmap.newBitmapBetween(0, nodeIndex + 
1);
             Bitmap.and(newForbiddenNodes, neighborhoods);
             Bitmap.or(newForbiddenNodes, forbiddenNodes);
-            enumerateCmpRec(csg, cmp, newForbiddenNodes);
+            if (!enumerateCmpRec(csg, cmp, newForbiddenNodes)) {
+                return false;
+            }
         }
+        return true;
     }
 
     // This function is used to calculate neighborhoods of given subgraph.
@@ -163,9 +181,9 @@ public class SubgraphEnumerator {
         for (Edge edge : hyperGraph.getEdges()) {
             BitSet left = edge.getLeft();
             BitSet right = edge.getRight();
-            if (Bitmap.isSubset(left, subGraph) && !Bitmap.isOverlap(left, 
forbiddenNodes)) {
+            if (Bitmap.isSubset(left, subGraph) && !Bitmap.isOverlap(right, 
forbiddenNodes)) {
                 Bitmap.set(neighborhoods, right.nextSetBit(0));
-            } else if (Bitmap.isSubset(right, subGraph) && 
!Bitmap.isOverlap(right, forbiddenNodes)) {
+            } else if (Bitmap.isSubset(right, subGraph) && 
!Bitmap.isOverlap(left, forbiddenNodes)) {
                 Bitmap.set(neighborhoods, left.nextSetBit(0));
             }
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/BitSetIterator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/BitSetIterator.java
similarity index 96%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/BitSetIterator.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/BitSetIterator.java
index 1c1af0b1f1..77d55da361 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/BitSetIterator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/BitSetIterator.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap;
 
 import org.jetbrains.annotations.NotNull;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/Bitmap.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/Bitmap.java
similarity index 98%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/Bitmap.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/Bitmap.java
index 27ba8d5994..619a9edf62 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/Bitmap.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/Bitmap.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap;
 
 import java.util.BitSet;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/ReverseBitSetIterator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/ReverseBitSetIterator.java
similarity index 96%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/ReverseBitSetIterator.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/ReverseBitSetIterator.java
index b039fbed9d..125f05dc1c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/ReverseBitSetIterator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/ReverseBitSetIterator.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap;
 
 import org.jetbrains.annotations.NotNull;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/SubsetIterator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/SubsetIterator.java
similarity index 97%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/SubsetIterator.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/SubsetIterator.java
index 0f48b3ad2f..8b7c2921df 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/bitmap/SubsetIterator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/bitmap/SubsetIterator.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap;
 
 import org.jetbrains.annotations.NotNull;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/AbstractReceiver.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/AbstractReceiver.java
similarity index 77%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/AbstractReceiver.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/AbstractReceiver.java
index 1d6da72803..13c85595d1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/AbstractReceiver.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/AbstractReceiver.java
@@ -15,10 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph.receiver;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.Edge;
-import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.Edge;
+import org.apache.doris.nereids.memo.Group;
 
 import java.util.BitSet;
 
@@ -28,9 +28,11 @@ import java.util.BitSet;
 public interface AbstractReceiver {
     public boolean emitCsgCmp(BitSet csg, BitSet cmp, Edge edge);
 
-    public void addPlan(BitSet bitSet, Plan plan);
+    public void addGroup(BitSet bitSet, Group group);
 
     public boolean contain(BitSet bitSet);
 
-    public Plan getBestPlan(BitSet bitSet);
+    public void reset();
+
+    public Group getBestPlan(BitSet bitSet);
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/Counter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java
similarity index 77%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/Counter.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java
index 5633d1b9c9..b3bba9a2e8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/Counter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java
@@ -15,10 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph.receiver;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.Edge;
-import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.Edge;
+import org.apache.doris.nereids.memo.Group;
 
 import com.google.common.base.Preconditions;
 
@@ -30,8 +30,18 @@ import java.util.HashMap;
  */
 public class Counter implements AbstractReceiver {
     // limit define the max number of csg-cmp pair in this Receiver
+    private int limit;
+    private int emitCount = 0;
     private HashMap<BitSet, Integer> counter = new HashMap<>();
 
+    public Counter() {
+        this.limit = Integer.MAX_VALUE;
+    }
+
+    public Counter(int limit) {
+        this.limit = limit;
+    }
+
     /**
      * Emit a new plan from bottom to top
      *
@@ -43,6 +53,10 @@ public class Counter implements AbstractReceiver {
     public boolean emitCsgCmp(BitSet left, BitSet right, Edge edge) {
         Preconditions.checkArgument(counter.containsKey(left));
         Preconditions.checkArgument(counter.containsKey(right));
+        emitCount += 1;
+        if (emitCount > limit) {
+            return false;
+        }
         BitSet bitSet = new BitSet();
         bitSet.or(left);
         bitSet.or(right);
@@ -54,7 +68,7 @@ public class Counter implements AbstractReceiver {
         return true;
     }
 
-    public void addPlan(BitSet bitSet, Plan plan) {
+    public void addGroup(BitSet bitSet, Group group) {
         counter.put(bitSet, 1);
     }
 
@@ -62,7 +76,12 @@ public class Counter implements AbstractReceiver {
         return counter.containsKey(bitSet);
     }
 
-    public Plan getBestPlan(BitSet bitSet) {
+    public void reset() {
+        this.counter.clear();
+        emitCount = 0;
+    }
+
+    public Group getBestPlan(BitSet bitSet) {
         throw new RuntimeException("Counter does not support getBestPlan()");
     }
 
@@ -73,4 +92,8 @@ public class Counter implements AbstractReceiver {
     public HashMap<BitSet, Integer> getAllCount() {
         return counter;
     }
+
+    public int getLimit() {
+        return limit;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java
new file mode 100644
index 0000000000..be708902a9
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java
@@ -0,0 +1,140 @@
+// 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.jobs.joinorder.hypergraph.receiver;
+
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.Edge;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.stats.StatsCalculator;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import java.util.BitSet;
+import java.util.HashMap;
+
+/**
+ * The Receiver is used for cached the plan that has been emitted and build 
the new plan
+ */
+public class PlanReceiver implements AbstractReceiver {
+    // limit define the max number of csg-cmp pair in this Receiver
+    HashMap<BitSet, Group> planTable = new HashMap<>();
+    int limit;
+    int emitCount = 0;
+
+    public PlanReceiver() {
+        limit = Integer.MAX_VALUE;
+    }
+
+    public PlanReceiver(int limit) {
+        this.limit = limit;
+    }
+
+    /**
+     * Emit a new plan from bottom to top
+     *
+     * @param left the bitmap of left child tree
+     * @param right the bitmap of the right child tree
+     * @param edge the join operator
+     * @return the left and the right can be connected by the edge
+     */
+    @Override
+    public boolean emitCsgCmp(BitSet left, BitSet right, Edge edge) {
+        Preconditions.checkArgument(planTable.containsKey(left));
+        Preconditions.checkArgument(planTable.containsKey(right));
+        emitCount += 1;
+        if (emitCount > limit) {
+            return false;
+        }
+        BitSet fullKey = Bitmap.newBitmapUnion(left, right);
+        Group group1 = constructGroup(left, right, edge);
+        Group group2 = constructGroup(right, left, edge);
+        Group winnerGroup;
+        if 
(group1.getLogicalExpression().getCostByProperties(PhysicalProperties.ANY) < 
group2.getLogicalExpression()
+                .getCostByProperties(PhysicalProperties.ANY)) {
+            winnerGroup = group1;
+        } else {
+            winnerGroup = group2;
+        }
+
+        if (!planTable.containsKey(fullKey)
+                || 
planTable.get(fullKey).getLogicalExpression().getCostByProperties(PhysicalProperties.ANY)
+                > 
winnerGroup.getLogicalExpression().getCostByProperties(PhysicalProperties.ANY)) 
{
+            planTable.put(fullKey, winnerGroup);
+        }
+        return true;
+    }
+
+    @Override
+    public void addGroup(BitSet bitSet, Group group) {
+        planTable.put(bitSet, group);
+    }
+
+    @Override
+    public boolean contain(BitSet bitSet) {
+        return planTable.containsKey(bitSet);
+    }
+
+    @Override
+    public void reset() {
+        planTable.clear();
+        emitCount = 0;
+    }
+
+    @Override
+    public Group getBestPlan(BitSet bitSet) {
+        Preconditions.checkArgument(planTable.containsKey(bitSet));
+        return planTable.get(bitSet);
+    }
+
+    private double getSimpleCost(Plan plan) {
+        if (!(plan instanceof LogicalJoin)) {
+            return 
plan.getGroupExpression().get().getOwnerGroup().getStatistics().getRowCount();
+        }
+        return 
plan.getGroupExpression().get().getCostByProperties(PhysicalProperties.ANY);
+    }
+
+    private Group constructGroup(BitSet left, BitSet right, Edge edge) {
+        Preconditions.checkArgument(planTable.containsKey(left));
+        Preconditions.checkArgument(planTable.containsKey(right));
+        Group leftGroup = planTable.get(left);
+        Group rightGroup = planTable.get(right);
+        Plan leftPlan = leftGroup.getLogicalExpression().getPlan();
+        Plan rightPlan = rightGroup.getLogicalExpression().getPlan();
+
+        double cost = getSimpleCost(leftPlan) + getSimpleCost(rightPlan);
+        LogicalJoin newJoin = new LogicalJoin(edge.getJoin().getJoinType(), 
edge.getJoin().getExpressions(),
+                leftGroup.getLogicalExpression().getPlan(),
+                rightGroup.getLogicalExpression().getPlan());
+
+        GroupExpression groupExpression = new GroupExpression(newJoin, 
Lists.newArrayList(leftGroup, rightGroup));
+        Group group = new Group();
+        group.addGroupExpression(groupExpression);
+        StatsCalculator.estimate(groupExpression);
+        cost += group.getStatistics().getRowCount();
+
+        groupExpression.updateLowestCostTable(PhysicalProperties.ANY,
+                Lists.newArrayList(PhysicalProperties.ANY, 
PhysicalProperties.ANY), cost);
+        return group;
+    }
+}
+
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 e699e74eb3..ca7e47a0f9 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
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.memo;
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.util.TreeStringUtils;
 import org.apache.doris.statistics.StatsDeriveResult;
@@ -316,6 +317,10 @@ public class Group {
         lowestCostPlans.clear();
     }
 
+    public boolean isJoinGroup() {
+        return getLogicalExpression().getPlan() instanceof LogicalJoin;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java
index d7cf89ed3b..da5b65f1c0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java
@@ -105,6 +105,11 @@ public class GroupExpression {
         return children.get(i);
     }
 
+    public void setChild(int i, Group group) {
+        children.set(i, group);
+        group.addParentExpression(this);
+    }
+
     public List<Group> children() {
         return children;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorder.java
deleted file mode 100644
index 52d1609b9c..0000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorder.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.rules.joinreorder;
-
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.HyperGraph;
-import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
-import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
-import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
-
-/**
- * This rule is for Join Reorder (non Cascades Transfrom Join Reorder).
- */
-public class HyperGraphJoinReorder extends OneRewriteRuleFactory {
-    @Override
-    public Rule build() {
-        // TODO: we need a pattern to match a subtree of join and mark the 
node in this tree ordered
-        return logicalJoin(
-                subTree(LogicalJoin.class, LogicalProject.class),
-                subTree(LogicalJoin.class, LogicalProject.class))
-                .thenApply(ctx -> {
-                    LogicalJoin<? extends Plan, ? extends Plan> rootJoin = 
ctx.root;
-                    // TODO: check mark.
-                    HyperGraph graph = HyperGraph.fromPlan(rootJoin);
-                    if (graph.optimize()) {
-                        return graph.toPlan();
-                    }
-                    return null;
-                }).toRule(RuleType.JOIN_REORDER);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupLeft.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupLeft.java
deleted file mode 100644
index 56aa07a0fc..0000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupLeft.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.rules.joinreorder;
-
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.HyperGraph;
-import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
-import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
-import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
-
-/**
- * This rule is for Join Reorder (non Cascades Transfrom Join Reorder).
- */
-public class HyperGraphJoinReorderGroupLeft extends OneRewriteRuleFactory {
-    @Override
-    public Rule build() {
-        // TODO: we need a pattern to match a subtree of join and mark the 
node in this tree ordered
-        return logicalJoin(
-                group(),
-                subTree(LogicalJoin.class, LogicalProject.class))
-                .thenApply(ctx -> {
-                    LogicalJoin<? extends Plan, ? extends Plan> rootJoin = 
ctx.root;
-                    HyperGraph graph = HyperGraph.fromPlan(rootJoin);
-                    System.out.println(graph.toDottyHyperGraph());
-                    if (graph.optimize()) {
-                        return graph.toPlan();
-                    }
-                    return null;
-                }).toRule(RuleType.JOIN_REORDER);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupRight.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupRight.java
deleted file mode 100644
index c1f3d1e16c..0000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupRight.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.rules.joinreorder;
-
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.RuleType;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.HyperGraph;
-import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
-import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
-import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
-
-/**
- * This rule is for Join Reorder (non Cascades Transfrom Join Reorder).
- */
-public class HyperGraphJoinReorderGroupRight extends OneRewriteRuleFactory {
-    @Override
-    public Rule build() {
-        // TODO: we need a pattern to match a subtree of join and mark the 
node in this tree ordered
-        return logicalJoin(
-                subTree(LogicalJoin.class, LogicalProject.class),
-                group())
-                .thenApply(ctx -> {
-                    LogicalJoin<? extends Plan, ? extends Plan> rootJoin = 
ctx.root;
-                    HyperGraph graph = HyperGraph.fromPlan(rootJoin);
-                    if (graph.optimize()) {
-                        return graph.toPlan();
-                    }
-                    return null;
-                }).toRule(RuleType.JOIN_REORDER);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/PlanTable.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/PlanTable.java
deleted file mode 100644
index 2cb9b62d23..0000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/receiver/PlanTable.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.rules.joinreorder.hypergraph.receiver;
-
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.Edge;
-import org.apache.doris.nereids.trees.plans.Plan;
-
-import java.util.BitSet;
-import java.util.HashMap;
-
-/**
- * The Receiver is used for cached the plan that has been emitted and build 
the new plan
- */
-public class PlanTable implements AbstractReceiver {
-    // limit define the max number of csg-cmp pair in this Receiver
-    HashMap<BitSet, Integer> counter;
-
-    /**
-     * Emit a new plan from bottom to top
-     *
-     * @param left the bitmap of left child tree
-     * @param right the bitmap of the right child tree
-     * @param edge the join operator
-     * @return the left and the right can be connected by the edge
-     */
-    public boolean emitCsgCmp(BitSet left, BitSet right, Edge edge) {
-        throw new RuntimeException("PlanTable does not support emitCsgCmp()");
-    }
-
-    public void addPlan(BitSet bitSet, Plan plan) {
-        throw new RuntimeException("PlanTable does not support addPlan()");
-    }
-
-    public boolean contain(BitSet bitSet) {
-        throw new RuntimeException("PlanTable does not support contain()");
-    }
-
-    public Plan getBestPlan(BitSet bitSet) {
-        throw new RuntimeException("PlanTable does not support getBestPlan()");
-    }
-}
-
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupLeftTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJobTest.java
similarity index 85%
rename from 
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupLeftTest.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJobTest.java
index b8d74d555b..93edf18663 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupLeftTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJobTest.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder;
+package org.apache.doris.nereids.jobs.joinorder;
 
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.trees.plans.JoinType;
@@ -26,17 +26,18 @@ import org.apache.doris.nereids.util.MemoTestUtils;
 import org.apache.doris.nereids.util.PlanChecker;
 import org.apache.doris.nereids.util.PlanConstructor;
 
+import com.google.common.collect.Lists;
 import org.junit.jupiter.api.Test;
 
-class HyperGraphJoinReorderGroupLeftTest {
-    private final LogicalOlapScan scan1 = 
PlanConstructor.newLogicalOlapScan(0, "t1", 0);
-    private final LogicalOlapScan scan2 = 
PlanConstructor.newLogicalOlapScan(1, "t2", 0);
-    private final LogicalOlapScan scan3 = 
PlanConstructor.newLogicalOlapScan(2, "t3", 0);
-    private final LogicalOlapScan scan4 = 
PlanConstructor.newLogicalOlapScan(3, "t4", 0);
-    private final LogicalOlapScan scan5 = 
PlanConstructor.newLogicalOlapScan(4, "t5", 0);
+public class JoinOrderJobTest {
+    private final LogicalOlapScan scan1 = 
PlanConstructor.newLogicalOlapScan(1, "t1", 0);
+    private final LogicalOlapScan scan2 = 
PlanConstructor.newLogicalOlapScan(2, "t2", 0);
+    private final LogicalOlapScan scan3 = 
PlanConstructor.newLogicalOlapScan(3, "t3", 0);
+    private final LogicalOlapScan scan4 = 
PlanConstructor.newLogicalOlapScan(4, "t4", 0);
+    private final LogicalOlapScan scan5 = 
PlanConstructor.newLogicalOlapScan(5, "t5", 0);
 
     @Test
-    void test() {
+    void testJoinOrderJob() {
         LogicalPlan plan = new LogicalPlanBuilder(scan1)
                 .hashJoinUsing(
                         new LogicalPlanBuilder(scan2)
@@ -46,11 +47,12 @@ class HyperGraphJoinReorderGroupLeftTest {
                                 .build(),
                         JoinType.INNER_JOIN, Pair.of(0, 1)
                 )
+                .project(Lists.newArrayList(1))
                 .build();
-
+        System.out.println(plan.treeString());
         PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
                 .deriveStats()
-                .applyTopDown(new HyperGraphJoinReorderGroupLeft())
+                .orderJoin()
                 .printlnTree();
     }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/BitSetTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/BitSetTest.java
similarity index 86%
rename from 
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/BitSetTest.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/BitSetTest.java
index 8a40a0a534..20b69583ac 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/BitSetTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/BitSetTest.java
@@ -15,10 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
-import 
org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.SubsetIterator;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import 
org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.SubsetIterator;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/CircleDetectorTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CircleDetectorTest.java
similarity index 96%
rename from 
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/CircleDetectorTest.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CircleDetectorTest.java
index de654924ea..bee8b56059 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/CircleDetectorTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/CircleDetectorTest.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
 import com.google.common.collect.ImmutableList;
 import org.junit.jupiter.api.Assertions;
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/GraphSimplifierTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java
similarity index 81%
rename from 
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/GraphSimplifierTest.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java
index d0365615ca..ec6790f41d 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/GraphSimplifierTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java
@@ -15,9 +15,9 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.receiver.Counter;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver.Counter;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.util.HyperGraphBuilder;
 
@@ -33,7 +33,7 @@ public class GraphSimplifierTest {
         //      |
         //     t2
         HyperGraph hyperGraph = new HyperGraphBuilder()
-                .init(10, 20, 30, 40, 50)
+                .init(10, 30, 20, 40, 50)
                 .addEdge(JoinType.INNER_JOIN, 0, 1)
                 .addEdge(JoinType.INNER_JOIN, 0, 2)
                 .addEdge(JoinType.INNER_JOIN, 0, 3)
@@ -47,8 +47,9 @@ public class GraphSimplifierTest {
         SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(counter, hyperGraph);
         subgraphEnumerator.enumerate();
         for (int count : counter.getAllCount().values()) {
-            Assertions.assertEquals(count, 1);
+            Assertions.assertTrue(count < 10);
         }
+        Assertions.assertTrue(graphSimplifier.isTotalOrder());
     }
 
     @Test
@@ -74,8 +75,9 @@ public class GraphSimplifierTest {
         SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(counter, hyperGraph);
         subgraphEnumerator.enumerate();
         for (int count : counter.getAllCount().values()) {
-            Assertions.assertEquals(count, 1);
+            Assertions.assertTrue(count < 10);
         }
+        Assertions.assertTrue(graphSimplifier.isTotalOrder());
     }
 
     @Test
@@ -102,8 +104,9 @@ public class GraphSimplifierTest {
         SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(counter, hyperGraph);
         subgraphEnumerator.enumerate();
         for (int count : counter.getAllCount().values()) {
-            Assertions.assertEquals(count, 1);
+            Assertions.assertTrue(count < 10);
         }
+        Assertions.assertTrue(graphSimplifier.isTotalOrder());
     }
 
     @Test
@@ -135,8 +138,9 @@ public class GraphSimplifierTest {
         SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(counter, hyperGraph);
         subgraphEnumerator.enumerate();
         for (int count : counter.getAllCount().values()) {
-            Assertions.assertEquals(count, 1);
+            Assertions.assertTrue(count < 10);
         }
+        Assertions.assertTrue(graphSimplifier.isTotalOrder());
     }
 
     @Test
@@ -160,8 +164,8 @@ public class GraphSimplifierTest {
 
     @Test
     void testRandomQuery() {
-        for (int i = 0; i < 10; i++) {
-            HyperGraph hyperGraph = new 
HyperGraphBuilder().randomBuildWith(10, 40);
+        for (int i = 0; i < 100; i++) {
+            HyperGraph hyperGraph = new 
HyperGraphBuilder().randomBuildWith(20, 40);
             GraphSimplifier graphSimplifier = new GraphSimplifier(hyperGraph);
             graphSimplifier.initFirstStep();
             while (graphSimplifier.applySimplificationStep()) {
@@ -170,8 +174,25 @@ public class GraphSimplifierTest {
             SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(counter, hyperGraph);
             subgraphEnumerator.enumerate();
             for (int count : counter.getAllCount().values()) {
-                Assertions.assertEquals(count, 1);
+                Assertions.assertTrue(count < 1000);
             }
+            Assertions.assertTrue(graphSimplifier.isTotalOrder());
         }
     }
+
+    @Test
+    void testLimit() {
+        int tableNum = 10;
+        int edgeNum = 20;
+        for (int limit = 1000; limit < 10000; limit += 100) {
+            HyperGraph hyperGraph = new 
HyperGraphBuilder().randomBuildWith(tableNum, edgeNum);
+            GraphSimplifier graphSimplifier = new GraphSimplifier(hyperGraph);
+            graphSimplifier.simplifyGraph(limit);
+            Counter counter = new Counter();
+            SubgraphEnumerator subgraphEnumerator = new 
SubgraphEnumerator(counter, hyperGraph);
+            subgraphEnumerator.enumerate();
+            Assertions.assertTrue(counter.getLimit() >= 0);
+        }
+
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/HyperGraphTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraphTest.java
similarity index 98%
rename from 
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/HyperGraphTest.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraphTest.java
index df7cf69852..113a8db93d 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/HyperGraphTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraphTest.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.util.HyperGraphBuilder;
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/SubgraphEnumeratorTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/SubgraphEnumeratorTest.java
similarity index 95%
rename from 
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/SubgraphEnumeratorTest.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/SubgraphEnumeratorTest.java
index 7f1bd8ec11..1b4e1fb306 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/hypergraph/SubgraphEnumeratorTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/SubgraphEnumeratorTest.java
@@ -15,11 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.rules.joinreorder.hypergraph;
+package org.apache.doris.nereids.jobs.joinorder.hypergraph;
 
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
-import 
org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.SubsetIterator;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.receiver.Counter;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import 
org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.SubsetIterator;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.receiver.Counter;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.util.HyperGraphBuilder;
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupRightTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupRightTest.java
deleted file mode 100644
index e9ee1d1542..0000000000
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderGroupRightTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.rules.joinreorder;
-
-import org.apache.doris.common.Pair;
-import org.apache.doris.nereids.trees.plans.JoinType;
-import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
-import org.apache.doris.nereids.util.LogicalPlanBuilder;
-import org.apache.doris.nereids.util.MemoTestUtils;
-import org.apache.doris.nereids.util.PlanChecker;
-import org.apache.doris.nereids.util.PlanConstructor;
-
-import org.junit.jupiter.api.Test;
-
-class HyperGraphJoinReorderGroupRightTest {
-    private final LogicalOlapScan scan1 = 
PlanConstructor.newLogicalOlapScan(0, "t1", 0);
-    private final LogicalOlapScan scan2 = 
PlanConstructor.newLogicalOlapScan(1, "t2", 0);
-    private final LogicalOlapScan scan3 = 
PlanConstructor.newLogicalOlapScan(2, "t3", 0);
-    private final LogicalOlapScan scan4 = 
PlanConstructor.newLogicalOlapScan(3, "t4", 0);
-    private final LogicalOlapScan scan5 = 
PlanConstructor.newLogicalOlapScan(4, "t5", 0);
-
-    @Test
-    void test() {
-        LogicalPlan plan = new LogicalPlanBuilder(scan1)
-                .hashJoinUsing(scan2, JoinType.INNER_JOIN, Pair.of(0, 1))
-                .hashJoinUsing(scan3, JoinType.INNER_JOIN, Pair.of(0, 1))
-                .hashJoinUsing(scan4, JoinType.INNER_JOIN, Pair.of(0, 1))
-                .hashJoinUsing(scan5, JoinType.INNER_JOIN, Pair.of(0, 1))
-                .build();
-
-        PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
-                .deriveStats()
-                .applyTopDown(new HyperGraphJoinReorderGroupRight())
-                .printlnTree();
-    }
-}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderTest.java
deleted file mode 100644
index d707722014..0000000000
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/joinreorder/HyperGraphJoinReorderTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.rules.joinreorder;
-
-import org.apache.doris.common.Pair;
-import org.apache.doris.nereids.trees.plans.JoinType;
-import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
-import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
-import org.apache.doris.nereids.util.LogicalPlanBuilder;
-import org.apache.doris.nereids.util.MemoTestUtils;
-import org.apache.doris.nereids.util.PlanChecker;
-import org.apache.doris.nereids.util.PlanConstructor;
-
-import org.junit.jupiter.api.Test;
-
-class HyperGraphJoinReorderTest {
-    private final LogicalOlapScan scan1 = 
PlanConstructor.newLogicalOlapScan(0, "t1", 0);
-    private final LogicalOlapScan scan2 = 
PlanConstructor.newLogicalOlapScan(1, "t2", 0);
-    private final LogicalOlapScan scan3 = 
PlanConstructor.newLogicalOlapScan(2, "t3", 0);
-    private final LogicalOlapScan scan4 = 
PlanConstructor.newLogicalOlapScan(3, "t4", 0);
-    private final LogicalOlapScan scan5 = 
PlanConstructor.newLogicalOlapScan(4, "t5", 0);
-
-    @Test
-    void test() {
-        LogicalPlan plan = new LogicalPlanBuilder(scan1)
-                .hashJoinUsing(scan2, JoinType.INNER_JOIN, Pair.of(0, 1))
-                .hashJoinUsing(scan3, JoinType.INNER_JOIN, Pair.of(0, 1))
-                .hashJoinUsing(
-                        new LogicalPlanBuilder(scan4)
-                                .hashJoinUsing(scan5, JoinType.INNER_JOIN, 
Pair.of(0, 1))
-                                .build(),
-                        JoinType.INNER_JOIN, Pair.of(0, 1)
-                )
-                .build();
-
-        PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
-                .deriveStats()
-                .applyTopDown(new HyperGraphJoinReorder())
-                .printlnTree();
-    }
-}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/HyperGraphBuilder.java 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/HyperGraphBuilder.java
index 65750c9140..66db0bd490 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/HyperGraphBuilder.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/HyperGraphBuilder.java
@@ -19,17 +19,13 @@ package org.apache.doris.nereids.util;
 
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.CascadesContext;
-import org.apache.doris.nereids.pattern.GroupExpressionMatching;
-import org.apache.doris.nereids.rules.Rule;
-import org.apache.doris.nereids.rules.joinreorder.HyperGraphJoinReorder;
-import 
org.apache.doris.nereids.rules.joinreorder.HyperGraphJoinReorderGroupLeft;
-import 
org.apache.doris.nereids.rules.joinreorder.HyperGraphJoinReorderGroupRight;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.HyperGraph;
-import org.apache.doris.nereids.rules.joinreorder.hypergraph.bitmap.Bitmap;
-import org.apache.doris.nereids.stats.StatsCalculator;
+import org.apache.doris.nereids.jobs.cascades.DeriveStatsJob;
+import org.apache.doris.nereids.jobs.joinorder.JoinOrderJob;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.HyperGraph;
+import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.Bitmap;
+import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.trees.expressions.EqualTo;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@@ -38,7 +34,6 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.statistics.StatsDeriveResult;
 
 import com.google.common.base.Preconditions;
-import org.junit.jupiter.api.Assertions;
 
 import java.util.ArrayList;
 import java.util.BitSet;
@@ -54,9 +49,7 @@ public class HyperGraphBuilder {
     public HyperGraph build() {
         assert plans.size() == 1 : "there are cross join";
         Plan plan = plans.values().iterator().next();
-        Plan planWithStats = extractJoinCluster(plan);
-        HyperGraph graph = HyperGraph.fromPlan(planWithStats);
-        return graph;
+        return buildHyperGraph(plan);
     }
 
     public HyperGraph randomBuildWith(int tableNum, int edgeNum) {
@@ -168,49 +161,31 @@ public class HyperGraphBuilder {
         return bitSet.equals(bitSet2);
     }
 
-    private Rule selectRuleForPlan(Plan plan) {
-        Assertions.assertTrue(plan instanceof LogicalJoin);
-        LogicalJoin join = (LogicalJoin) plan;
-        if (!(join.left() instanceof LogicalJoin)) {
-            return new HyperGraphJoinReorderGroupLeft().build();
-        } else if (!(join.right() instanceof LogicalJoin)) {
-            return new HyperGraphJoinReorderGroupRight().build();
-        }
-        return new HyperGraphJoinReorder().build();
-    }
-
-    private Plan extractJoinCluster(Plan plan) {
-        Rule rule = selectRuleForPlan(plan);
+    private HyperGraph buildHyperGraph(Plan plan) {
         CascadesContext cascadesContext = 
MemoTestUtils.createCascadesContext(MemoTestUtils.createConnectContext(),
                 plan);
-        GroupExpressionMatching groupExpressionMatching
-                = new GroupExpressionMatching(rule.getPattern(),
-                cascadesContext.getMemo().getRoot().getLogicalExpression());
-        List<Plan> planList = new ArrayList<>();
-        for (Plan matchingPlan : groupExpressionMatching) {
-            planList.add(matchingPlan);
-        }
-        assert planList.size() == 1 : "Now we only support one join cluster";
-        injectRowcount(planList.get(0));
-        return planList.get(0);
+        JoinOrderJob joinOrderJob = new 
JoinOrderJob(cascadesContext.getMemo().getRoot(),
+                cascadesContext.getCurrentJobContext());
+        cascadesContext.pushJob(
+                new 
DeriveStatsJob(cascadesContext.getMemo().getRoot().getLogicalExpression(),
+                        cascadesContext.getCurrentJobContext()));
+        cascadesContext.getJobScheduler().executeJobPool(cascadesContext);
+        injectRowcount(cascadesContext.getMemo().getRoot());
+        HyperGraph hyperGraph = new HyperGraph();
+        joinOrderJob.buildGraph(cascadesContext.getMemo().getRoot(), 
hyperGraph);
+        return hyperGraph;
     }
 
-    private void injectRowcount(Plan plan) {
-        if (plan instanceof GroupPlan) {
-            GroupPlan olapGroupPlan = (GroupPlan) plan;
-            
StatsCalculator.estimate(olapGroupPlan.getGroup().getLogicalExpression());
-            LogicalOlapScan scanPlan = (LogicalOlapScan) 
olapGroupPlan.getGroup().getLogicalExpression().getPlan();
-            StatsDeriveResult stats = olapGroupPlan.getGroup().getStatistics();
-            olapGroupPlan.getGroup()
-                    .setStatistics(stats
-                            
.updateRowCount(rowCounts.get(Integer.parseInt(scanPlan.getTable().getName()))));
+    private void injectRowcount(Group group) {
+        if (!group.isJoinGroup()) {
+            StatsDeriveResult stats = group.getStatistics();
+            LogicalOlapScan scanPlan = (LogicalOlapScan) 
group.getLogicalExpression().getPlan();
+            int rowCount = 
rowCounts.get(Integer.parseInt(scanPlan.getTable().getName()));
+            group.setStatistics(stats.updateRowCount(rowCount));
             return;
         }
-        LogicalJoin join = (LogicalJoin) plan;
-        injectRowcount(join.left());
-        injectRowcount(join.right());
-        // Because the children stats has been changed, so we need to 
recalculate it
-        StatsCalculator.estimate(join.getGroupExpression().get());
+        injectRowcount(group.getLogicalExpression().child(0));
+        injectRowcount(group.getLogicalExpression().child(1));
     }
 
     private void addCondition(int node1, int node2, BitSet key) {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
index d6b92578f6..a86ce9ed6c 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java
@@ -24,6 +24,7 @@ import org.apache.doris.nereids.glue.LogicalPlanAdapter;
 import org.apache.doris.nereids.jobs.JobContext;
 import org.apache.doris.nereids.jobs.batch.NereidsRewriteJobExecutor;
 import org.apache.doris.nereids.jobs.cascades.DeriveStatsJob;
+import org.apache.doris.nereids.jobs.joinorder.JoinOrderJob;
 import org.apache.doris.nereids.memo.Group;
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.memo.Memo;
@@ -71,6 +72,19 @@ public class PlanChecker {
         this.cascadesContext = cascadesContext;
     }
 
+    public static PlanChecker from(ConnectContext connectContext) {
+        return new PlanChecker(connectContext);
+    }
+
+    public static PlanChecker from(ConnectContext connectContext, Plan 
initPlan) {
+        CascadesContext cascadesContext = 
MemoTestUtils.createCascadesContext(connectContext, initPlan);
+        return new PlanChecker(cascadesContext);
+    }
+
+    public static PlanChecker from(CascadesContext cascadesContext) {
+        return new PlanChecker(cascadesContext);
+    }
+
     public PlanChecker checkParse(String sql, Consumer<PlanParseChecker> 
consumer) {
         PlanParseChecker checker = new PlanParseChecker(sql);
         consumer.accept(checker);
@@ -248,7 +262,15 @@ public class PlanChecker {
 
     public PlanChecker deriveStats() {
         cascadesContext.pushJob(
-            new 
DeriveStatsJob(cascadesContext.getMemo().getRoot().getLogicalExpression(), 
cascadesContext.getCurrentJobContext()));
+                new 
DeriveStatsJob(cascadesContext.getMemo().getRoot().getLogicalExpression(),
+                        cascadesContext.getCurrentJobContext()));
+        cascadesContext.getJobScheduler().executeJobPool(cascadesContext);
+        return this;
+    }
+
+    public PlanChecker orderJoin() {
+        cascadesContext.pushJob(
+                new JoinOrderJob(cascadesContext.getMemo().getRoot(), 
cascadesContext.getCurrentJobContext()));
         cascadesContext.getJobScheduler().executeJobPool(cascadesContext);
         return this;
     }
@@ -348,19 +370,6 @@ public class PlanChecker {
         });
     }
 
-    public static PlanChecker from(ConnectContext connectContext) {
-        return new PlanChecker(connectContext);
-    }
-
-    public static PlanChecker from(ConnectContext connectContext, Plan 
initPlan) {
-        CascadesContext cascadesContext = 
MemoTestUtils.createCascadesContext(connectContext, initPlan);
-        return new PlanChecker(cascadesContext);
-    }
-
-    public static PlanChecker from(CascadesContext cascadesContext) {
-        return new PlanChecker(cascadesContext);
-    }
-
     public CascadesContext getCascadesContext() {
         return cascadesContext;
     }


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

Reply via email to