From 49d4110eb566108b9d51755d546259e097c3fd81 Mon Sep 17 00:00:00 2001 From: yixinglu <2520865+yixinglu@users.noreply.github.com> Date: Sat, 3 Dec 2022 10:35:28 +0800 Subject: [PATCH 1/2] Cleanup match planner implementation --- src/graph/context/ast/CypherAstContext.h | 14 +- .../planner/match/MatchClausePlanner.cpp | 51 ++--- src/graph/planner/match/MatchPathPlanner.cpp | 210 +++++------------- src/graph/planner/match/MatchPathPlanner.h | 75 ++----- src/graph/planner/match/MatchPlanner.cpp | 28 ++- src/graph/planner/match/MatchSolver.cpp | 6 +- src/graph/planner/match/MatchSolver.h | 2 +- src/graph/planner/match/SegmentsConnector.cpp | 46 ++-- src/graph/planner/match/SegmentsConnector.h | 32 +-- .../planner/match/ShortestPathPlanner.cpp | 48 ++-- src/graph/planner/match/ShortestPathPlanner.h | 14 +- .../planner/match/UnwindClausePlanner.cpp | 22 +- .../planner/match/WhereClausePlanner.cpp | 16 +- .../planner/match/YieldClausePlanner.cpp | 20 +- src/graph/planner/plan/ExecutionPlan.cpp | 9 + src/graph/planner/plan/ExecutionPlan.h | 4 + 16 files changed, 231 insertions(+), 366 deletions(-) diff --git a/src/graph/context/ast/CypherAstContext.h b/src/graph/context/ast/CypherAstContext.h index df785b41958..eeb0857d5b0 100644 --- a/src/graph/context/ast/CypherAstContext.h +++ b/src/graph/context/ast/CypherAstContext.h @@ -95,6 +95,8 @@ struct CypherClauseContextBase : AstContext { // Input column names of current clause // Now used by unwind clause planner std::vector inputColNames; + + std::unordered_map aliasesAvailable; }; struct WhereClauseContext final : CypherClauseContextBase { @@ -104,7 +106,6 @@ struct WhereClauseContext final : CypherClauseContextBase { std::vector paths; Expression* filter{nullptr}; - std::unordered_map aliasesAvailable; }; struct OrderByClauseContext final : CypherClauseContextBase { @@ -134,7 +135,6 @@ struct YieldClauseContext final : CypherClauseContextBase { bool distinct{false}; const YieldColumns* yieldColumns{nullptr}; - std::unordered_map aliasesAvailable; bool hasAgg_{false}; bool needGenProject_{false}; @@ -169,7 +169,6 @@ struct MatchClauseContext final : CypherClauseContextBase { bool isOptional{false}; std::vector paths; std::unique_ptr where; - std::unordered_map aliasesAvailable; std::unordered_map aliasesGenerated; }; @@ -182,7 +181,6 @@ struct UnwindClauseContext final : CypherClauseContextBase { Expression* unwindExpr{nullptr}; std::string alias; - std::unordered_map aliasesAvailable; std::unordered_map aliasesGenerated; }; @@ -209,13 +207,13 @@ struct PatternContext { }; struct NodeContext final : PatternContext { - NodeContext(QueryContext* q, WhereClauseContext* b, GraphSpaceID g, NodeInfo* i) + NodeContext(QueryContext* q, WhereClauseContext* b, GraphSpaceID g, const NodeInfo* i) : PatternContext(PatternKind::kNode), qctx(q), bindWhereClause(b), spaceId(g), info(i) {} QueryContext* qctx; WhereClauseContext* bindWhereClause; GraphSpaceID spaceId; - NodeInfo* info; + const NodeInfo* info; std::unordered_set* nodeAliasesAvailable{nullptr}; // Output fields @@ -226,13 +224,13 @@ struct NodeContext final : PatternContext { }; struct EdgeContext final : PatternContext { - EdgeContext(QueryContext* q, WhereClauseContext* b, GraphSpaceID g, EdgeInfo* i) + EdgeContext(QueryContext* q, WhereClauseContext* b, GraphSpaceID g, const EdgeInfo* i) : PatternContext(PatternKind::kEdge), qctx(q), bindWhereClause(b), spaceId(g), info(i) {} QueryContext* qctx; WhereClauseContext* bindWhereClause; GraphSpaceID spaceId; - EdgeInfo* info; + const EdgeInfo* info; // Output fields ScanInfo scanInfo; diff --git a/src/graph/planner/match/MatchClausePlanner.cpp b/src/graph/planner/match/MatchClausePlanner.cpp index 544ee69e1f1..0bc9f1ac8bd 100644 --- a/src/graph/planner/match/MatchClausePlanner.cpp +++ b/src/graph/planner/match/MatchClausePlanner.cpp @@ -29,23 +29,13 @@ StatusOr MatchClausePlanner::transform(CypherClauseContextBase* clauseC auto& nodeInfos = iter->nodeInfos; SubPlan pathPlan; if (iter->pathType == Path::PathType::kDefault) { - MatchPathPlanner matchPathPlanner; - auto result = matchPathPlanner.transform(matchClauseCtx->qctx, - matchClauseCtx->space.id, - matchClauseCtx->where.get(), - matchClauseCtx->aliasesAvailable, - nodeAliasesSeen, - *iter); + MatchPathPlanner matchPathPlanner(matchClauseCtx, *iter); + auto result = matchPathPlanner.transform(matchClauseCtx->where.get(), nodeAliasesSeen); NG_RETURN_IF_ERROR(result); pathPlan = std::move(result).value(); } else { - ShortestPathPlanner shortestPathPlanner; - auto result = shortestPathPlanner.transform(matchClauseCtx->qctx, - matchClauseCtx->space.id, - matchClauseCtx->where.get(), - matchClauseCtx->aliasesAvailable, - nodeAliasesSeen, - *iter); + ShortestPathPlanner shortestPathPlanner(matchClauseCtx, *iter); + auto result = shortestPathPlanner.transform(matchClauseCtx->where.get(), nodeAliasesSeen); NG_RETURN_IF_ERROR(result); pathPlan = std::move(result).value(); } @@ -61,29 +51,30 @@ Status MatchClausePlanner::connectPathPlan(const std::vector& nodeInfo std::unordered_set& nodeAliasesSeen, SubPlan& matchClausePlan) { std::unordered_set intersectedAliases; - std::for_each( - nodeInfos.begin(), nodeInfos.end(), [&intersectedAliases, &nodeAliasesSeen](auto& info) { - if (nodeAliasesSeen.find(info.alias) != nodeAliasesSeen.end()) { - intersectedAliases.emplace(info.alias); - } - }); - std::for_each(nodeInfos.begin(), nodeInfos.end(), [&nodeAliasesSeen](auto& info) { + for (auto& info : nodeInfos) { + if (nodeAliasesSeen.find(info.alias) != nodeAliasesSeen.end()) { + intersectedAliases.emplace(info.alias); + } if (!info.anonymous) { nodeAliasesSeen.emplace(info.alias); } - }); + } + if (matchClausePlan.root == nullptr) { matchClausePlan = subplan; + return Status::OK(); + } + + StatusOr status; + if (intersectedAliases.empty()) { + status = SegmentsConnector::cartesianProduct(matchClauseCtx->qctx, matchClausePlan, subplan); } else { - if (intersectedAliases.empty()) { - matchClausePlan = - SegmentsConnector::cartesianProduct(matchClauseCtx->qctx, matchClausePlan, subplan); - } else { - // TODO: Actually a natural join would be much easy use. - matchClausePlan = SegmentsConnector::innerJoin( - matchClauseCtx->qctx, matchClausePlan, subplan, intersectedAliases); - } + // TODO: Actually a natural join would be much easy use. + status = SegmentsConnector::innerJoin( + matchClauseCtx->qctx, matchClausePlan, subplan, intersectedAliases); } + NG_RETURN_IF_ERROR(status); + matchClausePlan = std::move(status).value(); return Status::OK(); } diff --git a/src/graph/planner/match/MatchPathPlanner.cpp b/src/graph/planner/match/MatchPathPlanner.cpp index 3c534cb6eb4..088d39d1d50 100644 --- a/src/graph/planner/match/MatchPathPlanner.cpp +++ b/src/graph/planner/match/MatchPathPlanner.cpp @@ -19,6 +19,10 @@ namespace nebula { namespace graph { + +MatchPathPlanner::MatchPathPlanner(CypherClauseContextBase* ctx, const Path& path) + : ctx_(DCHECK_NOTNULL(ctx)), path_(path) {} + static std::vector genTraverseColNames(const std::vector& inputCols, const NodeInfo& node, const EdgeInfo& edge, @@ -62,73 +66,44 @@ static Expression* nodeId(ObjectPool* pool, const NodeInfo& node) { pool, InputPropertyExpression::make(pool, node.alias), ConstantExpression::make(pool, kVid)); } -StatusOr MatchPathPlanner::transform( - QueryContext* qctx, - GraphSpaceID spaceId, - WhereClauseContext* bindWhere, - const std::unordered_map& aliasesAvailable, - std::unordered_set nodeAliasesSeen, - Path& path) { +StatusOr MatchPathPlanner::transform(WhereClauseContext* bindWhere, + std::unordered_set nodeAliasesSeen) { // All nodes ever seen in current match clause // TODO: Maybe it is better to rebuild the graph and find all connected components. - auto& nodeInfos = path.nodeInfos; - auto& edgeInfos = path.edgeInfos; SubPlan subplan; size_t startIndex = 0; bool startFromEdge = false; - // The node alias seen in current pattern only - std::unordered_set nodeAliasesSeenInPattern; - - NG_RETURN_IF_ERROR(findStarts(nodeInfos, - edgeInfos, - qctx, - spaceId, - bindWhere, - aliasesAvailable, - nodeAliasesSeen, - startFromEdge, - startIndex, - subplan)); - NG_RETURN_IF_ERROR(expand(nodeInfos, - edgeInfos, - qctx, - spaceId, - startFromEdge, - startIndex, - subplan, - nodeAliasesSeenInPattern)); - - MatchSolver::buildProjectColumns(qctx, path, subplan); + + NG_RETURN_IF_ERROR(findStarts(bindWhere, nodeAliasesSeen, startFromEdge, startIndex, subplan)); + NG_RETURN_IF_ERROR(expand(startFromEdge, startIndex, subplan)); + + MatchSolver::buildProjectColumns(ctx_->qctx, path_, subplan); return subplan; } -Status MatchPathPlanner::findStarts( - std::vector& nodeInfos, - std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - WhereClauseContext* bindWhereClause, - const std::unordered_map& aliasesAvailable, - std::unordered_set nodeAliasesSeen, - bool& startFromEdge, - size_t& startIndex, - SubPlan& matchClausePlan) { +Status MatchPathPlanner::findStarts(WhereClauseContext* bindWhereClause, + std::unordered_set nodeAliasesSeen, + bool& startFromEdge, + size_t& startIndex, + SubPlan& matchClausePlan) { auto& startVidFinders = StartVidFinder::finders(); bool foundStart = false; - std::unordered_set allNodeAliasesAvailable; - allNodeAliasesAvailable.merge(nodeAliasesSeen); std::for_each( - aliasesAvailable.begin(), aliasesAvailable.end(), [&allNodeAliasesAvailable](auto& kv) { + ctx_->aliasesAvailable.begin(), ctx_->aliasesAvailable.end(), [&nodeAliasesSeen](auto& kv) { // if (kv.second == AliasType::kNode) { - allNodeAliasesAvailable.emplace(kv.first); + nodeAliasesSeen.emplace(kv.first); // } }); + auto spaceId = ctx_->space.id; + auto* qctx = ctx_->qctx; + const auto& nodeInfos = path_.nodeInfos; + const auto& edgeInfos = path_.edgeInfos; // Find the start plan node for (auto& finder : startVidFinders) { for (size_t i = 0; i < nodeInfos.size() && !foundStart; ++i) { - auto nodeCtx = NodeContext(qctx, bindWhereClause, spaceId, &nodeInfos[i]); - nodeCtx.nodeAliasesAvailable = &allNodeAliasesAvailable; + NodeContext nodeCtx(qctx, bindWhereClause, spaceId, &nodeInfos[i]); + nodeCtx.nodeAliasesAvailable = &nodeAliasesSeen; auto nodeFinder = finder(); if (nodeFinder->match(&nodeCtx)) { auto plan = nodeFinder->transform(&nodeCtx); @@ -144,7 +119,7 @@ Status MatchPathPlanner::findStarts( } if (i != nodeInfos.size() - 1) { - auto edgeCtx = EdgeContext(qctx, bindWhereClause, spaceId, &edgeInfos[i]); + EdgeContext edgeCtx(qctx, bindWhereClause, spaceId, &edgeInfos[i]); auto edgeFinder = finder(); if (edgeFinder->match(&edgeCtx)) { auto plan = edgeFinder->transform(&edgeCtx); @@ -166,100 +141,62 @@ Status MatchPathPlanner::findStarts( return Status::SemanticError("Can't solve the start vids from the sentence."); } - // Both StartNode and Argument are leaf plannodes - if (matchClausePlan.tail->isSingleInput() && - matchClausePlan.tail->kind() != PlanNode::Kind::kArgument) { - auto start = StartNode::make(qctx); - matchClausePlan.tail->setDep(0, start); - matchClausePlan.tail = start; - } + // Both StartNode and Argument are leaf plan nodes + matchClausePlan.appendStartNode(qctx); return Status::OK(); } -Status MatchPathPlanner::expand(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - bool startFromEdge, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern) { +Status MatchPathPlanner::expand(bool startFromEdge, size_t startIndex, SubPlan& subplan) { if (startFromEdge) { - return expandFromEdge( - nodeInfos, edgeInfos, qctx, spaceId, startIndex, subplan, nodeAliasesSeenInPattern); + return expandFromEdge(startIndex, subplan); } else { - return expandFromNode( - nodeInfos, edgeInfos, qctx, spaceId, startIndex, subplan, nodeAliasesSeenInPattern); + return expandFromNode(startIndex, subplan); } } -Status MatchPathPlanner::expandFromNode(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern) { +Status MatchPathPlanner::expandFromNode(size_t startIndex, SubPlan& subplan) { + const auto& nodeInfos = path_.nodeInfos; + DCHECK_LT(startIndex, nodeInfos.size()); // Vid of the start node is known already - nodeAliasesSeenInPattern.emplace(nodeInfos[startIndex].alias); - DCHECK(!nodeInfos.empty() && startIndex < nodeInfos.size()); + nodeAliasesSeenInPattern_.emplace(nodeInfos[startIndex].alias); if (startIndex == 0) { // Pattern: (start)-[]-...-() - return rightExpandFromNode( - nodeInfos, edgeInfos, qctx, spaceId, startIndex, subplan, nodeAliasesSeenInPattern); + return rightExpandFromNode(startIndex, subplan); } - const auto& var = subplan.root->outputVar(); if (startIndex == nodeInfos.size() - 1) { // Pattern: ()-[]-...-(start) - return leftExpandFromNode( - nodeInfos, edgeInfos, qctx, spaceId, startIndex, var, subplan, nodeAliasesSeenInPattern); + return leftExpandFromNode(startIndex, subplan); } // Pattern: ()-[]-...-(start)-...-[]-() - NG_RETURN_IF_ERROR(rightExpandFromNode( - nodeInfos, edgeInfos, qctx, spaceId, startIndex, subplan, nodeAliasesSeenInPattern)); - NG_RETURN_IF_ERROR(leftExpandFromNode(nodeInfos, - edgeInfos, - qctx, - spaceId, - startIndex, - subplan.root->outputVar(), - subplan, - nodeAliasesSeenInPattern)); + NG_RETURN_IF_ERROR(rightExpandFromNode(startIndex, subplan)); + NG_RETURN_IF_ERROR(leftExpandFromNode(startIndex, subplan)); return Status::OK(); } -Status MatchPathPlanner::leftExpandFromNode( - const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - std::string inputVar, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern) { +Status MatchPathPlanner::leftExpandFromNode(size_t startIndex, SubPlan& subplan) { + const auto& nodeInfos = path_.nodeInfos; + const auto& edgeInfos = path_.edgeInfos; Expression* nextTraverseStart = nullptr; if (startIndex == nodeInfos.size() - 1) { nextTraverseStart = initialExpr_; } else { - auto* pool = qctx->objPool(); + auto* pool = ctx_->qctx->objPool(); auto args = ArgumentList::make(pool); args->addArgument(InputPropertyExpression::make(pool, nodeInfos[startIndex].alias)); nextTraverseStart = FunctionCallExpression::make(pool, "_joinkey", args); } bool reversely = true; + auto qctx = ctx_->qctx; + auto spaceId = ctx_->space.id; for (size_t i = startIndex; i > 0; --i) { auto& node = nodeInfos[i]; auto& dst = nodeInfos[i - 1]; - - if (!node.anonymous) { - nodeAliasesSeenInPattern.emplace(node.alias); - } - bool expandInto = nodeAliasesSeenInPattern.find(dst.alias) != nodeAliasesSeenInPattern.end(); - + addNodeAlias(node); + bool expandInto = isExpandInto(dst.alias); auto& edge = edgeInfos[i - 1]; auto traverse = Traverse::make(qctx, subplan.root, spaceId); traverse->setSrc(nextTraverseStart); @@ -274,15 +211,11 @@ Status MatchPathPlanner::leftExpandFromNode( traverse->setDedup(); // If start from end of the path pattern, the first traverse would not // track the previous path, otherwise, it should. - traverse->setTrackPrevPath(startIndex + 1 == nodeInfos.size() ? i != startIndex : true); - traverse->setColNames( - genTraverseColNames(subplan.root->colNames(), - node, - edge, - startIndex + 1 == nodeInfos.size() ? i != startIndex : true)); + bool trackPrevPath = (startIndex + 1 == nodeInfos.size() ? i != startIndex : true); + traverse->setTrackPrevPath(trackPrevPath); + traverse->setColNames(genTraverseColNames(subplan.root->colNames(), node, edge, trackPrevPath)); subplan.root = traverse; nextTraverseStart = genNextTraverseStart(qctx->objPool(), edge); - inputVar = traverse->outputVar(); if (expandInto) { // TODO(shylock) optimize to embed filter to Traverse auto* startVid = nodeId(qctx->objPool(), dst); @@ -290,15 +223,12 @@ Status MatchPathPlanner::leftExpandFromNode( auto* filterExpr = RelationalExpression::makeEQ(qctx->objPool(), startVid, endVid); auto* filter = Filter::make(qctx, traverse, filterExpr, false); subplan.root = filter; - inputVar = filter->outputVar(); } } auto& lastNode = nodeInfos.front(); - bool duppedLastAlias = - nodeAliasesSeenInPattern.find(lastNode.alias) != nodeAliasesSeenInPattern.end() && - nodeAliasesSeenInPattern.size() > 1; + bool duppedLastAlias = isExpandInto(lastNode.alias) && nodeAliasesSeenInPattern_.size() > 1; // If the the last alias has been presented in the pattern, we could emit the AppendVertices node // because the same alias always presents in the same entity. if (duppedLastAlias) { @@ -319,25 +249,19 @@ Status MatchPathPlanner::leftExpandFromNode( return Status::OK(); } -Status MatchPathPlanner::rightExpandFromNode( - const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern) { - auto inputVar = subplan.root->outputVar(); +Status MatchPathPlanner::rightExpandFromNode(size_t startIndex, SubPlan& subplan) { + const auto& nodeInfos = path_.nodeInfos; + const auto& edgeInfos = path_.edgeInfos; Expression* nextTraverseStart = initialExpr_; bool reversely = false; + auto qctx = ctx_->qctx; + auto spaceId = ctx_->space.id; for (size_t i = startIndex; i < edgeInfos.size(); ++i) { auto& node = nodeInfos[i]; auto& dst = nodeInfos[i + 1]; - if (!node.anonymous) { - nodeAliasesSeenInPattern.emplace(node.alias); - } - bool expandInto = nodeAliasesSeenInPattern.find(dst.alias) != nodeAliasesSeenInPattern.end(); + addNodeAlias(node); + bool expandInto = isExpandInto(dst.alias); auto& edge = edgeInfos[i]; auto traverse = Traverse::make(qctx, subplan.root, spaceId); @@ -362,19 +286,14 @@ Status MatchPathPlanner::rightExpandFromNode( auto* filterExpr = RelationalExpression::makeEQ(qctx->objPool(), startVid, endVid); auto* filter = Filter::make(qctx, traverse, filterExpr, false); subplan.root = filter; - inputVar = filter->outputVar(); } } auto& lastNode = nodeInfos.back(); - bool duppedLastAlias = - nodeAliasesSeenInPattern.find(lastNode.alias) != nodeAliasesSeenInPattern.end() && - nodeAliasesSeenInPattern.size() > 1; + bool duppedLastAlias = isExpandInto(lastNode.alias) && nodeAliasesSeenInPattern_.size() > 1; - if (!lastNode.anonymous) { - nodeAliasesSeenInPattern.emplace(lastNode.alias); - } + addNodeAlias(lastNode); // If the the last alias has been presented in the pattern, we could emit the AppendVertices node // because the same alias always presents in the same entity. @@ -396,15 +315,8 @@ Status MatchPathPlanner::rightExpandFromNode( return Status::OK(); } -Status MatchPathPlanner::expandFromEdge(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern) { - return expandFromNode( - nodeInfos, edgeInfos, qctx, spaceId, startIndex, subplan, nodeAliasesSeenInPattern); +Status MatchPathPlanner::expandFromEdge(size_t startIndex, SubPlan& subplan) { + return expandFromNode(startIndex, subplan); } } // namespace graph diff --git a/src/graph/planner/match/MatchPathPlanner.h b/src/graph/planner/match/MatchPathPlanner.h index 7a812f8b6e5..f30433cbf41 100644 --- a/src/graph/planner/match/MatchPathPlanner.h +++ b/src/graph/planner/match/MatchPathPlanner.h @@ -8,74 +8,45 @@ namespace nebula { namespace graph { + // The MatchPathPlanner generates plan for match clause; class MatchPathPlanner final { public: - MatchPathPlanner() = default; + MatchPathPlanner(CypherClauseContextBase* ctx, const Path& path); - StatusOr transform(QueryContext* qctx, - GraphSpaceID spaceId, - WhereClauseContext* bindWhereClause, - const std::unordered_map& aliasesAvailable, - std::unordered_set nodeAliasesSeen, - Path& path); + StatusOr transform(WhereClauseContext* bindWhereClause, + std::unordered_set nodeAliasesSeen = {}); private: - Status findStarts(std::vector& nodeInfos, - std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - WhereClauseContext* bindWhereClause, - const std::unordered_map& aliasesAvailable, + Status findStarts(WhereClauseContext* bindWhereClause, std::unordered_set nodeAliases, bool& startFromEdge, size_t& startIndex, SubPlan& matchClausePlan); - Status expand(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - bool startFromEdge, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern); - - Status expandFromNode(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern); + Status expand(bool startFromEdge, size_t startIndex, SubPlan& subplan); + Status expandFromNode(size_t startIndex, SubPlan& subplan); + Status leftExpandFromNode(size_t startIndex, SubPlan& subplan); + Status rightExpandFromNode(size_t startIndex, SubPlan& subplan); + Status expandFromEdge(size_t startIndex, SubPlan& subplan); - Status leftExpandFromNode(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - std::string inputVar, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern); + void addNodeAlias(const NodeInfo& n) { + if (!n.anonymous) { + nodeAliasesSeenInPattern_.emplace(n.alias); + } + } - Status rightExpandFromNode(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern); - - Status expandFromEdge(const std::vector& nodeInfos, - const std::vector& edgeInfos, - QueryContext* qctx, - GraphSpaceID spaceId, - size_t startIndex, - SubPlan& subplan, - std::unordered_set& nodeAliasesSeenInPattern); + bool isExpandInto(const std::string& alias) const { + return nodeAliasesSeenInPattern_.find(alias) != nodeAliasesSeenInPattern_.end(); + } private: + CypherClauseContextBase* ctx_{nullptr}; Expression* initialExpr_{nullptr}; + const Path& path_; + + // The node alias seen in current pattern only + std::unordered_set nodeAliasesSeenInPattern_; }; } // namespace graph } // namespace nebula diff --git a/src/graph/planner/match/MatchPlanner.cpp b/src/graph/planner/match/MatchPlanner.cpp index 474d68fac5c..74bf2345019 100644 --- a/src/graph/planner/match/MatchPlanner.cpp +++ b/src/graph/planner/match/MatchPlanner.cpp @@ -68,7 +68,7 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma queryPlan = matchPlan; return Status::OK(); } - std::unordered_set intersectedAliases; + std::unordered_set interAliases; for (auto& alias : matchCtx->aliasesGenerated) { auto it = matchCtx->aliasesAvailable.find(alias.first); if (it != matchCtx->aliasesAvailable.end()) { @@ -81,22 +81,23 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma } // Joined On EdgeList is not supported if (alias.second == AliasType::kEdgeList) { - return Status::SemanticError(alias.first + - " defined with type EdgeList, which cannot be joined on"); + return Status::SemanticError("`%s' defined with type EdgeList, which cannot be joined on", + alias.first.c_str()); } - intersectedAliases.insert(alias.first); + interAliases.insert(alias.first); } } - if (!intersectedAliases.empty()) { + if (!interAliases.empty()) { if (matchPlan.tail->kind() == PlanNode::Kind::kArgument) { // The input of the argument operator is always the output of the plan on the other side of // the join matchPlan.tail->setInputVar(queryPlan.root->outputVar()); } + StatusOr status; if (matchCtx->isOptional) { // connect LeftJoin match filter auto& whereCtx = matchCtx->where; - if (whereCtx.get() != nullptr && whereCtx->filter != nullptr) { + if (whereCtx && whereCtx->filter) { auto exprs = ExpressionUtils::collectAll( whereCtx->filter, {Expression::Kind::kVarProperty, Expression::Kind::kLabel}); @@ -119,18 +120,17 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma "other statements is not supported yet."); } whereCtx->inputColNames = matchPlan.root->colNames(); - auto wherePlanStatus = - std::make_unique()->transform(matchCtx->where.get()); + auto wherePlanStatus = WhereClausePlanner().transform(matchCtx->where.get()); NG_RETURN_IF_ERROR(wherePlanStatus); auto wherePlan = std::move(wherePlanStatus).value(); matchPlan = SegmentsConnector::addInput(wherePlan, matchPlan, true); } - queryPlan = - SegmentsConnector::leftJoin(matchCtx->qctx, queryPlan, matchPlan, intersectedAliases); + status = SegmentsConnector::leftJoin(matchCtx->qctx, queryPlan, matchPlan, interAliases); } else { - queryPlan = - SegmentsConnector::innerJoin(matchCtx->qctx, queryPlan, matchPlan, intersectedAliases); + status = SegmentsConnector::innerJoin(matchCtx->qctx, queryPlan, matchPlan, interAliases); } + NG_RETURN_IF_ERROR(status); + queryPlan = std::move(status).value(); } else { queryPlan.root = BiCartesianProduct::make(matchCtx->qctx, queryPlan.root, matchPlan.root); } @@ -172,10 +172,8 @@ Status MatchPlanner::genQueryPartPlan(QueryContext* qctx, if (queryPlan.tail->isSingleInput()) { queryPlan.tail->setInputVar(qctx->vctx()->anonVarGen()->getVar()); if (!tailConnected_) { - auto start = StartNode::make(qctx); - queryPlan.tail->setDep(0, start); tailConnected_ = true; - queryPlan.tail = start; + queryPlan.appendStartNode(qctx); } } VLOG(1) << queryPlan; diff --git a/src/graph/planner/match/MatchSolver.cpp b/src/graph/planner/match/MatchSolver.cpp index f89512d62d8..af09284e934 100644 --- a/src/graph/planner/match/MatchSolver.cpp +++ b/src/graph/planner/match/MatchSolver.cpp @@ -249,11 +249,11 @@ static YieldColumn* buildEdgeColumn(QueryContext* qctx, const EdgeInfo& edge) { } // static -void MatchSolver::buildProjectColumns(QueryContext* qctx, Path& path, SubPlan& plan) { +void MatchSolver::buildProjectColumns(QueryContext* qctx, const Path& path, SubPlan& plan) { auto columns = qctx->objPool()->makeAndAdd(); std::vector colNames; - auto& nodeInfos = path.nodeInfos; - auto& edgeInfos = path.edgeInfos; + const auto& nodeInfos = path.nodeInfos; + const auto& edgeInfos = path.edgeInfos; auto addNode = [columns, &colNames, qctx](auto& nodeInfo) { if (!nodeInfo.alias.empty() && !nodeInfo.anonymous) { diff --git a/src/graph/planner/match/MatchSolver.h b/src/graph/planner/match/MatchSolver.h index 4a619e77c04..d9fad556778 100644 --- a/src/graph/planner/match/MatchSolver.h +++ b/src/graph/planner/match/MatchSolver.h @@ -49,7 +49,7 @@ class MatchSolver final { QueryContext* qctx); // Build yield columns for match & shortestPath statement - static void buildProjectColumns(QueryContext* qctx, Path& path, SubPlan& plan); + static void buildProjectColumns(QueryContext* qctx, const Path& path, SubPlan& plan); }; } // namespace graph diff --git a/src/graph/planner/match/SegmentsConnector.cpp b/src/graph/planner/match/SegmentsConnector.cpp index 77be56ef241..f66dcb7b8ac 100644 --- a/src/graph/planner/match/SegmentsConnector.cpp +++ b/src/graph/planner/match/SegmentsConnector.cpp @@ -11,10 +11,11 @@ namespace nebula { namespace graph { -SubPlan SegmentsConnector::innerJoin(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases) { +StatusOr SegmentsConnector::innerJoin( + QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases) { SubPlan newPlan = left; auto innerJoin = BiInnerJoin::make(qctx, left.root, right.root); std::vector hashKeys; @@ -34,10 +35,11 @@ SubPlan SegmentsConnector::innerJoin(QueryContext* qctx, return newPlan; } -SubPlan SegmentsConnector::leftJoin(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases) { +StatusOr SegmentsConnector::leftJoin( + QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases) { SubPlan newPlan = left; auto leftJoin = BiLeftJoin::make(qctx, left.root, right.root); std::vector hashKeys; @@ -57,31 +59,35 @@ SubPlan SegmentsConnector::leftJoin(QueryContext* qctx, return newPlan; } -SubPlan SegmentsConnector::cartesianProduct(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right) { +StatusOr SegmentsConnector::cartesianProduct(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right) { SubPlan newPlan = left; - newPlan.root = BiCartesianProduct::make(qctx, left.root, right.root); + auto* prod = BiCartesianProduct::make(qctx, left.root, right.root); + newPlan.root = prod; return newPlan; } -/*static*/ SubPlan SegmentsConnector::rollUpApply(QueryContext* qctx, - const SubPlan& left, - const std::vector& inputColNames, - const SubPlan& right, - const std::vector& compareCols, - const std::string& collectCol) { +/*static*/ +StatusOr SegmentsConnector::rollUpApply(CypherClauseContextBase* ctx, + const SubPlan& left, + const SubPlan& right, + const graph::Path& path) { + const std::string& collectCol = path.collectVariable; + auto* qctx = ctx->qctx; + SubPlan newPlan = left; std::vector compareProps; - for (const auto& col : compareCols) { + for (const auto& col : path.compareVariables) { compareProps.emplace_back(FunctionCallExpression::make( qctx->objPool(), "id", {InputPropertyExpression::make(qctx->objPool(), col)})); } InputPropertyExpression* collectProp = InputPropertyExpression::make(qctx->objPool(), collectCol); auto* rollUpApply = RollUpApply::make( qctx, left.root, DCHECK_NOTNULL(right.root), std::move(compareProps), collectProp); + // Left side input may be nullptr, which will be filled in later - std::vector colNames = left.root != nullptr ? left.root->colNames() : inputColNames; + std::vector colNames = left.root ? left.root->colNames() : ctx->inputColNames; colNames.emplace_back(collectCol); rollUpApply->setColNames(std::move(colNames)); newPlan.root = rollUpApply; diff --git a/src/graph/planner/match/SegmentsConnector.h b/src/graph/planner/match/SegmentsConnector.h index 20d9ed15fbf..68baa4ee02a 100644 --- a/src/graph/planner/match/SegmentsConnector.h +++ b/src/graph/planner/match/SegmentsConnector.h @@ -21,30 +21,30 @@ class SegmentsConnector final { /** * InnerJoin two plan on node id */ - static SubPlan innerJoin(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases); + static StatusOr innerJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases); /** * LeftJoin two plan on node id */ - static SubPlan leftJoin(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases); + static StatusOr leftJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases); /** * Simply do a CartesianProduct of two plan root. */ - static SubPlan cartesianProduct(QueryContext* qctx, const SubPlan& left, const SubPlan& right); - - static SubPlan rollUpApply(QueryContext* qctx, - const SubPlan& left, - const std::vector& inputColNames, - const SubPlan& right, - const std::vector& compareCols, - const std::string& collectCol); + static StatusOr cartesianProduct(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right); + + static StatusOr rollUpApply(CypherClauseContextBase* ctx, + const SubPlan& left, + const SubPlan& right, + const graph::Path& path); /* * left->right diff --git a/src/graph/planner/match/ShortestPathPlanner.cpp b/src/graph/planner/match/ShortestPathPlanner.cpp index 090305e2518..394ee46b553 100644 --- a/src/graph/planner/match/ShortestPathPlanner.cpp +++ b/src/graph/planner/match/ShortestPathPlanner.cpp @@ -14,6 +14,10 @@ namespace nebula { namespace graph { + +ShortestPathPlanner::ShortestPathPlanner(CypherClauseContextBase* ctx, const Path& path) + : ctx_(DCHECK_NOTNULL(ctx)), path_(path) {} + // The plan looks like this: // +--------+---------+ +---------+--------+ // | Start | | Start | @@ -40,27 +44,18 @@ namespace graph { // +--------+---------+ // | Project | // +--------+---------+ - -StatusOr ShortestPathPlanner::transform( - QueryContext* qctx, - GraphSpaceID spaceId, - WhereClauseContext* bindWhereClause, - const std::unordered_map& aliasesAvailable, - std::unordered_set nodeAliasesSeen, - Path& path) { - std::unordered_set allNodeAliasesAvailable; - allNodeAliasesAvailable.merge(nodeAliasesSeen); - std::for_each( - aliasesAvailable.begin(), aliasesAvailable.end(), [&allNodeAliasesAvailable](auto& kv) { - if (kv.second == AliasType::kNode) { - allNodeAliasesAvailable.emplace(kv.first); - } - }); +StatusOr ShortestPathPlanner::transform(WhereClauseContext* bindWhereClause, + std::unordered_set nodeAliasesSeen) { + for (auto& kv : ctx_->aliasesAvailable) { + if (kv.second == AliasType::kNode) { + nodeAliasesSeen.emplace(kv.first); + } + } SubPlan subplan; - bool singleShortest = path.pathType == Path::PathType::kSingleShortest; - auto& nodeInfos = path.nodeInfos; - auto& edge = path.edgeInfos.front(); + bool singleShortest = path_.pathType == Path::PathType::kSingleShortest; + auto& nodeInfos = path_.nodeInfos; + auto& edge = path_.edgeInfos.front(); std::vector colNames; colNames.emplace_back(nodeInfos.front().alias); colNames.emplace_back(edge.alias); @@ -69,22 +64,19 @@ StatusOr ShortestPathPlanner::transform( auto& startVidFinders = StartVidFinder::finders(); std::vector plans; + auto qctx = ctx_->qctx; + auto spaceId = ctx_->space.id; for (auto& nodeInfo : nodeInfos) { bool foundIndex = false; for (auto& finder : startVidFinders) { auto nodeCtx = NodeContext(qctx, bindWhereClause, spaceId, &nodeInfo); - nodeCtx.nodeAliasesAvailable = &allNodeAliasesAvailable; + nodeCtx.nodeAliasesAvailable = &nodeAliasesSeen; auto nodeFinder = finder(); if (nodeFinder->match(&nodeCtx)) { auto status = nodeFinder->transform(&nodeCtx); NG_RETURN_IF_ERROR(status); - auto plan = status.value(); - if (plan.tail->kind() != PlanNode::Kind::kStart && - plan.tail->kind() != PlanNode::Kind::kArgument) { - auto start = StartNode::make(qctx); - plan.tail->setDep(0, start); - plan.tail = start; - } + auto plan = std::move(status).value(); + plan.appendStartNode(qctx); auto initExpr = nodeCtx.initialExpr->clone(); auto columns = qctx->objPool()->makeAndAdd(); @@ -118,7 +110,7 @@ StatusOr ShortestPathPlanner::transform( subplan.root = shortestPath; subplan.tail = leftPlan.tail; - MatchSolver::buildProjectColumns(qctx, path, subplan); + MatchSolver::buildProjectColumns(qctx, path_, subplan); return subplan; } diff --git a/src/graph/planner/match/ShortestPathPlanner.h b/src/graph/planner/match/ShortestPathPlanner.h index 718bbb12781..f08dbf5dbad 100644 --- a/src/graph/planner/match/ShortestPathPlanner.h +++ b/src/graph/planner/match/ShortestPathPlanner.h @@ -12,14 +12,14 @@ namespace nebula { namespace graph { class ShortestPathPlanner final { public: - ShortestPathPlanner() = default; + ShortestPathPlanner(CypherClauseContextBase* ctx, const Path& path); - StatusOr transform(QueryContext* qctx, - GraphSpaceID spaceId, - WhereClauseContext* bindWhereClause, - const std::unordered_map& aliasesAvailable, - std::unordered_set nodeAliasesSeen, - Path& path); + StatusOr transform(WhereClauseContext* bindWhereClause, + std::unordered_set nodeAliasesSeen = {}); + + private: + CypherClauseContextBase* ctx_{nullptr}; + const Path& path_; }; } // namespace graph } // namespace nebula diff --git a/src/graph/planner/match/UnwindClausePlanner.cpp b/src/graph/planner/match/UnwindClausePlanner.cpp index 790cf710f3c..621e59ed08a 100644 --- a/src/graph/planner/match/UnwindClausePlanner.cpp +++ b/src/graph/planner/match/UnwindClausePlanner.cpp @@ -26,22 +26,14 @@ StatusOr UnwindClausePlanner::transform(CypherClauseContextBase* clause SubPlan subPlan; // Build plan for pattern from expression + StatusOr status; for (auto& path : unwindClauseCtx->paths) { - auto pathPlan = - std::make_unique()->transform(unwindClauseCtx->qctx, - unwindClauseCtx->space.id, - nullptr, - unwindClauseCtx->aliasesAvailable, - {}, - path); - NG_RETURN_IF_ERROR(pathPlan); - auto pathplan = std::move(pathPlan).value(); - subPlan = SegmentsConnector::rollUpApply(unwindClauseCtx->qctx, - subPlan, - unwindClauseCtx->inputColNames, - pathplan, - path.compareVariables, - path.collectVariable); + status = MatchPathPlanner(unwindClauseCtx, path).transform(nullptr, {}); + NG_RETURN_IF_ERROR(status); + status = + SegmentsConnector::rollUpApply(unwindClauseCtx, subPlan, std::move(status).value(), path); + NG_RETURN_IF_ERROR(status); + subPlan = std::move(status).value(); } if (subPlan.root != nullptr) { diff --git a/src/graph/planner/match/WhereClausePlanner.cpp b/src/graph/planner/match/WhereClausePlanner.cpp index 50b6b4daa34..89ea5803753 100644 --- a/src/graph/planner/match/WhereClausePlanner.cpp +++ b/src/graph/planner/match/WhereClausePlanner.cpp @@ -26,18 +26,14 @@ StatusOr WhereClausePlanner::transform(CypherClauseContextBase* ctx) { wherePlan.tail = wherePlan.root; SubPlan subPlan; + StatusOr status; // Build plan for pattern from expression for (auto& path : wctx->paths) { - auto pathPlan = std::make_unique()->transform( - wctx->qctx, wctx->space.id, nullptr, wctx->aliasesAvailable, {}, path); - NG_RETURN_IF_ERROR(pathPlan); - auto pathplan = std::move(pathPlan).value(); - subPlan = SegmentsConnector::rollUpApply(wctx->qctx, - subPlan, - wctx->inputColNames, - pathplan, - path.compareVariables, - path.collectVariable); + status = MatchPathPlanner(wctx, path).transform(nullptr, {}); + NG_RETURN_IF_ERROR(status); + status = SegmentsConnector::rollUpApply(wctx, subPlan, std::move(status).value(), path); + NG_RETURN_IF_ERROR(status); + subPlan = std::move(status).value(); } if (subPlan.root != nullptr) { wherePlan = SegmentsConnector::addInput(wherePlan, subPlan, true); diff --git a/src/graph/planner/match/YieldClausePlanner.cpp b/src/graph/planner/match/YieldClausePlanner.cpp index 1c3f1df33c6..81b30667528 100644 --- a/src/graph/planner/match/YieldClausePlanner.cpp +++ b/src/graph/planner/match/YieldClausePlanner.cpp @@ -28,8 +28,8 @@ void YieldClausePlanner::rewriteYieldColumns(const YieldClauseContext* yctx, const YieldColumns* yields, YieldColumns* newYields) { for (auto* col : yields->columns()) { - newYields->addColumn( - new YieldColumn(MatchSolver::doRewrite(yctx->qctx, yctx->aliasesAvailable, col->expr()))); + auto* expr = MatchSolver::doRewrite(yctx->qctx, yctx->aliasesAvailable, col->expr()); + newYields->addColumn(new YieldColumn(expr, col->alias())); } } @@ -76,18 +76,14 @@ Status YieldClausePlanner::buildYield(YieldClauseContext* yctx, SubPlan& subplan subplan.root = Dedup::make(yctx->qctx, subplan.root); } SubPlan patternPlan; + StatusOr status; // Build plan for pattern from expression for (auto& path : yctx->paths) { - auto pathPlan = std::make_unique()->transform( - yctx->qctx, yctx->space.id, nullptr, yctx->aliasesAvailable, {}, path); - NG_RETURN_IF_ERROR(pathPlan); - auto pathplan = std::move(pathPlan).value(); - patternPlan = SegmentsConnector::rollUpApply(yctx->qctx, - patternPlan, - yctx->inputColNames, - pathplan, - path.compareVariables, - path.collectVariable); + status = MatchPathPlanner(yctx, path).transform(nullptr, {}); + NG_RETURN_IF_ERROR(status); + status = SegmentsConnector::rollUpApply(yctx, patternPlan, std::move(status).value(), path); + NG_RETURN_IF_ERROR(status); + patternPlan = std::move(status).value(); } if (patternPlan.root != nullptr) { subplan = SegmentsConnector::addInput(subplan, patternPlan); diff --git a/src/graph/planner/plan/ExecutionPlan.cpp b/src/graph/planner/plan/ExecutionPlan.cpp index 6981782bf87..fae439b258e 100644 --- a/src/graph/planner/plan/ExecutionPlan.cpp +++ b/src/graph/planner/plan/ExecutionPlan.cpp @@ -15,6 +15,15 @@ namespace nebula { namespace graph { +void SubPlan::appendStartNode(QueryContext* qctx) { + if (tail->isSingleInput() && tail->kind() != PlanNode::Kind::kStart && + tail->kind() != PlanNode::Kind::kArgument) { + auto* start = StartNode::make(qctx); + tail->setDep(0, start); + tail = start; + } +} + ExecutionPlan::ExecutionPlan(PlanNode* root) : id_(EPIdGenerator::instance().id()), root_(root) {} ExecutionPlan::~ExecutionPlan() {} diff --git a/src/graph/planner/plan/ExecutionPlan.h b/src/graph/planner/plan/ExecutionPlan.h index 469a7ed4b89..65630beaf22 100644 --- a/src/graph/planner/plan/ExecutionPlan.h +++ b/src/graph/planner/plan/ExecutionPlan.h @@ -15,12 +15,16 @@ struct PlanDescription; struct PlanNodeDescription; namespace graph { + class PlanNode; +class QueryContext; struct SubPlan { // root and tail of a subplan. PlanNode* root{nullptr}; PlanNode* tail{nullptr}; + + void appendStartNode(QueryContext* qctx); }; // An ExecutionPlan is a Directed Cyclic Graph which composed by PlanNodes. From ae20e8443c101a9ccd4ea9f9566a1190c28370ea Mon Sep 17 00:00:00 2001 From: yixinglu <2520865+yixinglu@users.noreply.github.com> Date: Sat, 3 Dec 2022 10:48:24 +0800 Subject: [PATCH 2/2] Restore segment connector return type --- .../planner/match/MatchClausePlanner.cpp | 8 ++--- src/graph/planner/match/MatchPlanner.cpp | 7 ++-- src/graph/planner/match/SegmentsConnector.cpp | 35 +++++++++---------- src/graph/planner/match/SegmentsConnector.h | 30 ++++++++-------- .../planner/match/UnwindClausePlanner.cpp | 7 ++-- .../planner/match/WhereClausePlanner.cpp | 7 ++-- .../planner/match/YieldClausePlanner.cpp | 8 ++--- 7 files changed, 42 insertions(+), 60 deletions(-) diff --git a/src/graph/planner/match/MatchClausePlanner.cpp b/src/graph/planner/match/MatchClausePlanner.cpp index 0bc9f1ac8bd..99ad2ab1cab 100644 --- a/src/graph/planner/match/MatchClausePlanner.cpp +++ b/src/graph/planner/match/MatchClausePlanner.cpp @@ -65,16 +65,14 @@ Status MatchClausePlanner::connectPathPlan(const std::vector& nodeInfo return Status::OK(); } - StatusOr status; if (intersectedAliases.empty()) { - status = SegmentsConnector::cartesianProduct(matchClauseCtx->qctx, matchClausePlan, subplan); + matchClausePlan = + SegmentsConnector::cartesianProduct(matchClauseCtx->qctx, matchClausePlan, subplan); } else { // TODO: Actually a natural join would be much easy use. - status = SegmentsConnector::innerJoin( + matchClausePlan = SegmentsConnector::innerJoin( matchClauseCtx->qctx, matchClausePlan, subplan, intersectedAliases); } - NG_RETURN_IF_ERROR(status); - matchClausePlan = std::move(status).value(); return Status::OK(); } diff --git a/src/graph/planner/match/MatchPlanner.cpp b/src/graph/planner/match/MatchPlanner.cpp index 74bf2345019..194553e6750 100644 --- a/src/graph/planner/match/MatchPlanner.cpp +++ b/src/graph/planner/match/MatchPlanner.cpp @@ -93,7 +93,6 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma // the join matchPlan.tail->setInputVar(queryPlan.root->outputVar()); } - StatusOr status; if (matchCtx->isOptional) { // connect LeftJoin match filter auto& whereCtx = matchCtx->where; @@ -125,12 +124,10 @@ Status MatchPlanner::connectMatchPlan(SubPlan& queryPlan, MatchClauseContext* ma auto wherePlan = std::move(wherePlanStatus).value(); matchPlan = SegmentsConnector::addInput(wherePlan, matchPlan, true); } - status = SegmentsConnector::leftJoin(matchCtx->qctx, queryPlan, matchPlan, interAliases); + queryPlan = SegmentsConnector::leftJoin(matchCtx->qctx, queryPlan, matchPlan, interAliases); } else { - status = SegmentsConnector::innerJoin(matchCtx->qctx, queryPlan, matchPlan, interAliases); + queryPlan = SegmentsConnector::innerJoin(matchCtx->qctx, queryPlan, matchPlan, interAliases); } - NG_RETURN_IF_ERROR(status); - queryPlan = std::move(status).value(); } else { queryPlan.root = BiCartesianProduct::make(matchCtx->qctx, queryPlan.root, matchPlan.root); } diff --git a/src/graph/planner/match/SegmentsConnector.cpp b/src/graph/planner/match/SegmentsConnector.cpp index f66dcb7b8ac..4cc7658f4d9 100644 --- a/src/graph/planner/match/SegmentsConnector.cpp +++ b/src/graph/planner/match/SegmentsConnector.cpp @@ -11,11 +11,10 @@ namespace nebula { namespace graph { -StatusOr SegmentsConnector::innerJoin( - QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases) { +SubPlan SegmentsConnector::innerJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases) { SubPlan newPlan = left; auto innerJoin = BiInnerJoin::make(qctx, left.root, right.root); std::vector hashKeys; @@ -35,11 +34,10 @@ StatusOr SegmentsConnector::innerJoin( return newPlan; } -StatusOr SegmentsConnector::leftJoin( - QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases) { +SubPlan SegmentsConnector::leftJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases) { SubPlan newPlan = left; auto leftJoin = BiLeftJoin::make(qctx, left.root, right.root); std::vector hashKeys; @@ -59,20 +57,19 @@ StatusOr SegmentsConnector::leftJoin( return newPlan; } -StatusOr SegmentsConnector::cartesianProduct(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right) { +SubPlan SegmentsConnector::cartesianProduct(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right) { SubPlan newPlan = left; - auto* prod = BiCartesianProduct::make(qctx, left.root, right.root); - newPlan.root = prod; + newPlan.root = BiCartesianProduct::make(qctx, left.root, right.root); return newPlan; } /*static*/ -StatusOr SegmentsConnector::rollUpApply(CypherClauseContextBase* ctx, - const SubPlan& left, - const SubPlan& right, - const graph::Path& path) { +SubPlan SegmentsConnector::rollUpApply(CypherClauseContextBase* ctx, + const SubPlan& left, + const SubPlan& right, + const graph::Path& path) { const std::string& collectCol = path.collectVariable; auto* qctx = ctx->qctx; diff --git a/src/graph/planner/match/SegmentsConnector.h b/src/graph/planner/match/SegmentsConnector.h index 68baa4ee02a..9a201f59820 100644 --- a/src/graph/planner/match/SegmentsConnector.h +++ b/src/graph/planner/match/SegmentsConnector.h @@ -21,30 +21,28 @@ class SegmentsConnector final { /** * InnerJoin two plan on node id */ - static StatusOr innerJoin(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases); + static SubPlan innerJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases); /** * LeftJoin two plan on node id */ - static StatusOr leftJoin(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right, - const std::unordered_set& intersectedAliases); + static SubPlan leftJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases); /** * Simply do a CartesianProduct of two plan root. */ - static StatusOr cartesianProduct(QueryContext* qctx, - const SubPlan& left, - const SubPlan& right); - - static StatusOr rollUpApply(CypherClauseContextBase* ctx, - const SubPlan& left, - const SubPlan& right, - const graph::Path& path); + static SubPlan cartesianProduct(QueryContext* qctx, const SubPlan& left, const SubPlan& right); + + static SubPlan rollUpApply(CypherClauseContextBase* ctx, + const SubPlan& left, + const SubPlan& right, + const graph::Path& path); /* * left->right diff --git a/src/graph/planner/match/UnwindClausePlanner.cpp b/src/graph/planner/match/UnwindClausePlanner.cpp index 621e59ed08a..0624540539b 100644 --- a/src/graph/planner/match/UnwindClausePlanner.cpp +++ b/src/graph/planner/match/UnwindClausePlanner.cpp @@ -26,14 +26,11 @@ StatusOr UnwindClausePlanner::transform(CypherClauseContextBase* clause SubPlan subPlan; // Build plan for pattern from expression - StatusOr status; for (auto& path : unwindClauseCtx->paths) { - status = MatchPathPlanner(unwindClauseCtx, path).transform(nullptr, {}); + auto status = MatchPathPlanner(unwindClauseCtx, path).transform(nullptr, {}); NG_RETURN_IF_ERROR(status); - status = + subPlan = SegmentsConnector::rollUpApply(unwindClauseCtx, subPlan, std::move(status).value(), path); - NG_RETURN_IF_ERROR(status); - subPlan = std::move(status).value(); } if (subPlan.root != nullptr) { diff --git a/src/graph/planner/match/WhereClausePlanner.cpp b/src/graph/planner/match/WhereClausePlanner.cpp index 89ea5803753..a6bf3608da0 100644 --- a/src/graph/planner/match/WhereClausePlanner.cpp +++ b/src/graph/planner/match/WhereClausePlanner.cpp @@ -26,14 +26,11 @@ StatusOr WhereClausePlanner::transform(CypherClauseContextBase* ctx) { wherePlan.tail = wherePlan.root; SubPlan subPlan; - StatusOr status; // Build plan for pattern from expression for (auto& path : wctx->paths) { - status = MatchPathPlanner(wctx, path).transform(nullptr, {}); + auto status = MatchPathPlanner(wctx, path).transform(nullptr, {}); NG_RETURN_IF_ERROR(status); - status = SegmentsConnector::rollUpApply(wctx, subPlan, std::move(status).value(), path); - NG_RETURN_IF_ERROR(status); - subPlan = std::move(status).value(); + subPlan = SegmentsConnector::rollUpApply(wctx, subPlan, std::move(status).value(), path); } if (subPlan.root != nullptr) { wherePlan = SegmentsConnector::addInput(wherePlan, subPlan, true); diff --git a/src/graph/planner/match/YieldClausePlanner.cpp b/src/graph/planner/match/YieldClausePlanner.cpp index 81b30667528..6ff7b7a8c89 100644 --- a/src/graph/planner/match/YieldClausePlanner.cpp +++ b/src/graph/planner/match/YieldClausePlanner.cpp @@ -76,14 +76,12 @@ Status YieldClausePlanner::buildYield(YieldClauseContext* yctx, SubPlan& subplan subplan.root = Dedup::make(yctx->qctx, subplan.root); } SubPlan patternPlan; - StatusOr status; // Build plan for pattern from expression for (auto& path : yctx->paths) { - status = MatchPathPlanner(yctx, path).transform(nullptr, {}); + auto status = MatchPathPlanner(yctx, path).transform(nullptr, {}); NG_RETURN_IF_ERROR(status); - status = SegmentsConnector::rollUpApply(yctx, patternPlan, std::move(status).value(), path); - NG_RETURN_IF_ERROR(status); - patternPlan = std::move(status).value(); + patternPlan = + SegmentsConnector::rollUpApply(yctx, patternPlan, std::move(status).value(), path); } if (patternPlan.root != nullptr) { subplan = SegmentsConnector::addInput(subplan, patternPlan);