diff --git a/src/context/ast/CypherAstContext.h b/src/context/ast/CypherAstContext.h
new file mode 100644
index 0000000000000000000000000000000000000000..4dc9468a16ea2b28a09520612dfaee98f3d80942
--- /dev/null
+++ b/src/context/ast/CypherAstContext.h
@@ -0,0 +1,188 @@
+/* Copyright (c) 2020 vesoft inc. All rights reserved.
+ *
+ * This source code is licensed under Apache 2.0 License,
+ * attached with Common Clause Condition 1.0, found in the LICENSES directory.
+ */
+
+#ifndef CONTEXT_AST_CYPHERASTCONTEXT_H_
+#define CONTEXT_AST_CYPHERASTCONTEXT_H_
+
+#include "common/base/Base.h"
+#include "common/expression/ContainerExpression.h"
+#include "common/expression/Expression.h"
+#include "common/expression/PathBuildExpression.h"
+#include "context/ast/AstContext.h"
+#include "parser/MatchSentence.h"
+
+namespace nebula {
+namespace graph {
+enum class CypherClauseKind : uint8_t {
+    kMatch,
+    kUnwind,
+    kWith,
+    kWhere,
+    kReturn,
+    kOrderBy,
+    kPagination,
+    kYield,
+};
+
+enum class PatternKind : uint8_t {
+    kNode,
+    kEdge,
+};
+
+using Direction = MatchEdge::Direction;
+struct NodeInfo {
+    bool                                    anonymous{false};
+    std::vector<TagID>                      tids;
+    std::vector<const std::string*>         labels;
+    std::vector<MapExpression*>             labelProps;
+    const std::string                      *alias{nullptr};
+    const MapExpression                    *props{nullptr};
+    Expression                             *filter{nullptr};
+};
+
+struct EdgeInfo {
+    bool                                    anonymous{false};
+    MatchStepRange                         *range{nullptr};
+    std::vector<EdgeType>                   edgeTypes;
+    MatchEdge::Direction                    direction{MatchEdge::Direction::OUT_EDGE};
+    std::vector<const std::string*>         types;
+    const std::string                      *alias{nullptr};
+    const MapExpression                    *props{nullptr};
+    Expression                             *filter{nullptr};
+};
+
+enum class AliasType : int8_t {
+    kNode, kEdge, kPath, kDefault
+};
+
+struct ScanInfo {
+    Expression                             *filter{nullptr};
+    std::vector<int32_t>                    schemaIds;
+    std::vector<const std::string*>         schemaNames;
+    // use for seek by index itself
+    std::vector<IndexID>                    indexIds;
+    // use for seek by edge only
+    MatchEdge::Direction                    direction{MatchEdge::Direction::OUT_EDGE};
+};
+
+struct CypherClauseContextBase : AstContext {
+    explicit CypherClauseContextBase(CypherClauseKind k) : kind(k) {}
+    virtual ~CypherClauseContextBase() = default;
+
+    const CypherClauseKind  kind;
+};
+
+struct WhereClauseContext final : CypherClauseContextBase {
+    WhereClauseContext() : CypherClauseContextBase(CypherClauseKind::kWhere) {}
+
+    Expression* filter;
+    std::unordered_map<std::string, AliasType>*  aliasesUsed{nullptr};
+};
+
+struct OrderByClauseContext final : CypherClauseContextBase {
+    OrderByClauseContext() : CypherClauseContextBase(CypherClauseKind::kOrderBy) {}
+
+    std::vector<std::pair<size_t, OrderFactor::OrderType>>      indexedOrderFactors;
+};
+
+struct PaginationContext final : CypherClauseContextBase {
+    PaginationContext() : CypherClauseContextBase(CypherClauseKind::kPagination) {}
+
+    int64_t     skip{0};
+    int64_t     limit{std::numeric_limits<int64_t>::max()};
+};
+
+struct YieldClauseContext final : CypherClauseContextBase {
+    YieldClauseContext() : CypherClauseContextBase(CypherClauseKind::kYield) {}
+
+    bool                                              distinct{false};
+    const YieldColumns*                               yieldColumns{nullptr};
+    std::unordered_map<std::string, AliasType>*       aliasesUsed{nullptr};
+
+    bool                                              hasAgg_{false};
+    bool                                              needGenProject_{false};
+    YieldColumns*                                     projCols_;
+    std::vector<Expression*>                          groupKeys_;
+    std::vector<Expression*>                          groupItems_;
+    std::vector<std::string>                          aggOutputColumnNames_;
+    std::vector<std::string>                          projOutputColumnNames_;
+};
+
+struct ReturnClauseContext final : CypherClauseContextBase {
+    ReturnClauseContext() : CypherClauseContextBase(CypherClauseKind::kReturn) {}
+
+    std::unique_ptr<OrderByClauseContext>        order;
+    std::unique_ptr<PaginationContext>           pagination;
+    std::unique_ptr<YieldClauseContext>          yield;
+};
+
+struct WithClauseContext final : CypherClauseContextBase {
+    WithClauseContext() : CypherClauseContextBase(CypherClauseKind::kWith) {}
+
+    std::unique_ptr<OrderByClauseContext>       order;
+    std::unique_ptr<PaginationContext>          pagination;
+    std::unique_ptr<WhereClauseContext>         where;
+    std::unique_ptr<YieldClauseContext>         yield;
+    std::unordered_map<std::string, AliasType>  aliasesGenerated;
+};
+
+struct MatchClauseContext final : CypherClauseContextBase {
+    MatchClauseContext() : CypherClauseContextBase(CypherClauseKind::kMatch) {}
+
+    std::vector<NodeInfo>                       nodeInfos;
+    std::vector<EdgeInfo>                       edgeInfos;
+    std::unique_ptr<PathBuildExpression>        pathBuild;
+    std::unique_ptr<WhereClauseContext>         where;
+    std::unordered_map<std::string, AliasType>* aliasesUsed{nullptr};
+    std::unordered_map<std::string, AliasType>  aliasesGenerated;
+};
+
+struct UnwindClauseContext final : CypherClauseContextBase {
+    UnwindClauseContext() : CypherClauseContextBase(CypherClauseKind::kUnwind) {}
+
+    const YieldColumns*                         yieldColumns{nullptr};
+    std::unordered_map<std::string, AliasType>* aliasesUsed{nullptr};
+    std::unordered_map<std::string, AliasType>  aliasesGenerated;
+};
+
+struct MatchAstContext final : AstContext {
+    // Alternative of Match/Unwind/With and ends with Return.
+    std::vector<std::unique_ptr<CypherClauseContextBase>>  clauses;
+};
+
+struct PatternContext {
+    PatternContext(PatternKind k, MatchClauseContext* m) : kind(k), matchClauseCtx(m) {}
+    const PatternKind kind;
+    MatchClauseContext*    matchClauseCtx{nullptr};
+};
+
+struct NodeContext final : PatternContext {
+    NodeContext(MatchClauseContext* m, NodeInfo* i)
+        : PatternContext(PatternKind::kNode, m), info(i) {}
+
+    NodeInfo*            info{nullptr};
+
+    // Output fields
+    ScanInfo                    scanInfo;
+    List                        ids;
+    // initialize start expression in project node
+    std::unique_ptr<Expression> initialExpr;
+};
+
+struct EdgeContext final : PatternContext {
+    EdgeContext(MatchClauseContext* m, EdgeInfo* i)
+        : PatternContext(PatternKind::kEdge, m), info(i) {}
+
+    EdgeInfo* info{nullptr};
+
+    // Output fields
+    ScanInfo                    scanInfo;
+    // initialize start expression in project node
+    std::unique_ptr<Expression> initialExpr;
+};
+}  // namespace graph
+}  // namespace nebula
+#endif  // CONTEXT_AST_CYPHERASTCONTEXT_H_
diff --git a/src/context/ast/QueryAstContext.h b/src/context/ast/QueryAstContext.h
index 07fc9f06d04c6ba9216fa310c7dede819ca548a9..0b801736b77eb19fbe60ea702b98aa9f60efc9d0 100644
--- a/src/context/ast/QueryAstContext.h
+++ b/src/context/ast/QueryAstContext.h
@@ -1,188 +1,59 @@
-/* Copyright (c) 2020 vesoft inc. All rights reserved.
+/* Copyright (c) 2021 vesoft inc. All rights reserved.
  *
  * This source code is licensed under Apache 2.0 License,
  * attached with Common Clause Condition 1.0, found in the LICENSES directory.
  */
 
