diff --git a/src/context/Iterator.cpp b/src/context/Iterator.cpp
index a9ed83304c68df6eba3818f04e95d4b4ba3f3552..1cde95c4c4535948da95cf31d12dafe3fbb8980f 100644
--- a/src/context/Iterator.cpp
+++ b/src/context/Iterator.cpp
@@ -686,28 +686,20 @@ std::ostream& operator<<(std::ostream& os, LogicalRow::Kind kind) {
 }
 
 std::ostream& operator<<(std::ostream& os, const LogicalRow& row) {
-    switch (row.kind()) {
-        case nebula::graph::LogicalRow::Kind::kSequential:
-        case nebula::graph::LogicalRow::Kind::kJoin: {
-            std::stringstream ss;
-            size_t cnt = 0;
-            for (auto* seg : row.segments()) {
-                if (seg == nullptr) {
-                    ss << "nullptr";
-                } else {
-                    ss << *seg;
-                }
-                if (cnt < row.size() - 1) {
-                    ss << ",";
-                }
-                ++cnt;
-            }
-            os << ss.str();
-            break;
+    std::stringstream ss;
+    size_t cnt = 0;
+    for (auto* seg : row.segments()) {
+        if (seg == nullptr) {
+            ss << "nullptr";
+        } else {
+            ss << *seg;
         }
-        default:
-            LOG(FATAL) << "Not support streaming for " << row.kind();
+        if (cnt < row.size() - 1) {
+            ss << ",";
+        }
+        ++cnt;
     }
+    os << ss.str();
     return os;
 }
 }  // namespace graph
diff --git a/src/context/ast/QueryAstContext.h b/src/context/ast/QueryAstContext.h
index e2f12f0b05b215cd3237507df44ca76234a899e4..c7ed9351f56e6c4f3383ecb280565f52bd6880d8 100644
--- a/src/context/ast/QueryAstContext.h
+++ b/src/context/ast/QueryAstContext.h
@@ -150,11 +150,10 @@ struct NodeContext final : PatternContext {
     NodeInfo*            info{nullptr};
 
     // Output fields
-    ScanInfo             scanInfo;
-    const Expression*    ids{nullptr};
+    ScanInfo                    scanInfo;
+    const Expression*           ids{nullptr};
     // initialize start expression in project node
-    // initialExpr will be used by YieldColumn, so no need to handle the lifecycle by object pool.
-    Expression*          initialExpr{nullptr};
+    std::unique_ptr<Expression> initialExpr;
 };
 
 struct EdgeContext final : PatternContext {
diff --git a/src/executor/query/ProjectExecutor.cpp b/src/executor/query/ProjectExecutor.cpp
index 6559ea9a328cd7b7e4ae251573ba9e6f5bef7fb9..80604cbdbff4e186afe4679054faf410c61606e0 100644
--- a/src/executor/query/ProjectExecutor.cpp
+++ b/src/executor/query/ProjectExecutor.cpp
@@ -26,6 +26,7 @@ folly::Future<Status> ProjectExecutor::execute() {
     DataSet ds;
     ds.colNames = project->colNames();
     for (; iter->valid(); iter->next()) {
+        VLOG(1) << "row: " << *iter->row();
         Row row;
         for (auto& col : columns) {
             Value val = col->expr()->eval(ctx(iter.get()));
diff --git a/src/planner/match/AddDependencyStrategy.h b/src/planner/match/AddDependencyStrategy.h
index 7e6aa336edcb392e8ae622f06e9326d4311427f6..52494559349e63bbf20d84900bbb1e6384b5672d 100644
--- a/src/planner/match/AddDependencyStrategy.h
+++ b/src/planner/match/AddDependencyStrategy.h
@@ -8,7 +8,7 @@
 #define PLANNER_MATCH_ADDDEPENDENCYSTRATEGY_H_
 
 #include "planner/PlanNode.h"
-#include "planner/match/SegmentsConnector.h"
+#include "planner/match/SegmentsConnectStrategy.h"
 
 namespace nebula {
 namespace graph {
diff --git a/src/planner/match/AddInputStrategy.h b/src/planner/match/AddInputStrategy.h
index 5d0a298487f34f65fcf3cceac509444d05bdc5a2..54ffcbedc14087f9264f19d7b2fa75aa9ad87626 100644
--- a/src/planner/match/AddInputStrategy.h
+++ b/src/planner/match/AddInputStrategy.h
@@ -8,7 +8,7 @@
 #define PLANNER_MATCH_ADDINPUTSTRATEGY_H_
 
 #include "planner/PlanNode.h"
-#include "planner/match/SegmentsConnector.h"
+#include "planner/match/SegmentsConnectStrategy.h"
 
 namespace nebula {
 namespace graph {
diff --git a/src/planner/match/Expand.cpp b/src/planner/match/Expand.cpp
index 7d5c4c78f20e81bfb403c9739cb7ea00afc444c7..1d6bab1461ac47f9bd63abbe2fd02aa55c4657ca 100644
--- a/src/planner/match/Expand.cpp
+++ b/src/planner/match/Expand.cpp
@@ -26,26 +26,35 @@ static std::unique_ptr<std::vector<VertexProp>> genVertexProps() {
 }
 
 std::unique_ptr<std::vector<storage::cpp2::EdgeProp>> Expand::genEdgeProps(const EdgeInfo &edge) {
-    if (edge.edgeTypes.empty()) {
-        return std::make_unique<std::vector<storage::cpp2::EdgeProp>>(
-            buildAllEdgeProp().value());
-    }
-
     auto edgeProps = std::make_unique<std::vector<EdgeProp>>();
     for (auto edgeType : edge.edgeTypes) {
         auto edgeSchema = matchCtx_->qctx->schemaMng()->getEdgeSchema(
             matchCtx_->space.id, edgeType);
-        if (edge.direction == Direction::IN_EDGE) {
-            edgeType = -edgeType;
-        } else if (edge.direction == Direction::BOTH) {
-            EdgeProp edgeProp;
-            edgeProp.set_type(-edgeType);
-            std::vector<std::string> props{kSrc, kType, kRank, kDst};
-            for (std::size_t i = 0; i < edgeSchema->getNumFields(); ++i) {
-                props.emplace_back(edgeSchema->getFieldName(i));
+
+        switch (edge.direction) {
+            case Direction::OUT_EDGE: {
+                if (reversely_) {
+                    edgeType = -edgeType;
+                }
+                break;
+            }
+            case Direction::IN_EDGE: {
+                if (!reversely_) {
+                    edgeType = -edgeType;
+                }
+                break;
+            }
+            case Direction::BOTH: {
+                EdgeProp edgeProp;
+                edgeProp.set_type(-edgeType);
+                std::vector<std::string> props{kSrc, kType, kRank, kDst};
+                for (std::size_t i = 0; i < edgeSchema->getNumFields(); ++i) {
+                    props.emplace_back(edgeSchema->getFieldName(i));
+                }
+                edgeProp.set_props(std::move(props));
+                edgeProps->emplace_back(std::move(edgeProp));
+                break;
             }
-            edgeProp.set_props(std::move(props));
-            edgeProps->emplace_back(std::move(edgeProp));
         }
         EdgeProp edgeProp;
         edgeProp.set_type(edgeType);
@@ -75,25 +84,24 @@ static Expression* buildPathExpr() {
 
 Status Expand::doExpand(const NodeInfo& node,
                         const EdgeInfo& edge,
-                        const PlanNode* input,
-                        SubPlan*plan) {
-    NG_RETURN_IF_ERROR(expandSteps(node, edge, input, plan));
+                        SubPlan* plan) {
+    NG_RETURN_IF_ERROR(expandSteps(node, edge, plan));
     NG_RETURN_IF_ERROR(filterDatasetByPathLength(edge, plan->root, plan));
     return Status::OK();
 }
 
 Status Expand::expandSteps(const NodeInfo& node,
                            const EdgeInfo& edge,
-                           const PlanNode* input,
                            SubPlan* plan) {
     SubPlan subplan;
-    NG_RETURN_IF_ERROR(expandStep(edge, input, node.filter, true, &subplan));
+    NG_RETURN_IF_ERROR(expandStep(edge, dependency_, inputVar_, node.filter, true, &subplan));
     // plan->tail = subplan.tail;
     PlanNode* passThrough = subplan.root;
     auto maxHop = edge.range ? edge.range->max() : 1;
     for (int64_t i = 1; i < maxHop; ++i) {
         SubPlan curr;
-        NG_RETURN_IF_ERROR(expandStep(edge, passThrough, nullptr, false, &curr));
+        NG_RETURN_IF_ERROR(
+            expandStep(edge, passThrough, passThrough->outputVar(), nullptr, false, &curr));
         auto rNode = subplan.root;
         DCHECK(rNode->kind() == PNKind::kUnion || rNode->kind() == PNKind::kPassThrough);
         NG_RETURN_IF_ERROR(collectData(passThrough, curr.root, rNode, &passThrough, &subplan));
@@ -104,17 +112,17 @@ Status Expand::expandSteps(const NodeInfo& node,
 
 // build subplan: Project->Dedup->GetNeighbors->[Filter]->Project
 Status Expand::expandStep(const EdgeInfo& edge,
-                          const PlanNode* input,
+                          PlanNode* dep,
+                          const std::string& inputVar,
                           const Expression* nodeFilter,
                           bool needPassThrough,
                           SubPlan* plan) {
-    DCHECK(input != nullptr);
     auto qctx = matchCtx_->qctx;
 
     // Extract dst vid from input project node which output dataset format is: [v1,e1,...,vn,en]
     SubPlan curr;
-    curr.root = const_cast<PlanNode*>(input);
-    MatchSolver::extractAndDedupVidColumn(qctx, initialExpr_, &curr);
+    curr.root = dep;
+    MatchSolver::extractAndDedupVidColumn(qctx, initialExpr_.release(), dep, inputVar, curr);
 
     auto gn = GetNeighbors::make(qctx, curr.root, matchCtx_->space.id);
     auto srcExpr = ExpressionUtils::inputPropExpr(kVid);
@@ -152,7 +160,7 @@ Status Expand::expandStep(const EdgeInfo& edge,
             auto la = static_cast<const LabelAttributeExpression*>(expr);
             return new AttributeExpression(new EdgeExpression(), la->right()->clone().release());
         });
-        auto filter = edge.filter->clone().release();
+        auto filter = saveObject(edge.filter->clone().release());
         filter->accept(&visitor);
         auto filterNode = Filter::make(qctx, root, filter);
         filterNode->setColNames(root->colNames());
@@ -230,30 +238,5 @@ Status Expand::filterDatasetByPathLength(const EdgeInfo& edge,
     // plan->tail = curr.tail;
     return Status::OK();
 }
-
-StatusOr<std::vector<storage::cpp2::EdgeProp>> Expand::buildAllEdgeProp() {
-    // list all edge properties
-    std::map<TagID, std::shared_ptr<const meta::SchemaProviderIf>> edgesSchema;
-    const auto allEdgesResult = matchCtx_->qctx->schemaMng()->getAllVerEdgeSchema(
-        matchCtx_->space.id);
-    NG_RETURN_IF_ERROR(allEdgesResult);
-    const auto allEdges = std::move(allEdgesResult).value();
-    for (const auto &edge : allEdges) {
-        edgesSchema.emplace(edge.first, edge.second.back());
-    }
-    std::vector<storage::cpp2::EdgeProp> eProps;
-    for (const auto &edgeSchema : edgesSchema) {
-        storage::cpp2::EdgeProp eProp;
-        eProp.set_type(edgeSchema.first);
-        std::vector<std::string> props{kSrc, kType, kRank, kDst};
-        for (std::size_t i = 0; i < edgeSchema.second->getNumFields(); ++i) {
-            props.emplace_back(edgeSchema.second->getFieldName(i));
-        }
-        eProp.set_props(std::move(props));
-        eProps.emplace_back(std::move(eProp));
-    }
-    return eProps;
-}
-
 }  // namespace graph
 }  // namespace nebula
diff --git a/src/planner/match/Expand.h b/src/planner/match/Expand.h
index 09e255c591cff29f87b7da8d4d9fede5d32ba41d..ba4e9cfc23bf28cf68f0d337284476101566fb45 100644
--- a/src/planner/match/Expand.h
+++ b/src/planner/match/Expand.h
@@ -19,21 +19,36 @@ namespace graph {
  */
 class Expand final {
 public:
-    Expand(MatchClauseContext* matchCtx, Expression** initialExpr)
-        : matchCtx_(matchCtx), initialExpr_(initialExpr) {}
+    Expand(MatchClauseContext* matchCtx, std::unique_ptr<Expression> initialExpr)
+        : matchCtx_(matchCtx), initialExpr_(std::move(initialExpr)) {}
+
+    Expand* reversely() {
+        reversely_ = true;
+        return this;
+    }
+
+    Expand* depends(PlanNode* dep) {
+        dependency_ = dep;
+        return this;
+    }
+
+    Expand* inputVar(const std::string& inputVar) {
+        inputVar_ = inputVar;
+        return this;
+    }
 
     Status doExpand(const NodeInfo& node,
                     const EdgeInfo& edge,
-                    const PlanNode* input,
                     SubPlan* plan);
 
+private:
     Status expandSteps(const NodeInfo& node,
                        const EdgeInfo& edge,
-                       const PlanNode* input,
                        SubPlan* plan);
 
     Status expandStep(const EdgeInfo& edge,
-                      const PlanNode* input,
+                      PlanNode* dep,
+                      const std::string& inputVar,
                       const Expression* nodeFilter,
                       bool needPassThrough,
                       SubPlan* plan);
@@ -46,22 +61,18 @@ public:
 
     Status filterDatasetByPathLength(const EdgeInfo& edge, PlanNode* input, SubPlan* plan);
 
-    Expression* initialExprOrEdgeDstExpr(const PlanNode* node);
-
-    PlanNode* joinDataSet(const PlanNode* right, const PlanNode* left);
-
     template <typename T>
     T* saveObject(T* obj) const {
         return matchCtx_->qctx->objPool()->add(obj);
     }
 
-private:
     std::unique_ptr<std::vector<storage::cpp2::EdgeProp>> genEdgeProps(const EdgeInfo &edge);
 
-    StatusOr<std::vector<storage::cpp2::EdgeProp>> buildAllEdgeProp();
-
-    MatchClauseContext* matchCtx_;
-    Expression**        initialExpr_;
+    MatchClauseContext*                 matchCtx_;
+    std::unique_ptr<Expression>         initialExpr_;
+    bool                                reversely_{false};
+    PlanNode*                           dependency_{nullptr};
+    std::string                         inputVar_;
 };
 }   // namespace graph
 }   // namespace nebula
diff --git a/src/planner/match/InnerJoinStrategy.cpp b/src/planner/match/InnerJoinStrategy.cpp
index ca26ff502db194f918e2e8d4ecff76420e99cdb0..9815301bc94208df94b6fd855800f7f608db0e5c 100644
--- a/src/planner/match/InnerJoinStrategy.cpp
+++ b/src/planner/match/InnerJoinStrategy.cpp
@@ -18,10 +18,24 @@ PlanNode* InnerJoinStrategy::connect(const PlanNode* left, const PlanNode* right
 }
 
 PlanNode* InnerJoinStrategy::joinDataSet(const PlanNode* left, const PlanNode* right) {
-    auto& leftKey = left->colNamesRef().back();
-    auto& rightKey = right->colNamesRef().front();
-    auto buildExpr = MatchSolver::getLastEdgeDstExprInLastPath(leftKey);
-    auto probeExpr = MatchSolver::getFirstVertexVidInFistPath(rightKey);
+    Expression* buildExpr = nullptr;
+    if (leftPos_ == JoinPos::kStart) {
+        auto& leftKey = left->colNamesRef().front();
+        buildExpr = MatchSolver::getStartVidInPath(leftKey);
+    } else {
+        auto& leftKey = left->colNamesRef().back();
+        buildExpr = MatchSolver::getEndVidInPath(leftKey);
+    }
+
+    Expression* probeExpr = nullptr;
+    if (rightPos_ == JoinPos::kStart) {
+        auto& rightKey = right->colNamesRef().front();
+        probeExpr = MatchSolver::getStartVidInPath(rightKey);
+    } else {
+        auto& rightKey = right->colNamesRef().back();
+        probeExpr = MatchSolver::getEndVidInPath(rightKey);
+    }
+
     qctx_->objPool()->add(buildExpr);
     qctx_->objPool()->add(probeExpr);
     auto join = DataJoin::make(qctx_,
diff --git a/src/planner/match/InnerJoinStrategy.h b/src/planner/match/InnerJoinStrategy.h
index 49f4034dd2596ebc67ed9384c4c4109c32e82d20..c11ece57181b6dda1f343531d6025b92230ea364 100644
--- a/src/planner/match/InnerJoinStrategy.h
+++ b/src/planner/match/InnerJoinStrategy.h
@@ -7,8 +7,8 @@
 #ifndef PLANNER_PLANNERS_MATCH_INNERJOINSTRATEGY_H_
 #define PLANNER_PLANNERS_MATCH_INNERJOINSTRATEGY_H_
 
-#include "planner/match/SegmentsConnector.h"
 #include "planner/PlanNode.h"
+#include "planner/match/SegmentsConnectStrategy.h"
 
 namespace nebula {
 namespace graph {
@@ -17,12 +17,30 @@ namespace graph {
  */
 class InnerJoinStrategy final : public SegmentsConnectStrategy {
 public:
+    enum class JoinPos : int8_t {
+        kStart,
+        kEnd
+    };
+
     explicit InnerJoinStrategy(QueryContext* qctx) : SegmentsConnectStrategy(qctx) {}
 
+    InnerJoinStrategy* leftPos(JoinPos pos) {
+        leftPos_ = pos;
+        return this;
+    }
+
+    InnerJoinStrategy* rightPos(JoinPos pos) {
+        rightPos_ = pos;
+        return this;
+    }
+
     PlanNode* connect(const PlanNode* left, const PlanNode* right) override;
 
 private:
     PlanNode* joinDataSet(const PlanNode* left, const PlanNode* right);
+
+    JoinPos     leftPos_{JoinPos::kEnd};
+    JoinPos     rightPos_{JoinPos::kStart};
 };
 }  // namespace graph
 }  // namespace nebula
diff --git a/src/planner/match/MatchClausePlanner.cpp b/src/planner/match/MatchClausePlanner.cpp
index fa22755603469b7101ad34f847c5f79fc07da266..08b5f3ba027c55dde22826dc3495eccaebfae854 100644
--- a/src/planner/match/MatchClausePlanner.cpp
+++ b/src/planner/match/MatchClausePlanner.cpp
@@ -18,6 +18,7 @@
 
 namespace nebula {
 namespace graph {
+
 StatusOr<SubPlan> MatchClausePlanner::transform(CypherClauseContextBase* clauseCtx) {
     if (clauseCtx->kind != CypherClauseKind::kMatch) {
         return Status::Error("Not a valid context for MatchClausePlanner.");
@@ -27,34 +28,39 @@ StatusOr<SubPlan> MatchClausePlanner::transform(CypherClauseContextBase* clauseC
     auto& nodeInfos = matchClauseCtx->nodeInfos;
     auto& edgeInfos = matchClauseCtx->edgeInfos;
     SubPlan matchClausePlan;
-    int64_t startIndex = -1;
+    size_t startIndex = 0;
+    bool startFromEdge = false;
 
-    NG_RETURN_IF_ERROR(findStarts(matchClauseCtx, startIndex, matchClausePlan));
-    NG_RETURN_IF_ERROR(expand(nodeInfos, edgeInfos, matchClauseCtx, startIndex, matchClausePlan));
-    NG_RETURN_IF_ERROR(projectColumnsBySymbols(matchClauseCtx, &matchClausePlan));
+    NG_RETURN_IF_ERROR(findStarts(matchClauseCtx, startFromEdge, startIndex, matchClausePlan));
+    NG_RETURN_IF_ERROR(
+        expand(nodeInfos, edgeInfos, matchClauseCtx, startFromEdge, startIndex, matchClausePlan));
+    NG_RETURN_IF_ERROR(projectColumnsBySymbols(matchClauseCtx, startIndex, matchClausePlan));
     NG_RETURN_IF_ERROR(appendFilterPlan(matchClauseCtx, matchClausePlan));
     return matchClausePlan;
 }
 
 Status MatchClausePlanner::findStarts(MatchClauseContext* matchClauseCtx,
-                                      int64_t& startIndex,
+                                      bool& startFromEdge,
+                                      size_t& startIndex,
                                       SubPlan& matchClausePlan) {
     auto& nodeInfos = matchClauseCtx->nodeInfos;
     auto& edgeInfos = matchClauseCtx->edgeInfos;
     auto& startVidFinders = StartVidFinder::finders();
+    bool foundStart = false;
     // Find the start plan node
-    for (size_t i = 0; i < nodeInfos.size(); ++i) {
-        for (auto& finder : startVidFinders) {
+    for (auto& finder : startVidFinders) {
+        for (size_t i = 0; i < nodeInfos.size() && !foundStart; ++i) {
             auto nodeCtx = NodeContext(matchClauseCtx, &nodeInfos[i]);
-            auto finderObj = finder();
-            if (finderObj->match(&nodeCtx)) {
-                auto plan = finderObj->transform(&nodeCtx);
+            auto nodeFinder = finder();
+            if (nodeFinder->match(&nodeCtx)) {
+                auto plan = nodeFinder->transform(&nodeCtx);
                 if (!plan.ok()) {
                     return plan.status();
                 }
                 matchClausePlan = std::move(plan).value();
                 startIndex = i;
-                initialExpr_ = nodeCtx.initialExpr;
+                foundStart = true;
+                initialExpr_ = nodeCtx.initialExpr->clone();
                 VLOG(1) << "Find starts: " << startIndex
                     << " node: " << matchClausePlan.root->outputVar()
                     << " colNames: " << folly::join(",", matchClausePlan.root->colNames());
@@ -63,22 +69,25 @@ Status MatchClausePlanner::findStarts(MatchClauseContext* matchClauseCtx,
 
             if (i != nodeInfos.size() - 1) {
                 auto edgeCtx = EdgeContext(matchClauseCtx, &edgeInfos[i]);
-                if (finderObj->match(&edgeCtx)) {
-                    auto plan = finderObj->transform(&edgeCtx);
+                auto edgeFinder = finder();
+                if (edgeFinder->match(&edgeCtx)) {
+                    auto plan = edgeFinder->transform(&edgeCtx);
                     if (!plan.ok()) {
                         return plan.status();
                     }
                     matchClausePlan = std::move(plan).value();
+                    startFromEdge = true;
                     startIndex = i;
+                    foundStart = true;
                     break;
                 }
             }
         }
-        if (startIndex != -1) {
+        if (foundStart) {
             break;
         }
     }
-    if (startIndex < 0) {
+    if (!foundStart) {
         return Status::Error("Can't solve the start vids from the sentence: %s",
                              matchClauseCtx->sentence->toString().c_str());
     }
@@ -89,23 +98,121 @@ Status MatchClausePlanner::findStarts(MatchClauseContext* matchClauseCtx,
 Status MatchClausePlanner::expand(const std::vector<NodeInfo>& nodeInfos,
                                   const std::vector<EdgeInfo>& edgeInfos,
                                   MatchClauseContext* matchClauseCtx,
-                                  int64_t startIndex,
+                                  bool startFromEdge,
+                                  size_t startIndex,
                                   SubPlan& subplan) {
-    // Do expand from startIndex and connect the the subplans.
-    // TODO: Only support start from the head node now.
-    if (startIndex != 0) {
-        return Status::Error("Only support start from the head node parttern.");
+    if (startFromEdge) {
+        return expandFromEdge(nodeInfos, edgeInfos, matchClauseCtx, startIndex, subplan);
+    } else {
+        return expandFromNode(nodeInfos, edgeInfos, matchClauseCtx, startIndex, subplan);
     }
+}
+
+Status MatchClausePlanner::expandFromNode(const std::vector<NodeInfo>& nodeInfos,
+                                          const std::vector<EdgeInfo>& edgeInfos,
+                                          MatchClauseContext* matchClauseCtx,
+                                          size_t startIndex,
+                                          SubPlan& subplan) {
+    SubPlan rightExpandPlan = subplan;
+    NG_RETURN_IF_ERROR(
+        rightExpandFromNode(nodeInfos, edgeInfos, matchClauseCtx, startIndex, rightExpandPlan));
 
-    std::vector<std::string> joinColNames = {folly::stringPrintf("%s_%d", kPathStr, 0)};
-    for (size_t i = 0; i < edgeInfos.size(); ++i) {
+    if (startIndex > 0) {
+        auto left = rightExpandPlan.root;
+        SubPlan leftExpandPlan = rightExpandPlan;
+        NG_RETURN_IF_ERROR(leftExpandFromNode(nodeInfos,
+                                              edgeInfos,
+                                              matchClauseCtx,
+                                              startIndex,
+                                              subplan.root->outputVar(),
+                                              leftExpandPlan));
+        rightExpandPlan.root = leftExpandPlan.root;
+        if (startIndex < nodeInfos.size() - 1) {
+            // Connect the left expand and right expand part.
+            auto right = leftExpandPlan.root;
+            rightExpandPlan.root =
+                SegmentsConnector::innerJoinSegments(matchClauseCtx->qctx,
+                                                     left,
+                                                     right,
+                                                     InnerJoinStrategy::JoinPos::kStart,
+                                                     InnerJoinStrategy::JoinPos::kStart);
+        }
+    }
+    subplan = rightExpandPlan;
+    return Status::OK();
+}
+
+Status MatchClausePlanner::leftExpandFromNode(const std::vector<NodeInfo>& nodeInfos,
+                                              const std::vector<EdgeInfo>& edgeInfos,
+                                              MatchClauseContext* matchClauseCtx,
+                                              size_t startIndex,
+                                              std::string inputVar,
+                                              SubPlan& subplan) {
+    std::vector<std::string> joinColNames = {
+        folly::stringPrintf("%s_%lu", kPathStr, nodeInfos.size())};
+    for (size_t i = startIndex; i > 0; --i) {
         auto left = subplan.root;
-        auto status = std::make_unique<Expand>(matchClauseCtx, &initialExpr_)
-                          ->doExpand(nodeInfos[i], edgeInfos[i], subplan.root, &subplan);
+        auto status = std::make_unique<Expand>(matchClauseCtx,
+                                               i == startIndex ? initialExpr_->clone() : nullptr)
+                          ->depends(subplan.root)
+                          ->inputVar(inputVar)
+                          ->reversely()
+                          ->doExpand(nodeInfos[i], edgeInfos[i - 1], &subplan);
         if (!status.ok()) {
             return status;
         }
-        if (i > 0) {
+        if (i < startIndex) {
+            auto right = subplan.root;
+            VLOG(1) << "left: " << folly::join(",", left->colNames())
+                << " right: " << folly::join(",", right->colNames());
+            subplan.root = SegmentsConnector::innerJoinSegments(matchClauseCtx->qctx, left, right);
+            joinColNames.emplace_back(
+                folly::stringPrintf("%s_%lu", kPathStr, nodeInfos.size() + i));
+            subplan.root->setColNames(joinColNames);
+        }
+        inputVar = subplan.root->outputVar();
+    }
+
+    VLOG(1) << "root: " << subplan.root->outputVar() << " tail: " << subplan.tail->outputVar();
+    auto left = subplan.root;
+    NG_RETURN_IF_ERROR(
+        appendFetchVertexPlan(nodeInfos.front().filter,
+                              matchClauseCtx->space,
+                              matchClauseCtx->qctx,
+                              edgeInfos.empty() ? initialExpr_->clone().release() : nullptr,
+                              subplan));
+    if (!edgeInfos.empty()) {
+        auto right = subplan.root;
+        VLOG(1) << "left: " << folly::join(",", left->colNames())
+            << " right: " << folly::join(",", right->colNames());
+        subplan.root = SegmentsConnector::innerJoinSegments(matchClauseCtx->qctx, left, right);
+        joinColNames.emplace_back(
+            folly::stringPrintf("%s_%lu", kPathStr, nodeInfos.size() + startIndex));
+        subplan.root->setColNames(joinColNames);
+    }
+
+    VLOG(1) << "root: " << subplan.root->outputVar() << " tail: " << subplan.tail->outputVar();
+    return Status::OK();
+}
+
+Status MatchClausePlanner::rightExpandFromNode(const std::vector<NodeInfo>& nodeInfos,
+                                               const std::vector<EdgeInfo>& edgeInfos,
+                                               MatchClauseContext* matchClauseCtx,
+                                               size_t startIndex,
+                                               SubPlan& subplan) {
+    std::vector<std::string> joinColNames = {folly::stringPrintf("%s_%lu", kPathStr, startIndex)};
+    for (size_t i = startIndex; i < edgeInfos.size(); ++i) {
+        auto left = subplan.root;
+        auto status =
+            std::make_unique<Expand>(matchClauseCtx,
+                                     i == startIndex ? initialExpr_->clone() : nullptr)
+                ->depends(subplan.root)
+                ->inputVar(subplan.root->outputVar())
+                ->doExpand(nodeInfos[i], edgeInfos[i], &subplan);
+        if (!status.ok()) {
+            return status;
+        }
+        if (i > startIndex) {
             auto right = subplan.root;
             VLOG(1) << "left: " << folly::join(",", left->colNames())
                 << " right: " << folly::join(",", right->colNames());
@@ -117,8 +224,12 @@ Status MatchClausePlanner::expand(const std::vector<NodeInfo>& nodeInfos,
 
     VLOG(1) << "root: " << subplan.root->outputVar() << " tail: " << subplan.tail->outputVar();
     auto left = subplan.root;
-    NG_RETURN_IF_ERROR(appendFetchVertexPlan(
-        nodeInfos.back().filter, matchClauseCtx->qctx, matchClauseCtx->space, &subplan));
+    NG_RETURN_IF_ERROR(
+        appendFetchVertexPlan(nodeInfos.back().filter,
+                              matchClauseCtx->space,
+                              matchClauseCtx->qctx,
+                              edgeInfos.empty() ? initialExpr_->clone().release() : nullptr,
+                              subplan));
     if (!edgeInfos.empty()) {
         auto right = subplan.root;
         VLOG(1) << "left: " << folly::join(",", left->colNames())
@@ -132,14 +243,29 @@ Status MatchClausePlanner::expand(const std::vector<NodeInfo>& nodeInfos,
     return Status::OK();
 }
 
+Status MatchClausePlanner::expandFromEdge(const std::vector<NodeInfo>& nodeInfos,
+                                          const std::vector<EdgeInfo>& edgeInfos,
+                                          MatchClauseContext* matchClauseCtx,
+                                          size_t startIndex,
+                                          SubPlan& subplan) {
+    UNUSED(nodeInfos);
+    UNUSED(edgeInfos);
+    UNUSED(matchClauseCtx);
+    UNUSED(startIndex);
+    UNUSED(subplan);
+    return Status::Error("Expand from edge has not been implemented yet.");
+}
+
 Status MatchClausePlanner::appendFetchVertexPlan(const Expression* nodeFilter,
+                                                 const SpaceInfo& space,
                                                  QueryContext* qctx,
-                                                 SpaceInfo& space,
-                                                 SubPlan* plan) {
-    MatchSolver::extractAndDedupVidColumn(qctx, &initialExpr_, plan);
+                                                 Expression* initialExpr,
+                                                 SubPlan& plan) {
+    MatchSolver::extractAndDedupVidColumn(
+        qctx, initialExpr, plan.root, plan.root->outputVar(), plan);
     auto srcExpr = ExpressionUtils::inputPropExpr(kVid);
     auto gv = GetVertices::make(
-        qctx, plan->root, space.id, qctx->objPool()->add(srcExpr.release()), {}, {});
+        qctx, plan.root, space.id, qctx->objPool()->add(srcExpr.release()), {}, {});
 
     PlanNode* root = gv;
     if (nodeFilter != nullptr) {
@@ -158,6 +284,7 @@ Status MatchClausePlanner::appendFetchVertexPlan(const Expression* nodeFilter,
             return new VertexExpression();
         });
         filter->accept(&visitor);
+        qctx->objPool()->add(filter);
         root = Filter::make(qctx, root, filter);
     }
 
@@ -166,35 +293,54 @@ Status MatchClausePlanner::appendFetchVertexPlan(const Expression* nodeFilter,
     auto pathExpr = std::make_unique<PathBuildExpression>();
     pathExpr->add(std::make_unique<VertexExpression>());
     columns->addColumn(new YieldColumn(pathExpr.release()));
-    plan->root = Project::make(qctx, root, columns);
-    plan->root->setColNames({kPathStr});
+    plan.root = Project::make(qctx, root, columns);
+    plan.root->setColNames({kPathStr});
     return Status::OK();
 }
 
 Status MatchClausePlanner::projectColumnsBySymbols(MatchClauseContext* matchClauseCtx,
-                                                   SubPlan* plan) {
+                                                   size_t startIndex,
+                                                   SubPlan& plan) {
     auto qctx = matchClauseCtx->qctx;
     auto& nodeInfos = matchClauseCtx->nodeInfos;
     auto& edgeInfos = matchClauseCtx->edgeInfos;
-    auto columns = qctx->objPool()->add(new YieldColumns);
-    auto input = plan->root;
+    auto input = plan.root;
     const auto& inColNames = input->colNamesRef();
-    DCHECK_EQ(inColNames.size(), nodeInfos.size());
+    auto columns = qctx->objPool()->add(new YieldColumns);
     std::vector<std::string> colNames;
 
     auto addNode = [&, this](size_t i) {
         auto& nodeInfo = nodeInfos[i];
         if (nodeInfo.alias != nullptr && !nodeInfo.anonymous) {
-            columns->addColumn(buildVertexColumn(inColNames[i], *nodeInfo.alias));
+            if (i >= startIndex) {
+                columns->addColumn(
+                    buildVertexColumn(inColNames[i - startIndex], *nodeInfo.alias));
+            } else if (startIndex == (nodeInfos.size() - 1)) {
+                columns->addColumn(buildVertexColumn(
+                    inColNames[startIndex - i], *nodeInfo.alias));
+            } else {
+                columns->addColumn(buildVertexColumn(
+                    inColNames[nodeInfos.size() - i], *nodeInfo.alias));
+            }
             colNames.emplace_back(*nodeInfo.alias);
         }
     };
 
     for (size_t i = 0; i < edgeInfos.size(); i++) {
+        VLOG(1) << "colSize: " << inColNames.size() << "i: " << i
+                << " nodesize: " << nodeInfos.size() << " start: " << startIndex;
         addNode(i);
         auto& edgeInfo = edgeInfos[i];
         if (edgeInfo.alias != nullptr && !edgeInfo.anonymous) {
-            columns->addColumn(buildEdgeColumn(inColNames[i], edgeInfo));
+            if (i >= startIndex) {
+                columns->addColumn(buildEdgeColumn(inColNames[i - startIndex], edgeInfo));
+            } else if (startIndex == (nodeInfos.size() - 1)) {
+                columns->addColumn(
+                    buildEdgeColumn(inColNames[edgeInfos.size() - 1 - i], edgeInfo));
+            } else {
+                columns->addColumn(
+                    buildEdgeColumn(inColNames[edgeInfos.size() - i], edgeInfo));
+            }
             colNames.emplace_back(*edgeInfo.alias);
         }
     }
@@ -207,15 +353,16 @@ Status MatchClausePlanner::projectColumnsBySymbols(MatchClauseContext* matchClau
     auto iter = std::find_if(aliases.begin(), aliases.end(), [](const auto& alias) {
         return alias.second == AliasType::kPath;
     });
-    std::string alias = iter != aliases.end() ? iter->first : qctx->vctx()->anonColGen()->getCol();
-    columns->addColumn(buildPathColumn(alias, input));
+    std::string alias =
+        iter != aliases.end() ? iter->first : qctx->vctx()->anonColGen()->getCol();
+    columns->addColumn(buildPathColumn(alias, startIndex, inColNames, nodeInfos.size()));
     colNames.emplace_back(alias);
 
     auto project = Project::make(qctx, input, columns);
     project->setColNames(std::move(colNames));
 
-    plan->root = MatchSolver::filtPathHasSameEdge(project, alias, qctx);
-    VLOG(1) << "root: " << plan->root->outputVar() << " tail: " << plan->tail->outputVar();
+    plan.root = MatchSolver::filtPathHasSameEdge(project, alias, qctx);
+    VLOG(1) << "root: " << plan.root->outputVar() << " tail: " << plan.tail->outputVar();
     return Status::OK();
 }
 
@@ -250,12 +397,45 @@ YieldColumn* MatchClausePlanner::buildEdgeColumn(const std::string& colName, Edg
 }
 
 YieldColumn* MatchClausePlanner::buildPathColumn(const std::string& alias,
-                                                 const PlanNode* input) const {
-    auto pathExpr = std::make_unique<PathBuildExpression>();
-    for (const auto& colName : input->colNamesRef()) {
-        pathExpr->add(ExpressionUtils::inputPropExpr(colName));
+                                                 size_t startIndex,
+                                                 const std::vector<std::string> colNames,
+                                                 size_t nodeInfoSize) const {
+    auto colSize = colNames.size();
+    DCHECK((nodeInfoSize == colSize) || (nodeInfoSize + 1 == colSize));
+    size_t bound = 0;
+    if (colSize > nodeInfoSize) {
+        bound = colSize - startIndex - 1;
+    } else if (startIndex == (nodeInfoSize - 1)) {
+        bound = 0;
+    } else {
+        bound = colSize - startIndex;
+    }
+
+    auto rightExpandPath = std::make_unique<PathBuildExpression>();
+    for (size_t i = 0; i < bound; ++i) {
+        rightExpandPath->add(ExpressionUtils::inputPropExpr(colNames[i]));
+    }
+
+    auto leftExpandPath = std::make_unique<PathBuildExpression>();
+    for (size_t i = bound; i < colNames.size(); ++i) {
+        leftExpandPath->add(ExpressionUtils::inputPropExpr(colNames[i]));
+    }
+
+    auto finalPath = std::make_unique<PathBuildExpression>();
+    if (leftExpandPath->size() != 0) {
+        auto args = new ArgumentList();
+        args->addArgument(std::move(leftExpandPath));
+        auto reversePath =
+            std::make_unique<FunctionCallExpression>(new std::string("reversePath"), args);
+        if (rightExpandPath->size() == 0) {
+            return new YieldColumn(reversePath.release(), new std::string(alias));
+        }
+        finalPath->add(std::move(reversePath));
+    }
+    if (rightExpandPath->size() != 0) {
+        finalPath->add(std::move(rightExpandPath));
     }
-    return new YieldColumn(pathExpr.release(), new std::string(alias));
+    return new YieldColumn(finalPath.release(), new std::string(alias));
 }
 
 Status MatchClausePlanner::appendFilterPlan(MatchClauseContext* matchClauseCtx, SubPlan& subplan) {
diff --git a/src/planner/match/MatchClausePlanner.h b/src/planner/match/MatchClausePlanner.h
index cd88e3dede23eebb84acd62847f46ca68a0eedb3..a726c3a2e438c1a97558100585d2775011a8972f 100644
--- a/src/planner/match/MatchClausePlanner.h
+++ b/src/planner/match/MatchClausePlanner.h
@@ -22,32 +22,67 @@ public:
 
 private:
     Status findStarts(MatchClauseContext* matchClauseCtx,
-                      int64_t& startIndex,
+                      bool& startFromEdge,
+                      size_t& startIndex,
                       SubPlan& matchClausePlan);
 
     Status expand(const std::vector<NodeInfo>& nodeInfos,
                   const std::vector<EdgeInfo>& edgeInfos,
                   MatchClauseContext* matchClauseCtx,
-                  int64_t startIndex,
+                  bool startFromEdge,
+                  size_t startIndex,
                   SubPlan& subplan);
 
+    Status expandFromNode(const std::vector<NodeInfo>& nodeInfos,
+                          const std::vector<EdgeInfo>& edgeInfos,
+                          MatchClauseContext* matchClauseCtx,
+                          size_t startIndex,
+                          SubPlan& subplan);
+
+    PlanNode* joinLeftAndRightExpandPart(QueryContext* qctx, PlanNode* left, PlanNode* right);
+
+    Status leftExpandFromNode(const std::vector<NodeInfo>& nodeInfos,
+                              const std::vector<EdgeInfo>& edgeInfos,
+                              MatchClauseContext* matchClauseCtx,
+                              size_t startIndex,
+                              std::string inputVar,
+                              SubPlan& subplan);
+
+    Status rightExpandFromNode(const std::vector<NodeInfo>& nodeInfos,
+                               const std::vector<EdgeInfo>& edgeInfos,
+                               MatchClauseContext* matchClauseCtx,
+                               size_t startIndex,
+                               SubPlan& subplan);
+
+    Status expandFromEdge(const std::vector<NodeInfo>& nodeInfos,
+                          const std::vector<EdgeInfo>& edgeInfos,
+                          MatchClauseContext* matchClauseCtx,
+                          size_t startIndex,
+                          SubPlan& subplan);
+
     Status appendFetchVertexPlan(const Expression* nodeFilter,
+                                 const SpaceInfo& space,
                                  QueryContext* qctx,
-                                 SpaceInfo& space,
-                                 SubPlan* plan);
+                                 Expression* initialExpr,
+                                 SubPlan& plan);
 
-    Status projectColumnsBySymbols(MatchClauseContext* matchClauseCtx, SubPlan *plan);
+    Status projectColumnsBySymbols(MatchClauseContext* matchClauseCtx,
+                                   size_t startIndex,
+                                   SubPlan& plan);
 
     YieldColumn* buildVertexColumn(const std::string& colName, const std::string& alias) const;
 
     YieldColumn* buildEdgeColumn(const std::string& colName, EdgeInfo& edge) const;
 
-    YieldColumn* buildPathColumn(const std::string& alias, const PlanNode* input) const;
+    YieldColumn* buildPathColumn(const std::string& alias,
+                                 size_t startIndex,
+                                 const std::vector<std::string> colNames,
+                                 size_t nodeInfoSize) const;
 
     Status appendFilterPlan(MatchClauseContext* matchClauseCtx, SubPlan& subplan);
 
 private:
-    Expression* initialExpr_;
+    std::unique_ptr<Expression> initialExpr_;
 };
 }  // namespace graph
 }  // namespace nebula
diff --git a/src/planner/match/MatchSolver.cpp b/src/planner/match/MatchSolver.cpp
index e748bbf2716805f73ca1f2eb2cc8811205837e27..d28c8a2e39c8634005c793a8b3922195e55316ce 100644
--- a/src/planner/match/MatchSolver.cpp
+++ b/src/planner/match/MatchSolver.cpp
@@ -162,33 +162,33 @@ Status MatchSolver::buildFilter(const MatchClauseContext* mctx, SubPlan* plan) {
 }
 
 void MatchSolver::extractAndDedupVidColumn(QueryContext* qctx,
-                                           Expression** initialExpr,
-                                           SubPlan* plan) {
+                                           Expression* initialExpr,
+                                           PlanNode* dep,
+                                           const std::string& inputVar,
+                                           SubPlan& plan) {
     auto columns = qctx->objPool()->add(new YieldColumns);
-    auto input = plan->root;
-    Expression* vidExpr = initialExprOrEdgeDstExpr(input, initialExpr);
+    auto* var = qctx->symTable()->getVar(inputVar);
+    Expression* vidExpr = initialExprOrEdgeDstExpr(initialExpr, var->colNames.back());
     columns->addColumn(new YieldColumn(vidExpr));
-    auto project = Project::make(qctx, input, columns);
+    auto project = Project::make(qctx, dep, columns);
+    project->setInputVar(inputVar);
     project->setColNames({kVid});
     auto dedup = Dedup::make(qctx, project);
     dedup->setColNames({kVid});
 
-    plan->root = dedup;
-    // plan->tail = dedup;
+    plan.root = dedup;
 }
 
-Expression* MatchSolver::initialExprOrEdgeDstExpr(const PlanNode* node, Expression** initialExpr) {
-    Expression* vidExpr = *initialExpr;
-    if (vidExpr != nullptr) {
-        VLOG(1) << vidExpr->toString();
-        *initialExpr = nullptr;
+Expression* MatchSolver::initialExprOrEdgeDstExpr(Expression* initialExpr,
+                                                  const std::string& vidCol) {
+    if (initialExpr != nullptr) {
+        return initialExpr;
     } else {
-        vidExpr = getLastEdgeDstExprInLastPath(node->colNamesRef().back());
+        return getEndVidInPath(vidCol);
     }
-    return vidExpr;
 }
 
-Expression* MatchSolver::getLastEdgeDstExprInLastPath(const std::string& colName) {
+Expression* MatchSolver::getEndVidInPath(const std::string& colName) {
     // expr: __Project_2[-1] => path
     auto columnExpr = ExpressionUtils::inputPropExpr(colName);
     // expr: endNode(path) => vn
@@ -201,7 +201,7 @@ Expression* MatchSolver::getLastEdgeDstExprInLastPath(const std::string& colName
     return new AttributeExpression(endNode.release(), vidExpr.release());
 }
 
-Expression* MatchSolver::getFirstVertexVidInFistPath(const std::string& colName) {
+Expression* MatchSolver::getStartVidInPath(const std::string& colName) {
     // expr: __Project_2[0] => path
     auto columnExpr = ExpressionUtils::inputPropExpr(colName);
     // expr: startNode(path) => v1
diff --git a/src/planner/match/MatchSolver.h b/src/planner/match/MatchSolver.h
index 5e6cf5a3d80d442ac078a1428c1838690e7a52f6..ddce44c342d3b99413aabcdd75117d1dcad7e9f0 100644
--- a/src/planner/match/MatchSolver.h
+++ b/src/planner/match/MatchSolver.h
@@ -45,14 +45,17 @@ public:
     static Status buildFilter(const MatchClauseContext* mctx, SubPlan* plan);
 
     static void extractAndDedupVidColumn(QueryContext* qctx,
-                                         Expression** initialExpr,
-                                         SubPlan* plan);
+                                         Expression* initialExpr,
+                                         PlanNode* dep,
+                                         const std::string& inputVar,
+                                         SubPlan& plan);
 
-    static Expression* initialExprOrEdgeDstExpr(const PlanNode* node, Expression** initialExpr);
+    static Expression* initialExprOrEdgeDstExpr(Expression* initialExpr,
+                                                const std::string& vidCol);
 
-    static Expression* getLastEdgeDstExprInLastPath(const std::string& colName);
+    static Expression* getEndVidInPath(const std::string& colName);
 
-    static Expression* getFirstVertexVidInFistPath(const std::string& colName);
+    static Expression* getStartVidInPath(const std::string& colName);
 
     static PlanNode* filtPathHasSameEdge(PlanNode* input,
                                          const std::string& column,
diff --git a/src/planner/match/PropIndexSeek.cpp b/src/planner/match/PropIndexSeek.cpp
index 2cb25c964fab59a5d31f318301e30343f5b7fcd7..5b42dddcae1bba510d889dc5cf5213e490079a87 100644
--- a/src/planner/match/PropIndexSeek.cpp
+++ b/src/planner/match/PropIndexSeek.cpp
@@ -74,7 +74,7 @@ StatusOr<SubPlan> PropIndexSeek::transformNode(NodeContext* nodeCtx) {
     plan.root = scan;
 
     // initialize start expression in project node
-    nodeCtx->initialExpr = ExpressionUtils::newVarPropExpr(kVid);
+    nodeCtx->initialExpr = std::unique_ptr<Expression>(ExpressionUtils::newVarPropExpr(kVid));
     return plan;
 }
 
diff --git a/src/planner/match/SegmentsConnectStrategy.h b/src/planner/match/SegmentsConnectStrategy.h
new file mode 100644
index 0000000000000000000000000000000000000000..c18bbc6a26618872f03d594a36893b38b574f095
--- /dev/null
+++ b/src/planner/match/SegmentsConnectStrategy.h
@@ -0,0 +1,26 @@
+/* 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 PLANNER_MATCH_SEGMENTSCONNECTSTRATEGY_H_
+#define PLANNER_MATCH_SEGMENTSCONNECTSTRATEGY_H_
+
+namespace nebula {
+namespace graph {
+
+class SegmentsConnectStrategy {
+public:
+    explicit SegmentsConnectStrategy(QueryContext* qctx) : qctx_(qctx) {}
+
+    virtual ~SegmentsConnectStrategy() = default;
+
+    virtual PlanNode* connect(const PlanNode* left, const PlanNode* right) = 0;
+
+protected:
+    QueryContext*   qctx_;
+};
+}  // namespace graph
+}  // namespace nebula
+#endif  // PLANNER_MATCH_SEGMENTSCONNECTSTRATEGY_H_
diff --git a/src/planner/match/SegmentsConnector.cpp b/src/planner/match/SegmentsConnector.cpp
index c6c790b05851ff84386f2355b28758960d5e602e..30eea7d56673cab2881b14704e801cc9ee62b9da 100644
--- a/src/planner/match/SegmentsConnector.cpp
+++ b/src/planner/match/SegmentsConnector.cpp
@@ -7,7 +7,6 @@
 #include "planner/match/SegmentsConnector.h"
 #include "planner/match/AddDependencyStrategy.h"
 #include "planner/match/AddInputStrategy.h"
-#include "planner/match/InnerJoinStrategy.h"
 #include "planner/match/CartesianProductStrategy.h"
 
 namespace nebula {
@@ -36,9 +35,14 @@ StatusOr<SubPlan> SegmentsConnector::connectSegments(CypherClauseContextBase* le
 }
 
 PlanNode* SegmentsConnector::innerJoinSegments(QueryContext* qctx,
-                                            const PlanNode* left,
-                                            const PlanNode* right) {
-    return std::make_unique<InnerJoinStrategy>(qctx)->connect(left, right);
+                                               const PlanNode* left,
+                                               const PlanNode* right,
+                                               InnerJoinStrategy::JoinPos leftPos,
+                                               InnerJoinStrategy::JoinPos rightPos) {
+    return std::make_unique<InnerJoinStrategy>(qctx)
+                ->leftPos(leftPos)
+                ->rightPos(rightPos)
+                ->connect(left, right);
 }
 
 PlanNode* SegmentsConnector::cartesianProductSegments(QueryContext* qctx,
diff --git a/src/planner/match/SegmentsConnector.h b/src/planner/match/SegmentsConnector.h
index 39e54871558b9e42cbd175982d282a6ed664a6a2..f664e44090214fdde45f88c493b0d947c34f3e32 100644
--- a/src/planner/match/SegmentsConnector.h
+++ b/src/planner/match/SegmentsConnector.h
@@ -11,6 +11,7 @@
 #include "context/ast/QueryAstContext.h"
 #include "planner/PlanNode.h"
 #include "planner/Planner.h"
+#include "planner/match/InnerJoinStrategy.h"
 
 namespace nebula {
 namespace graph {
@@ -36,9 +37,12 @@ public:
                                              SubPlan& left,
                                              SubPlan& right);
 
-    static PlanNode* innerJoinSegments(QueryContext* qctx,
-                                       const PlanNode* left,
-                                       const PlanNode* right);
+    static PlanNode* innerJoinSegments(
+        QueryContext* qctx,
+        const PlanNode* left,
+        const PlanNode* right,
+        InnerJoinStrategy::JoinPos leftPos = InnerJoinStrategy::JoinPos::kEnd,
+        InnerJoinStrategy::JoinPos rightPos = InnerJoinStrategy::JoinPos::kStart);
 
     static PlanNode* cartesianProductSegments(QueryContext* qctx,
                                               const PlanNode* left,
@@ -48,18 +52,6 @@ public:
 
     static void addInput(const PlanNode* left, const PlanNode* right, bool copyColNames = false);
 };
-
-class SegmentsConnectStrategy {
-public:
-    explicit SegmentsConnectStrategy(QueryContext* qctx) : qctx_(qctx) {}
-
-    virtual ~SegmentsConnectStrategy() = default;
-
-    virtual PlanNode* connect(const PlanNode* left, const PlanNode* right) = 0;
-
-protected:
-    QueryContext*   qctx_;
-};
 }  // namespace graph
 }  // namespace nebula
 #endif  // PLANNER_MATCH_SEGMENTSCONNECTOR_H_
diff --git a/src/planner/match/VertexIdSeek.cpp b/src/planner/match/VertexIdSeek.cpp
index 6d0a30f13f7af7bcdb19dff0f210baf383c52a6b..3e6c82979fdf37c0403d33673c0da40c180648e5 100644
--- a/src/planner/match/VertexIdSeek.cpp
+++ b/src/planner/match/VertexIdSeek.cpp
@@ -122,7 +122,7 @@ StatusOr<SubPlan> VertexIdSeek::transformNode(NodeContext* nodeCtx) {
     plan.root = passThrough;
     plan.tail = passThrough;
 
-    nodeCtx->initialExpr = vidsResult.second;
+    nodeCtx->initialExpr = std::unique_ptr<Expression>(vidsResult.second);
     VLOG(1) << "root: " << plan.root->kind() << " tail: " << plan.tail->kind();
     return plan;
 }
diff --git a/src/validator/MatchValidator.cpp b/src/validator/MatchValidator.cpp
index 89ce6dc5b64c3f66e0b2543cb5e110b8f1e59557..497a4ce9de157984e89e60994dadcd11a4e72451 100644
--- a/src/validator/MatchValidator.cpp
+++ b/src/validator/MatchValidator.cpp
@@ -231,6 +231,16 @@ Status MatchValidator::buildEdgeInfo(const MatchPath *path,
                 edgeInfos[i].edgeTypes.emplace_back(etype.value());
                 edgeInfos[i].types.emplace_back(*type);
             }
+        } else {
+            const auto allEdgesResult =
+                matchCtx_->qctx->schemaMng()->getAllVerEdgeSchema(space_.id);
+            NG_RETURN_IF_ERROR(allEdgesResult);
+            const auto allEdges = std::move(allEdgesResult).value();
+            for (const auto &edgeSchema : allEdges) {
+                edgeInfos[i].edgeTypes.emplace_back(edgeSchema.first);
+                // TODO:
+                // edgeInfos[i].types.emplace_back(*type);
+            }
         }
         auto *stepRange = edge->range();
         if (stepRange != nullptr) {
diff --git a/src/validator/test/QueryValidatorTest.cpp b/src/validator/test/QueryValidatorTest.cpp
index b543e53cada7ca0adc9ebe20215ea01d5866b2dc..084add461315013eaad4a9cf8dd97e598e7f3453 100644
--- a/src/validator/test/QueryValidatorTest.cpp
+++ b/src/validator/test/QueryValidatorTest.cpp
@@ -1359,6 +1359,81 @@ TEST_F(QueryValidatorTest, TestMatch) {
         };
         EXPECT_TRUE(checkResult(query, expected));
     }
+    {
+        std::string query = "MATCH (v1)-[e:serve*2..3{start_year: 2000}]-(v2) "
+                            "WHERE id(v1) == \"LeBron James\""
+                            "RETURN v1, v2";
+        std::vector<PlanNode::Kind> expected = {
+            PK::kProject,
+            PK::kFilter,
+            PK::kFilter,
+            PK::kProject,
+            PK::kDataJoin,
+            PK::kProject,
+            PK::kGetVertices,
+            PK::kDedup,
+            PK::kProject,
+            PK::kFilter,
+            PK::kUnion,
+            PK::kPassThrough,
+            PK::kUnion,
+            PK::kFilter,
+            PK::kPassThrough,
+            PK::kPassThrough,
+            PK::kProject,
+            PK::kFilter,
+            PK::kProject,
+            PK::kDataJoin,
+            PK::kProject,
+            PK::kFilter,
+            PK::kProject,
+            PK::kDataJoin,
+            PK::kGetNeighbors,
+            PK::kFilter,
+            PK::kProject,
+            PK::kDedup,
+            PK::kGetNeighbors,
+            PK::kFilter,
+            PK::kProject,
+            PK::kDedup,
+            PK::kGetNeighbors,
+            PK::kPassThrough,
+            PK::kProject,
+            PK::kDedup,
+            PK::kStart,
+            PK::kProject,
+        };
+        EXPECT_TRUE(checkResult(query, expected));
+    }
+    {
+        std::string query = "MATCH p = (n)-[]-(m:person{name:\"LeBron James\"}) RETURN p";
+        std::vector<PlanNode::Kind> expected = {
+            PK::kProject,
+            PK::kFilter,
+            PK::kProject,
+            PK::kDataJoin,
+            PK::kProject,
+            PK::kGetVertices,
+            PK::kDedup,
+            PK::kProject,
+            PK::kFilter,
+            PK::kPassThrough,
+            PK::kProject,
+            PK::kFilter,
+            PK::kGetNeighbors,
+            PK::kDedup,
+            PK::kProject,
+            PK::kDataJoin,
+            PK::kProject,
+            PK::kFilter,
+            PK::kGetVertices,
+            PK::kDedup,
+            PK::kProject,
+            PK::kIndexScan,
+            PK::kStart,
+        };
+        EXPECT_TRUE(checkResult(query, expected));
+    }
 }
 
 
diff --git a/tests/tck/features/bugfix/MatchNotFilterTheUndeclaredTag.feature b/tests/tck/features/bugfix/MatchNotFilterTheUndeclaredTag.feature
new file mode 100644
index 0000000000000000000000000000000000000000..2ff81fadc004d05532c77491524ebcbe3d895545
--- /dev/null
+++ b/tests/tck/features/bugfix/MatchNotFilterTheUndeclaredTag.feature
@@ -0,0 +1,97 @@
+# 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.
+Feature: Fix match not filter the undeclared tag, pr#501
+
+  Background:
+    Given a graph with space named "nba"
+
+  Scenario: [1] one step given tag without property
+    When executing query:
+      """
+      MATCH (v:player{name:"Tim Duncan"})-->(v2:team)
+      RETURN v2 AS Team
+      """
+    Then the result should be, in any order:
+      | Team                           |
+      | ("Spurs" :team{name: "Spurs"}) |
+
+  Scenario: [2] one step given tag without property
+    When executing query:
+      """
+      MATCH (v:team{name:"Spurs"})--(v2)
+      RETURN v2 AS Player
+      """
+    Then the result should be, in any order:
+      | Player                                                                                                      |
+      | ("Aron Baynes" :player{age: 32, name: "Aron Baynes"})                                                       |
+      | ("Boris Diaw" :player{age: 36, name: "Boris Diaw"})                                                         |
+      | ("Cory Joseph" :player{age: 27, name: "Cory Joseph"})                                                       |
+      | ("Danny Green" :player{age: 31, name: "Danny Green"})                                                       |
+      | ("David West" :player{age: 38, name: "David West"})                                                         |
+      | ("Dejounte Murray" :player{age: 29, name: "Dejounte Murray"})                                               |
+      | ("Jonathon Simmons" :player{age: 29, name: "Jonathon Simmons"})                                             |
+      | ("Kyle Anderson" :player{age: 25, name: "Kyle Anderson"})                                                   |
+      | ("LaMarcus Aldridge" :player{age: 33, name: "LaMarcus Aldridge"})                                           |
+      | ("Manu Ginobili" :player{age: 41, name: "Manu Ginobili"})                                                   |
+      | ("Marco Belinelli" :player{age: 32, name: "Marco Belinelli"})                                               |
+      | ("Paul Gasol" :player{age: 38, name: "Paul Gasol"})                                                         |
+      | ("Rudy Gay" :player{age: 32, name: "Rudy Gay"})                                                             |
+      | ("Tiago Splitter" :player{age: 34, name: "Tiago Splitter"})                                                 |
+      | ("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"}) |
+      | ("Tony Parker" :player{age: 36, name: "Tony Parker"})                                                       |
+      | ("Tracy McGrady" :player{age: 39, name: "Tracy McGrady"})                                                   |
+      | ("Marco Belinelli" :player{age: 32, name: "Marco Belinelli"})                                               |
+
+  Scenario: [1] multi steps given tag without property
+    When executing query:
+      """
+      MATCH (v:player{name: "Tim Duncan"})-->(v2:team)<--(v3)
+      RETURN v2 AS Team
+      """
+    Then the result should be, in any order:
+      | Team                           |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+
+  Scenario: multi steps given tag without property no direction
+    When executing query:
+      """
+      MATCH (v:player{name: "Tim Duncan"})--(v2:team)--(v3)
+      RETURN v2 AS Team
+      """
+    Then the result should be, in any order:
+      | Team                           |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
+      | ("Spurs" :team{name: "Spurs"}) |
diff --git a/tests/tck/features/match/Base.feature b/tests/tck/features/match/Base.feature
index 441a53e400442a0c215f95c5e882c56551751a25..cd7ccb52b37f1bf225cab6e7636eea16640032c7 100644
--- a/tests/tck/features/match/Base.feature
+++ b/tests/tck/features/match/Base.feature
@@ -35,98 +35,3 @@ Feature: Basic match
       | 'Jonathon Simmons' |
       | 'Klay Thompson'    |
       | 'Dejounte Murray'  |
-
-  Scenario: [1] one step given tag without property
-    Given a graph with space named "nba"
-    When executing query:
-      """
-      MATCH (v:player{name:"Tim Duncan"})-->(v2:team)
-      RETURN v2 AS Team
-      """
-    Then the result should be, in any order:
-      | Team                           |
-      | ("Spurs" :team{name: "Spurs"}) |
-
-  @skip
-  Scenario: [2] one step given tag without property
-    When executing query:
-      """
-      MATCH (v:team{name:"Spurs"})--(v2)
-      RETURN v2 AS Player
-      """
-    Then the result should be, in any order:
-      | ("Player"                                                      ) |
-      | ("Boris Diaw" :player{name: "Boris Diaw",age: 36}              ) |
-      | ("Kyle Anderson" :player{name: "Kyle Anderson",age: 25}        ) |
-      | ("Cory Joseph" :player{name: "Cory Joseph",age: 27}            ) |
-      | ("Tiago Splitter" :player{name: "Tiago Splitter",age: 34}      ) |
-      | ("LaMarcus Aldridge" :player{name: "LaMarcus Aldridge",age: 33}) |
-      | ("Paul Gasol" :player{name: "Paul Gasol",age: 38}              ) |
-      | ("Marco Belinelli" :player{name: "Marco Belinelli",age: 32}    ) |
-      | ("Tracy McGrady" :player{name: "Tracy McGrady",age: 39}        ) |
-      | ("David West" :player{name: "David West",age: 38}              ) |
-      | ("Manu Ginobili" :player{name: "Manu Ginobili",age: 41}        ) |
-      | ("Tony Parker" :player{name: "Tony Parker",age: 36}            ) |
-      | ("Rudy Gay" :player{name: "Rudy Gay",age: 32}                  ) |
-      | ("Jonathon Simmons" :player{name: "Jonathon Simmons",age: 29}  ) |
-      | ("Aron Baynes" :player{name: "Aron Baynes",age: 32}            ) |
-      | ("Danny Green" :player{name: "Danny Green",age: 31}            ) |
-      | ("Tim Duncan" :player{name: "Tim Duncan",age: 42}              ) |
-      | ("Marco Belinelli" :player{name: "Marco Belinelli",age: 32}    ) |
-      | ("Dejounte Murray" :player{name: "Dejounte Murray",age: 29}    ) |
-
-  @skip
-  Scenario: [1] multi steps given tag without property
-    Given a graph with space named "nba"
-    When executing query:
-      """
-      MATCH (v:player{name: "Tim Duncan"})-->(v2:team)<--(v3)
-      RETURN v2 AS Team
-      """
-    Then the result should be, in any order:
-      | Team                           |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-
-  @skip
-  Scenario: multi steps given tag without property no direction
-    Given a graph with space named "nba"
-    When executing query:
-      """
-      MATCH (v:player{name: "Tim Duncan"})--(v2:team)--(v3)
-      RETURN v2 AS Team
-      """
-    Then the result should be, in any order:
-      | Team                           |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
-      | ("Spurs" :team{name: "Spurs"}) |
diff --git a/tests/tck/features/match/MatchById.intVid.feature b/tests/tck/features/match/MatchById.IntVid.feature
similarity index 99%
rename from tests/tck/features/match/MatchById.intVid.feature
rename to tests/tck/features/match/MatchById.IntVid.feature
index b0e6b13e28a42eff2c8986afffd189f73b843c45..b709098589bf9c5e0cce15eca4cc5ddd43001a4e 100644
--- a/tests/tck/features/match/MatchById.intVid.feature
+++ b/tests/tck/features/match/MatchById.IntVid.feature
@@ -88,6 +88,7 @@ Feature: Integer Vid Match By Id
       """
     Then the result should be, in any order, with relax comparison:
       | start           | e                                          | end                   |
+      | ("Paul George") | [:like "Paul George"<-"Russell Westbrook"] | ("Russell Westbrook") |
       | ("Paul George") | [:like "Paul George"->"Russell Westbrook"] | ("Russell Westbrook") |
       | ("Paul George") | [:serve "Paul George"->"Pacers"]           | ("Pacers")            |
       | ("Paul George") | [:serve "Paul George"->"Thunders"]         | ("Thunders")          |
diff --git a/tests/tck/features/match/MatchById.feature b/tests/tck/features/match/MatchById.feature
index d8db1206491dfc3f2995ef85d6e51f8f3c1fa3f7..d873163b80dbd91554fd0350a88bda96976acd15 100644
--- a/tests/tck/features/match/MatchById.feature
+++ b/tests/tck/features/match/MatchById.feature
@@ -88,6 +88,7 @@ Feature: Match By Id
       """
     Then the result should be, in any order, with relax comparison:
       | start           | e                                          | end                   |
+      | ("Paul George") | [:like "Paul George"<-"Russell Westbrook"] | ("Russell Westbrook") |
       | ("Paul George") | [:like "Paul George"->"Russell Westbrook"] | ("Russell Westbrook") |
       | ("Paul George") | [:serve "Paul George"->"Pacers"]           | ("Pacers")            |
       | ("Paul George") | [:serve "Paul George"->"Thunders"]         | ("Thunders")          |
diff --git a/tests/tck/features/match/StartFromAnyNode.IntVid.feature b/tests/tck/features/match/StartFromAnyNode.IntVid.feature
new file mode 100644
index 0000000000000000000000000000000000000000..b5adb78af28ee79741725ebad929586b1d01672b
--- /dev/null
+++ b/tests/tck/features/match/StartFromAnyNode.IntVid.feature
@@ -0,0 +1,533 @@
+# 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.
+Feature: Start From Any Node
+
+  Background:
+    Given a graph with space named "nba_int_vid"
+
+  Scenario: start from middle node, with prop index, with totally 2 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)
+      RETURN n,m,l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l                   |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Spurs")           | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Spurs")           |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Spurs")           |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player)-[]-(l)
+      WHERE m.name=="Kyle Anderson"
+      RETURN n,m,l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l                   |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Spurs")           | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Spurs")           |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Spurs")           |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Spurs")           |
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                 |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")<-[:teammate@0]-("Tony Parker")> |
+      | <("Grizzlies")<-[:serve@0]-("Kyle Anderson")<-[:teammate@0]-("Tony Parker")>      |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")<-[:teammate@0]-("Tony Parker")>          |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")<-[:like@0]-("Dejounte Murray")> |
+      | <("Grizzlies")<-[:serve@0]-("Kyle Anderson")<-[:like@0]-("Dejounte Murray")>      |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")<-[:like@0]-("Dejounte Murray")>          |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")>      |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")>      |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")-[:serve@0]->("Grizzlies")>               |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")-[:serve@0]->("Spurs")>          |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")-[:serve@0]->("Spurs")>          |
+      | <("Grizzlies")<-[:serve@0]-("Kyle Anderson")-[:serve@0]->("Spurs")>               |
+    When executing query:
+      """
+      MATCH (n)-[e1]-(m:player{name:"Kyle Anderson"})-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)-[e1]-(m:player{name:"Kyle Anderson"})-[e2]->(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                       | l             |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+    When executing query:
+      """
+      MATCH (n)-[e1]-(m:player{name:"Kyle Anderson"})<-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+    When executing query:
+      """
+      MATCH (n)-[e1]->(m:player{name:"Kyle Anderson"})-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)-[e1]->(m:player{name:"Kyle Anderson"})-[e2]->(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                       | l             |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+    When executing query:
+      """
+      MATCH (n)-[e1]->(m:player{name:"Kyle Anderson"})<-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+    When executing query:
+      """
+      MATCH (n)<-[e1]-(m:player{name:"Kyle Anderson"})-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n             | e1                                       | m                 | e2                                            | l                   |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)<-[e1]-(m:player{name:"Kyle Anderson"})-[e2]->(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n             | e1                                       | m                 | e2                                       | l             |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+    When executing query:
+      """
+      MATCH (n)<-[e1]-(m:player{name:"Kyle Anderson"})<-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n             | e1                                       | m                 | e2                                            | l                   |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+
+  Scenario: start from middle node, with prop index, with totally 3 steps
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 141   |
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      WHERE k.name == "Marc Gasol"
+      RETURN n, m, l, k
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l             | k              |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies") | ("Marc Gasol") |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies") | ("Marc Gasol") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies") | ("Marc Gasol") |
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      WHERE k.name == "Marc Gasol"
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                                       |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")<-[:serve@0]-("Marc Gasol")> |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")<-[:serve@0]-("Marc Gasol")> |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")-[:serve@0]->("Grizzlies")<-[:serve@0]-("Marc Gasol")>          |
+    When executing query:
+      """
+      MATCH p = ()-[e1]-(m:player{name:"Kyle Anderson"})-[e2]-()-[e3]-(k)
+      WHERE k.name == "Marc Gasol"
+      RETURN e1, e2, e3
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                            | e2                                       | e3                                    |
+      | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | [:serve "Kyle Anderson"->"Grizzlies" @0] | [:serve "Grizzlies"<-"Marc Gasol" @0] |
+      | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | [:serve "Kyle Anderson"->"Grizzlies" @0] | [:serve "Grizzlies"<-"Marc Gasol" @0] |
+      | [:serve "Kyle Anderson"->"Spurs" @0]          | [:serve "Kyle Anderson"->"Grizzlies" @0] | [:serve "Grizzlies"<-"Marc Gasol" @0] |
+    When executing query:
+      """
+      MATCH p = (k)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 46    |
+    When executing query:
+      """
+      MATCH p = (k)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)
+      WHERE l.name == "Lakers"
+      RETURN k, n, m, l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | k                | n                 | m               | l          |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Vince Carter") | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Yao Ming")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Rudy Gay")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Magic")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Raptors")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Rockets")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Spurs")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Bucks")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Bulls")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Grizzlies")    | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Lakers")       | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Spurs")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+    When executing query:
+      """
+      MATCH p = (k)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)
+      WHERE l.name == "Lakers"
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                                 |
+      | <("Grant Hill")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>   |
+      | <("Vince Carter")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")> |
+      | <("Yao Ming")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Grant Hill")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>   |
+      | <("Rudy Gay")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Magic")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>       |
+      | <("Raptors")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Rockets")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Spurs")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>       |
+      | <("Marc Gasol")-[:like@0]->("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>      |
+      | <("Marc Gasol")<-[:like@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>      |
+      | <("Bucks")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>          |
+      | <("Bulls")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>          |
+      | <("Grizzlies")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>      |
+      | <("Lakers")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>         |
+      | <("Spurs")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>          |
+    When executing query:
+      """
+      MATCH ()-[e1]-()-[e2]-(:player{name:"Kobe Bryant"})-[e3]-(l)
+      WHERE l.name == "Lakers"
+      RETURN e1, e2, e3
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                         | e2                                        | e3                                  |
+      | [:like "Tracy McGrady"<-"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"<-"Vince Carter" @0] | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"<-"Yao Ming" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"->"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"->"Rudy Gay" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Magic" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Raptors" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Rockets" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Spurs" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Paul Gasol"<-"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Paul Gasol"->"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Bucks" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Bulls" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Grizzlies" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Lakers" @0]         | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Spurs" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+
+  Scenario: start from middle node, with prop index, with totally 4 steps
+    When executing query:
+      """
+      MATCH p = ()-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)-[]-(k)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 348   |
+    When executing query:
+      """
+      MATCH p = ()-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)-[]-(k)
+      WHERE k.name == "Paul Gasol"
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                                                            |
+      | <("Grant Hill")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>   |
+      | <("Vince Carter")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")> |
+      | <("Yao Ming")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Grant Hill")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>   |
+      | <("Rudy Gay")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Magic")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>       |
+      | <("Raptors")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Rockets")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Spurs")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>       |
+      | <("Marc Gasol")-[:like@0]->("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>      |
+      | <("Marc Gasol")<-[:like@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>      |
+      | <("Bucks")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>          |
+      | <("Bulls")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>          |
+      | <("Grizzlies")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol" )>     |
+      | <("Spurs")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>          |
+    When executing query:
+      """
+      MATCH (i)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)-[]-(k)
+      WHERE k.name == "Paul Gasol"
+      RETURN i, n, m, l, k
+      """
+    Then the result should be, in any order, with relax comparison:
+      | i                | n                 | m               | l          | k              |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Vince Carter") | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Yao Ming")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Rudy Gay")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Magic")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Raptors")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Rockets")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Spurs")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Bucks")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Bulls")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Grizzlies")    | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Spurs")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+    When executing query:
+      """
+      MATCH ()-[e1]-()-[e2]-(:player{name:"Kobe Bryant"})-[e3]-()-[e4]-(k)
+      WHERE k.name == "Paul Gasol"
+      RETURN e1, e2, e3, e4
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                         | e2                                        | e3                                  | e4                                 |
+      | [:like "Tracy McGrady"<-"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"<-"Vince Carter" @0] | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"<-"Yao Ming" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"->"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"->"Rudy Gay" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Magic" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Raptors" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Rockets" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Spurs" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Paul Gasol"<-"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Paul Gasol"->"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Bucks" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Bulls" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Grizzlies" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Spurs" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+
+  Scenario: start from end node, with prop index, with totally 1 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})
+      RETURN n, m
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 |
+      | ("Tony Parker")     | ("Kyle Anderson") |
+      | ("Dejounte Murray") | ("Kyle Anderson") |
+      | ("Grizzlies")       | ("Kyle Anderson") |
+      | ("Spurs")           | ("Kyle Anderson") |
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 |
+      | ("Tony Parker")     | ("Kyle Anderson") |
+      | ("Dejounte Murray") | ("Kyle Anderson") |
+      | ("Grizzlies")       | ("Kyle Anderson") |
+      | ("Spurs")           | ("Kyle Anderson") |
+
+  Scenario: start from end node, with prop index, with totally 2 steps
+    When executing query:
+      """
+      MATCH p = (l)-[]-(n)-[]-(m:player{name:"Stephen Curry"})
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                              |
+      | <("Warriors")<-[:serve@0]-("Klay Thompson")-[:like@0]->("Stephen Curry")>      |
+      | <("Amar'e Stoudemire")-[:like@0]->("Steve Nash")-[:like@0]->("Stephen Curry")> |
+      | <("Dirk Nowitzki")-[:like@0]->("Steve Nash")-[:like@0]->("Stephen Curry")>     |
+      | <("Jason Kidd")-[:like@0]->("Steve Nash")-[:like@0]->("Stephen Curry")>        |
+      | <("Amar'e Stoudemire")<-[:like@0]-("Steve Nash")-[:like@0]->("Stephen Curry")> |
+      | <("Dirk Nowitzki")<-[:like@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>     |
+      | <("Jason Kidd")<-[:like@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>        |
+      | <("Lakers")<-[:serve@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>           |
+      | <("Mavericks")<-[:serve@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>        |
+      | <("Suns")<-[:serve@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>             |
+      | <("Suns")<-[:serve@1]-("Steve Nash")-[:like@0]->("Stephen Curry")>             |
+      | <("David West")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>        |
+      | <("JaVale McGee")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>      |
+      | <("Kevin Durant")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>      |
+      | <("Klay Thompson")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>     |
+      | <("Marco Belinelli")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>   |
+    When executing query:
+      """
+      MATCH (l)-[]-(n)-[]-(m:player{name:"Stephen Curry"})
+      RETURN l, n, m
+      """
+    Then the result should be, in any order, with relax comparison:
+      | l                     | n                 | m                 |
+      | ("Warriors")          | ("Klay Thompson") | ("Stephen Curry") |
+      | ("Amar'e Stoudemire") | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Dirk Nowitzki")     | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Jason Kidd")        | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Amar'e Stoudemire") | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Dirk Nowitzki")     | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Jason Kidd")        | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Lakers")            | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Mavericks")         | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Suns")              | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Suns")              | ("Steve Nash")    | ("Stephen Curry") |
+      | ("David West")        | ("Warriors")      | ("Stephen Curry") |
+      | ("JaVale McGee")      | ("Warriors")      | ("Stephen Curry") |
+      | ("Kevin Durant")      | ("Warriors")      | ("Stephen Curry") |
+      | ("Klay Thompson")     | ("Warriors")      | ("Stephen Curry") |
+      | ("Marco Belinelli")   | ("Warriors")      | ("Stephen Curry") |
+    When executing query:
+      """
+      MATCH ()-[e1]-()-[e2]-(:player{name:"Stephen Curry"})
+      RETURN e1, e2
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                           | e2                                          |
+      | [:serve "Klay Thompson"->"Warriors" @0]      | [:like "Stephen Curry"<-"Klay Thompson" @0] |
+      | [:like "Steve Nash"<-"Amar'e Stoudemire" @0] | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"<-"Dirk Nowitzki" @0]     | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"<-"Jason Kidd" @0]        | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"->"Amar'e Stoudemire" @0] | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"->"Dirk Nowitzki" @0]     | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"->"Jason Kidd" @0]        | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Lakers" @0]           | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Mavericks" @0]        | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Suns" @0]             | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Suns" @1]             | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Warriors"<-"David West" @0]         | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"JaVale McGee" @0]       | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"Kevin Durant" @0]       | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"Klay Thompson" @0]      | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"Marco Belinelli" @0]    | [:serve "Stephen Curry"->"Warriors" @0]     |
+
+  Scenario: start from middle node, with prop index, with upto 3 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})-[*1..2]-(l)
+      RETURN n,m,l
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 153   |
+
+  Scenario: start from middle node, with prop index, with upto 4 steps
+    When executing query:
+      """
+      MATCH (n)-[*1..2]-(m:player{name:"Kyle Anderson"})-[*1..2]-(l)
+      RETURN n,m,l
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 1846  |
+    When executing query:
+      """
+      MATCH p = (n)-[*1..2]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 1693  |
+
+  @skip
+  Scenario: start from middle node, with vertex id, with totally 2 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m)-[]-(l)
+      WHERE id(m)=="Kyle Anderson"
+      RETURN n,m,l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l                   |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Spurs")           | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Spurs")           |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Spurs")           |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Spurs")           |
diff --git a/tests/tck/features/match/StartFromAnyNode.feature b/tests/tck/features/match/StartFromAnyNode.feature
new file mode 100644
index 0000000000000000000000000000000000000000..725f20e6ec915ba743e5947c9b1b59766888a004
--- /dev/null
+++ b/tests/tck/features/match/StartFromAnyNode.feature
@@ -0,0 +1,533 @@
+# 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.
+Feature: Start From Any Node
+
+  Background:
+    Given a graph with space named "nba"
+
+  Scenario: start from middle node, with prop index, with totally 2 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)
+      RETURN n,m,l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l                   |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Spurs")           | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Spurs")           |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Spurs")           |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player)-[]-(l)
+      WHERE m.name=="Kyle Anderson"
+      RETURN n,m,l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l                   |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Spurs")           | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Spurs")           |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Spurs")           |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Spurs")           |
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                 |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")<-[:teammate@0]-("Tony Parker")> |
+      | <("Grizzlies")<-[:serve@0]-("Kyle Anderson")<-[:teammate@0]-("Tony Parker")>      |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")<-[:teammate@0]-("Tony Parker")>          |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")<-[:like@0]-("Dejounte Murray")> |
+      | <("Grizzlies")<-[:serve@0]-("Kyle Anderson")<-[:like@0]-("Dejounte Murray")>      |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")<-[:like@0]-("Dejounte Murray")>          |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")>      |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")>      |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")-[:serve@0]->("Grizzlies")>               |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")-[:serve@0]->("Spurs")>          |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")-[:serve@0]->("Spurs")>          |
+      | <("Grizzlies")<-[:serve@0]-("Kyle Anderson")-[:serve@0]->("Spurs")>               |
+    When executing query:
+      """
+      MATCH (n)-[e1]-(m:player{name:"Kyle Anderson"})-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)-[e1]-(m:player{name:"Kyle Anderson"})-[e2]->(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                       | l             |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+    When executing query:
+      """
+      MATCH (n)-[e1]-(m:player{name:"Kyle Anderson"})<-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Grizzlies")       | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")           | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+    When executing query:
+      """
+      MATCH (n)-[e1]->(m:player{name:"Kyle Anderson"})-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)-[e1]->(m:player{name:"Kyle Anderson"})-[e2]->(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                       | l             |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+    When executing query:
+      """
+      MATCH (n)-[e1]->(m:player{name:"Kyle Anderson"})<-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | e1                                            | m                 | e2                                            | l                   |
+      | ("Dejounte Murray") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Tony Parker")     | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+    When executing query:
+      """
+      MATCH (n)<-[e1]-(m:player{name:"Kyle Anderson"})-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n             | e1                                       | m                 | e2                                            | l                   |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0]      | ("Grizzlies")       |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]          | ("Spurs")           |
+    When executing query:
+      """
+      MATCH (n)<-[e1]-(m:player{name:"Kyle Anderson"})-[e2]->(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n             | e1                                       | m                 | e2                                       | l             |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Grizzlies") |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Spurs")     |
+    When executing query:
+      """
+      MATCH (n)<-[e1]-(m:player{name:"Kyle Anderson"})<-[e2]-(l)
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n             | e1                                       | m                 | e2                                            | l                   |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | ("Tony Parker")     |
+      | ("Grizzlies") | [:serve "Kyle Anderson"->"Grizzlies" @0] | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+      | ("Spurs")     | [:serve "Kyle Anderson"->"Spurs" @0]     | ("Kyle Anderson") | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | ("Dejounte Murray") |
+
+  Scenario: start from middle node, with prop index, with totally 3 steps
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 141   |
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      WHERE k.name == "Marc Gasol"
+      RETURN n, m, l, k
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l             | k              |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies") | ("Marc Gasol") |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies") | ("Marc Gasol") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies") | ("Marc Gasol") |
+    When executing query:
+      """
+      MATCH p = (n)-[]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      WHERE k.name == "Marc Gasol"
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                                       |
+      | <("Tony Parker")-[:teammate@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")<-[:serve@0]-("Marc Gasol")> |
+      | <("Dejounte Murray")-[:like@0]->("Kyle Anderson")-[:serve@0]->("Grizzlies")<-[:serve@0]-("Marc Gasol")> |
+      | <("Spurs")<-[:serve@0]-("Kyle Anderson")-[:serve@0]->("Grizzlies")<-[:serve@0]-("Marc Gasol")>          |
+    When executing query:
+      """
+      MATCH p = ()-[e1]-(m:player{name:"Kyle Anderson"})-[e2]-()-[e3]-(k)
+      WHERE k.name == "Marc Gasol"
+      RETURN e1, e2, e3
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                            | e2                                       | e3                                    |
+      | [:teammate "Kyle Anderson"<-"Tony Parker" @0] | [:serve "Kyle Anderson"->"Grizzlies" @0] | [:serve "Grizzlies"<-"Marc Gasol" @0] |
+      | [:like "Kyle Anderson"<-"Dejounte Murray" @0] | [:serve "Kyle Anderson"->"Grizzlies" @0] | [:serve "Grizzlies"<-"Marc Gasol" @0] |
+      | [:serve "Kyle Anderson"->"Spurs" @0]          | [:serve "Kyle Anderson"->"Grizzlies" @0] | [:serve "Grizzlies"<-"Marc Gasol" @0] |
+    When executing query:
+      """
+      MATCH p = (k)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 46    |
+    When executing query:
+      """
+      MATCH p = (k)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)
+      WHERE l.name == "Lakers"
+      RETURN k, n, m, l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | k                | n                 | m               | l          |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Vince Carter") | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Yao Ming")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Rudy Gay")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Magic")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Raptors")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Rockets")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Spurs")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Bucks")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Bulls")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Grizzlies")    | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Lakers")       | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+      | ("Spurs")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") |
+    When executing query:
+      """
+      MATCH p = (k)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)
+      WHERE l.name == "Lakers"
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                                 |
+      | <("Grant Hill")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>   |
+      | <("Vince Carter")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")> |
+      | <("Yao Ming")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Grant Hill")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>   |
+      | <("Rudy Gay")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Magic")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>       |
+      | <("Raptors")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Rockets")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>     |
+      | <("Spurs")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>       |
+      | <("Marc Gasol")-[:like@0]->("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>      |
+      | <("Marc Gasol")<-[:like@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>      |
+      | <("Bucks")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>          |
+      | <("Bulls")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>          |
+      | <("Grizzlies")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>      |
+      | <("Lakers")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>         |
+      | <("Spurs")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")>          |
+    When executing query:
+      """
+      MATCH ()-[e1]-()-[e2]-(:player{name:"Kobe Bryant"})-[e3]-(l)
+      WHERE l.name == "Lakers"
+      RETURN e1, e2, e3
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                         | e2                                        | e3                                  |
+      | [:like "Tracy McGrady"<-"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"<-"Vince Carter" @0] | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"<-"Yao Ming" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"->"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Tracy McGrady"->"Rudy Gay" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Magic" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Raptors" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Rockets" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Tracy McGrady"->"Spurs" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Paul Gasol"<-"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:like "Paul Gasol"->"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Bucks" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Bulls" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Grizzlies" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Lakers" @0]         | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+      | [:serve "Paul Gasol"->"Spurs" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] |
+
+  Scenario: start from middle node, with prop index, with totally 4 steps
+    When executing query:
+      """
+      MATCH p = ()-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)-[]-(k)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 348   |
+    When executing query:
+      """
+      MATCH p = ()-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)-[]-(k)
+      WHERE k.name == "Paul Gasol"
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                                                                            |
+      | <("Grant Hill")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>   |
+      | <("Vince Carter")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")> |
+      | <("Yao Ming")-[:like@0]->("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Grant Hill")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>   |
+      | <("Rudy Gay")<-[:like@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Magic")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>       |
+      | <("Raptors")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Rockets")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>     |
+      | <("Spurs")<-[:serve@0]-("Tracy McGrady")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>       |
+      | <("Marc Gasol")-[:like@0]->("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>      |
+      | <("Marc Gasol")<-[:like@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>      |
+      | <("Bucks")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>          |
+      | <("Bulls")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>          |
+      | <("Grizzlies")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol" )>     |
+      | <("Spurs")<-[:serve@0]-("Paul Gasol")-[:like@0]->("Kobe Bryant")-[:serve@0]->("Lakers")<-[:serve@0]-("Paul Gasol")>          |
+    When executing query:
+      """
+      MATCH (i)-[]-(n)-[]-(m:player{name:"Kobe Bryant"})-[]-(l)-[]-(k)
+      WHERE k.name == "Paul Gasol"
+      RETURN i, n, m, l, k
+      """
+    Then the result should be, in any order, with relax comparison:
+      | i                | n                 | m               | l          | k              |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Vince Carter") | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Yao Ming")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Grant Hill")   | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Rudy Gay")     | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Magic")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Raptors")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Rockets")      | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Spurs")        | ("Tracy McGrady") | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Marc Gasol")   | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Bucks")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Bulls")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Grizzlies")    | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+      | ("Spurs")        | ("Paul Gasol")    | ("Kobe Bryant") | ("Lakers") | ("Paul Gasol") |
+    When executing query:
+      """
+      MATCH ()-[e1]-()-[e2]-(:player{name:"Kobe Bryant"})-[e3]-()-[e4]-(k)
+      WHERE k.name == "Paul Gasol"
+      RETURN e1, e2, e3, e4
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                         | e2                                        | e3                                  | e4                                 |
+      | [:like "Tracy McGrady"<-"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"<-"Vince Carter" @0] | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"<-"Yao Ming" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"->"Grant Hill" @0]   | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Tracy McGrady"->"Rudy Gay" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Magic" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Raptors" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Rockets" @0]     | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Tracy McGrady"->"Spurs" @0]       | [:like "Kobe Bryant"<-"Tracy McGrady" @0] | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Paul Gasol"<-"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:like "Paul Gasol"->"Marc Gasol" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Bucks" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Bulls" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Grizzlies" @0]      | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+      | [:serve "Paul Gasol"->"Spurs" @0]          | [:like "Kobe Bryant"<-"Paul Gasol" @0]    | [:serve "Kobe Bryant"->"Lakers" @0] | [:serve "Lakers"<-"Paul Gasol" @0] |
+
+  Scenario: start from end node, with prop index, with totally 1 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})
+      RETURN n, m
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 |
+      | ("Tony Parker")     | ("Kyle Anderson") |
+      | ("Dejounte Murray") | ("Kyle Anderson") |
+      | ("Grizzlies")       | ("Kyle Anderson") |
+      | ("Spurs")           | ("Kyle Anderson") |
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})
+      RETURN *
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 |
+      | ("Tony Parker")     | ("Kyle Anderson") |
+      | ("Dejounte Murray") | ("Kyle Anderson") |
+      | ("Grizzlies")       | ("Kyle Anderson") |
+      | ("Spurs")           | ("Kyle Anderson") |
+
+  Scenario: start from end node, with prop index, with totally 2 steps
+    When executing query:
+      """
+      MATCH p = (l)-[]-(n)-[]-(m:player{name:"Stephen Curry"})
+      RETURN p
+      """
+    Then the result should be, in any order, with relax comparison:
+      | p                                                                              |
+      | <("Warriors")<-[:serve@0]-("Klay Thompson")-[:like@0]->("Stephen Curry")>      |
+      | <("Amar'e Stoudemire")-[:like@0]->("Steve Nash")-[:like@0]->("Stephen Curry")> |
+      | <("Dirk Nowitzki")-[:like@0]->("Steve Nash")-[:like@0]->("Stephen Curry")>     |
+      | <("Jason Kidd")-[:like@0]->("Steve Nash")-[:like@0]->("Stephen Curry")>        |
+      | <("Amar'e Stoudemire")<-[:like@0]-("Steve Nash")-[:like@0]->("Stephen Curry")> |
+      | <("Dirk Nowitzki")<-[:like@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>     |
+      | <("Jason Kidd")<-[:like@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>        |
+      | <("Lakers")<-[:serve@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>           |
+      | <("Mavericks")<-[:serve@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>        |
+      | <("Suns")<-[:serve@0]-("Steve Nash")-[:like@0]->("Stephen Curry")>             |
+      | <("Suns")<-[:serve@1]-("Steve Nash")-[:like@0]->("Stephen Curry")>             |
+      | <("David West")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>        |
+      | <("JaVale McGee")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>      |
+      | <("Kevin Durant")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>      |
+      | <("Klay Thompson")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>     |
+      | <("Marco Belinelli")-[:serve@0]->("Warriors")<-[:serve@0]-("Stephen Curry")>   |
+    When executing query:
+      """
+      MATCH (l)-[]-(n)-[]-(m:player{name:"Stephen Curry"})
+      RETURN l, n, m
+      """
+    Then the result should be, in any order, with relax comparison:
+      | l                     | n                 | m                 |
+      | ("Warriors")          | ("Klay Thompson") | ("Stephen Curry") |
+      | ("Amar'e Stoudemire") | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Dirk Nowitzki")     | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Jason Kidd")        | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Amar'e Stoudemire") | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Dirk Nowitzki")     | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Jason Kidd")        | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Lakers")            | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Mavericks")         | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Suns")              | ("Steve Nash")    | ("Stephen Curry") |
+      | ("Suns")              | ("Steve Nash")    | ("Stephen Curry") |
+      | ("David West")        | ("Warriors")      | ("Stephen Curry") |
+      | ("JaVale McGee")      | ("Warriors")      | ("Stephen Curry") |
+      | ("Kevin Durant")      | ("Warriors")      | ("Stephen Curry") |
+      | ("Klay Thompson")     | ("Warriors")      | ("Stephen Curry") |
+      | ("Marco Belinelli")   | ("Warriors")      | ("Stephen Curry") |
+    When executing query:
+      """
+      MATCH ()-[e1]-()-[e2]-(:player{name:"Stephen Curry"})
+      RETURN e1, e2
+      """
+    Then the result should be, in any order, with relax comparison:
+      | e1                                           | e2                                          |
+      | [:serve "Klay Thompson"->"Warriors" @0]      | [:like "Stephen Curry"<-"Klay Thompson" @0] |
+      | [:like "Steve Nash"<-"Amar'e Stoudemire" @0] | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"<-"Dirk Nowitzki" @0]     | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"<-"Jason Kidd" @0]        | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"->"Amar'e Stoudemire" @0] | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"->"Dirk Nowitzki" @0]     | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:like "Steve Nash"->"Jason Kidd" @0]        | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Lakers" @0]           | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Mavericks" @0]        | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Suns" @0]             | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Steve Nash"->"Suns" @1]             | [:like "Stephen Curry"<-"Steve Nash" @0]    |
+      | [:serve "Warriors"<-"David West" @0]         | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"JaVale McGee" @0]       | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"Kevin Durant" @0]       | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"Klay Thompson" @0]      | [:serve "Stephen Curry"->"Warriors" @0]     |
+      | [:serve "Warriors"<-"Marco Belinelli" @0]    | [:serve "Stephen Curry"->"Warriors" @0]     |
+
+  Scenario: start from middle node, with prop index, with upto 3 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m:player{name:"Kyle Anderson"})-[*1..2]-(l)
+      RETURN n,m,l
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 153   |
+
+  Scenario: start from middle node, with prop index, with upto 4 steps
+    When executing query:
+      """
+      MATCH (n)-[*1..2]-(m:player{name:"Kyle Anderson"})-[*1..2]-(l)
+      RETURN n,m,l
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 1846  |
+    When executing query:
+      """
+      MATCH p = (n)-[*1..2]-(m:player{name:"Kyle Anderson"})-[]-(l)-[]-(k)
+      RETURN p
+      | YIELD count(*) AS count
+      """
+    Then the result should be, in any order, with relax comparison:
+      | count |
+      | 1693  |
+
+  @skip
+  Scenario: start from middle node, with vertex id, with totally 2 steps
+    When executing query:
+      """
+      MATCH (n)-[]-(m)-[]-(l)
+      WHERE id(m)=="Kyle Anderson"
+      RETURN n,m,l
+      """
+    Then the result should be, in any order, with relax comparison:
+      | n                   | m                 | l                   |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Spurs")           | ("Kyle Anderson") | ("Tony Parker")     |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Spurs")           | ("Kyle Anderson") | ("Dejounte Murray") |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Spurs")           | ("Kyle Anderson") | ("Grizzlies")       |
+      | ("Tony Parker")     | ("Kyle Anderson") | ("Spurs")           |
+      | ("Dejounte Murray") | ("Kyle Anderson") | ("Spurs")           |
+      | ("Grizzlies")       | ("Kyle Anderson") | ("Spurs")           |