-#ifndef COONTEXT_AST_QUERYASTCONTEXT_H_
-#define COONTEXT_AST_QUERYASTCONTEXT_H_
+#ifndef CONTEXT_AST_QUERYASTCONTEXT_H_
+#define CONTEXT_AST_QUERYASTCONTEXT_H_
 
 #include "common/base/Base.h"
-#include "common/expression/ContainerExpression.h"
 #include "common/expression/Expression.h"
-#include "common/expression/PathBuildExpression.h"
 #include "context/ast/AstContext.h"
-#include "parser/MatchSentence.h"
 
 namespace nebula {
 namespace graph {
-enum class CypherClauseKind : uint8_t {
-    kMatch,
-    kUnwind,
-    kWith,
-    kWhere,
-    kReturn,
-    kOrderBy,
-    kPagination,
-    kYield,
-};
-
-enum class PatternKind : uint8_t {
-    kNode,
-    kEdge,
-};
-
-using Direction = MatchEdge::Direction;
-struct NodeInfo {
-    bool                                    anonymous{false};
-    std::vector<TagID>                      tids;
-    std::vector<const std::string*>         labels;
-    std::vector<MapExpression*>             labelProps;
-    const std::string                      *alias{nullptr};
-    const MapExpression                    *props{nullptr};
-    Expression                             *filter{nullptr};
-};
-
-struct EdgeInfo {
-    bool                                    anonymous{false};
-    MatchStepRange                         *range{nullptr};
-    std::vector<EdgeType>                   edgeTypes;
-    MatchEdge::Direction                    direction{MatchEdge::Direction::OUT_EDGE};
-    std::vector<const std::string*>         types;
-    const std::string                      *alias{nullptr};
-    const MapExpression                    *props{nullptr};
-    Expression                             *filter{nullptr};
-};
-
-enum class AliasType : int8_t {
-    kNode, kEdge, kPath, kDefault
-};
-
-struct ScanInfo {
-    Expression                             *filter{nullptr};
-    std::vector<int32_t>                    schemaIds;
-    std::vector<const std::string*>         schemaNames;
-    // use for seek by index itself
-    std::vector<IndexID>                    indexIds;
-    // use for seek by edge only
-    MatchEdge::Direction                    direction{MatchEdge::Direction::OUT_EDGE};
-};
-
-struct CypherClauseContextBase : AstContext {
-    explicit CypherClauseContextBase(CypherClauseKind k) : kind(k) {}
-    virtual ~CypherClauseContextBase() = default;
-
-    const CypherClauseKind  kind;
-};
-
-struct WhereClauseContext final : CypherClauseContextBase {
-    WhereClauseContext() : CypherClauseContextBase(CypherClauseKind::kWhere) {}
-
-    Expression* filter;
-    std::unordered_map<std::string, AliasType>*  aliasesUsed{nullptr};
-};
-
-struct OrderByClauseContext final : CypherClauseContextBase {
-    OrderByClauseContext() : CypherClauseContextBase(CypherClauseKind::kOrderBy) {}
-
-    std::vector<std::pair<size_t, OrderFactor::OrderType>>      indexedOrderFactors;
-};
 
-struct PaginationContext final : CypherClauseContextBase {
-    PaginationContext() : CypherClauseContextBase(CypherClauseKind::kPagination) {}
-
-    int64_t     skip{0};
-    int64_t     limit{std::numeric_limits<int64_t>::max()};
-};
-
-struct YieldClauseContext final : CypherClauseContextBase {
-    YieldClauseContext() : CypherClauseContextBase(CypherClauseKind::kYield) {}
-
-    bool                                              distinct{false};
-    const YieldColumns*                               yieldColumns{nullptr};
-    std::unordered_map<std::string, AliasType>*       aliasesUsed{nullptr};
-
-    bool                                              hasAgg_{false};
-    bool                                              needGenProject_{false};
-    YieldColumns*                                     projCols_;
-    std::vector<Expression*>                          groupKeys_;
-    std::vector<Expression*>                          groupItems_;
-    std::vector<std::string>                          aggOutputColumnNames_;
-    std::vector<std::string>                          projOutputColumnNames_;
-};
-
-struct ReturnClauseContext final : CypherClauseContextBase {
-    ReturnClauseContext() : CypherClauseContextBase(CypherClauseKind::kReturn) {}
-
-    std::unique_ptr<OrderByClauseContext>        order;
-    std::unique_ptr<PaginationContext>           pagination;
-    std::unique_ptr<YieldClauseContext>          yield;
-};
-
-struct WithClauseContext final : CypherClauseContextBase {
-    WithClauseContext() : CypherClauseContextBase(CypherClauseKind::kWith) {}
-
-    std::unique_ptr<OrderByClauseContext>       order;
-    std::unique_ptr<PaginationContext>          pagination;
-    std::unique_ptr<WhereClauseContext>         where;
-    std::unique_ptr<YieldClauseContext>         yield;
-    std::unordered_map<std::string, AliasType>  aliasesGenerated;
-};
-
-struct MatchClauseContext final : CypherClauseContextBase {
-    MatchClauseContext() : CypherClauseContextBase(CypherClauseKind::kMatch) {}
-
-    std::vector<NodeInfo>                       nodeInfos;
-    std::vector<EdgeInfo>                       edgeInfos;
-    std::unique_ptr<PathBuildExpression>        pathBuild;
-    std::unique_ptr<WhereClauseContext>         where;
-    std::unordered_map<std::string, AliasType>* aliasesUsed{nullptr};
-    std::unordered_map<std::string, AliasType>  aliasesGenerated;
-};
-
-struct UnwindClauseContext final : CypherClauseContextBase {
-    UnwindClauseContext() : CypherClauseContextBase(CypherClauseKind::kUnwind) {}
-
-    const YieldColumns*                         yieldColumns{nullptr};
-    std::unordered_map<std::string, AliasType>* aliasesUsed{nullptr};
-    std::unordered_map<std::string, AliasType>  aliasesGenerated;
+enum FromType {
+    kInstant,
+    kVariable,
+    kPipe;
 };
 
-struct MatchAstContext final : AstContext {
-    // Alternative of Match/Unwind/With and ends with Return.
-    std::vector<std::unique_ptr<CypherClauseContextBase>>  clauses;
+struct Starts {
+    FromType fromType{kInstant};
+    Expression* src{nullptr};
+    Expression* originalSrc{nullptr};
+    std::string userDefinedVarName;
+    std::string firstBeginningSrcVidColName;
+    std::vector<Value> vids;
 };
 
-struct PatternContext {
-    PatternContext(PatternKind k, MatchClauseContext* m) : kind(k), matchClauseCtx(m) {}
-    const PatternKind kind;
-    MatchClauseContext*    matchClauseCtx{nullptr};
+struct Over {
+    bool isOverAll{false};
+    std::vector<EdgeType> edgeTypes;
+    storage::cpp2::EdgeDirection direction;
+    std::vector<std::string> allEdges;
 };
 
-struct NodeContext final : PatternContext {
-    NodeContext(MatchClauseContext* m, NodeInfo* i)
-        : PatternContext(PatternKind::kNode, m), info(i) {}
+// path context
+struct PathContext {
+    Starts from;
+    Starts to;
+    Steps steps;
+    Over over;
 
-    NodeInfo*            info{nullptr};
+    bool isShortest_{false};
+    bool isWeight_{false};
+    bool noLoop_{false};
 
-    // Output fields
-    ScanInfo                    scanInfo;
-    List                        ids;
-    // initialize start expression in project node
-    std::unique_ptr<Expression> initialExpr;
+    // runtime
+    PlanNode* loopDepTail{nullptr};
+    PlanNode* toProjectStartVid{nullptr};
+    PlanNode* fromDedupStartVid{nullptr};
+    PlanNode* toDedupStartVid{nullptr};
 };
 
-struct EdgeContext final : PatternContext {
-    EdgeContext(MatchClauseContext* m, EdgeInfo* i)
-        : PatternContext(PatternKind::kEdge, m), info(i) {}
-
-    EdgeInfo* info{nullptr};
-
-    // Output fields
-    ScanInfo                    scanInfo;
-    // initialize start expression in project node
-    std::unique_ptr<Expression> initialExpr;
-};
 }  // namespace graph
 }  // namespace nebula
-#endif  // COONTEXT_AST_QUERYASTCONTEXT_H_
+#endif  // CONTEXT_AST_QUERYASTCONTEXT_H_
diff --git a/src/planner/match/CypherClausePlanner.h b/src/planner/match/CypherClausePlanner.h
index c6b44c19c8ad479cd8ea2d76c3b84d6854f1c3b0..8c3353b89ff228c11f1c17cbfdf28718a5a37e1f 100644
--- a/src/planner/match/CypherClausePlanner.h
+++ b/src/planner/match/CypherClausePlanner.h
@@ -7,7 +7,7 @@
 #ifndef PLANNER_MATCH_CYPHERCLAUSEPLANNER_H_
 #define PLANNER_MATCH_CYPHERCLAUSEPLANNER_H_
 
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/Planner.h"
 
 namespace nebula {
diff --git a/src/planner/match/Expand.h b/src/planner/match/Expand.h
index a03a9d0e754f51a6e7119fa23d152c86ac912ef7..5ae98aa03543dbf9b09b8316bedcc38ce8a1ea6e 100644
--- a/src/planner/match/Expand.h
+++ b/src/planner/match/Expand.h
@@ -8,7 +8,7 @@
 #define PLANNER_MATCH_EXPAND_H_
 
 #include "common/base/Base.h"
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/PlanNode.h"
 #include "planner/Planner.h"
 
diff --git a/src/planner/match/MatchClausePlanner.cpp b/src/planner/match/MatchClausePlanner.cpp
index 184499ac0ac243411b57837c042dcb5a05f2a1ae..7c8e81058f1c9a595f98a481e943c1a2d7ebc46a 100644
--- a/src/planner/match/MatchClausePlanner.cpp
+++ b/src/planner/match/MatchClausePlanner.cpp
@@ -6,7 +6,7 @@
 
 #include "planner/match/MatchClausePlanner.h"
 
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/Query.h"
 #include "planner/match/Expand.h"
 #include "planner/match/MatchSolver.h"
diff --git a/src/planner/match/MatchPlanner.cpp b/src/planner/match/MatchPlanner.cpp
index 1538fbeb8efa7ddd58165087ed08d42d8f8462a8..bd5fc06002c9f289bca66984b217994fd3bf4824 100644
--- a/src/planner/match/MatchPlanner.cpp
+++ b/src/planner/match/MatchPlanner.cpp
@@ -6,7 +6,7 @@
 
 #include "planner/match/MatchPlanner.h"
 
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/match/MatchClausePlanner.h"
 #include "planner/match/ReturnClausePlanner.h"
 #include "planner/match/SegmentsConnector.h"
diff --git a/src/planner/match/MatchPlanner.h b/src/planner/match/MatchPlanner.h
index c2d88b94fe6f30d856fc1bbcf10fe73e5299660c..0d97659de7e709e6352573dfb0d5fb94210664c9 100644
--- a/src/planner/match/MatchPlanner.h
+++ b/src/planner/match/MatchPlanner.h
@@ -7,7 +7,7 @@
 #ifndef PLANNER_MATCHPLANNER_H_
 #define PLANNER_MATCHPLANNER_H_
 
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/Planner.h"
 
 namespace nebula {
diff --git a/src/planner/match/MatchSolver.cpp b/src/planner/match/MatchSolver.cpp
index ff0722148106dc5b40eeff93d28aaf4dc044743f..7dc68df05eefed17a438de48ab3b6b4ba51d92d8 100644
--- a/src/planner/match/MatchSolver.cpp
+++ b/src/planner/match/MatchSolver.cpp
@@ -8,7 +8,7 @@
 
 #include "common/expression/UnaryExpression.h"
 #include "context/ast/AstContext.h"
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/Planner.h"
 #include "planner/Query.h"
 #include "util/ExpressionUtils.h"
diff --git a/src/planner/match/MatchSolver.h b/src/planner/match/MatchSolver.h
index ab8bab2c4f66c9b93f869cfa0f41c1cb85089bb7..b68ec145c6252cb2fc80bfa8649609a10b0869c0 100644
--- a/src/planner/match/MatchSolver.h
+++ b/src/planner/match/MatchSolver.h
@@ -11,7 +11,7 @@
 #include "common/expression/LabelAttributeExpression.h"
 #include "common/expression/LabelExpression.h"
 #include "context/QueryContext.h"
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/Planner.h"
 
 namespace nebula {
diff --git a/src/planner/match/SegmentsConnector.h b/src/planner/match/SegmentsConnector.h
index f664e44090214fdde45f88c493b0d947c34f3e32..b22bbb0b23cf06674331f1d68bb37794392fef85 100644
--- a/src/planner/match/SegmentsConnector.h
+++ b/src/planner/match/SegmentsConnector.h
@@ -8,7 +8,7 @@
 #define PLANNER_MATCH_SEGMENTSCONNECTOR_H_
 
 #include "context/QueryContext.h"
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/PlanNode.h"
 #include "planner/Planner.h"
 #include "planner/match/InnerJoinStrategy.h"
diff --git a/src/planner/match/StartVidFinder.h b/src/planner/match/StartVidFinder.h
index 6fb87033fa92d95c5873d2ccbad4bc6f496ea07b..a655a1671d022bdbe326cbc3a095da3d6150c89e 100644
--- a/src/planner/match/StartVidFinder.h
+++ b/src/planner/match/StartVidFinder.h
@@ -7,7 +7,7 @@
 #ifndef PLANNER_MATCH_STARTVIDFINDER_H_
 #define PLANNER_MATCH_STARTVIDFINDER_H_
 
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/Planner.h"
 
 namespace nebula {
diff --git a/src/planner/match/VertexIdSeek.h b/src/planner/match/VertexIdSeek.h
index 95709f7dcc03797b82ab4707bf3aea8d7d65be4e..d51f85da36e78923d6bcc8e84ef6dff28deb3b6d 100644
--- a/src/planner/match/VertexIdSeek.h
+++ b/src/planner/match/VertexIdSeek.h
@@ -7,7 +7,7 @@
 #ifndef PLANNER_MATCH_VERTEXIDSEEK_H_
 #define PLANNER_MATCH_VERTEXIDSEEK_H_
 
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 #include "planner/match/StartVidFinder.h"
 
 namespace nebula {
diff --git a/src/validator/MatchValidator.h b/src/validator/MatchValidator.h
index 2fb6cd4345f676156f80e43284cfa84bea5edde1..c5e4be614793cb8a315f592e045f10942b78d8be 100644
--- a/src/validator/MatchValidator.h
+++ b/src/validator/MatchValidator.h
@@ -11,7 +11,7 @@
 #include "validator/TraversalValidator.h"
 #include "util/AnonVarGenerator.h"
 #include "planner/Query.h"
-#include "context/ast/QueryAstContext.h"
+#include "context/ast/CypherAstContext.h"
 
 namespace nebula {