From 9f8aa44fb214e2dd284ec35040a87f8ccb769248 Mon Sep 17 00:00:00 2001 From: CPWstatic <13495049+CPWstatic@users.noreply.github.com> Date: Thu, 23 Dec 2021 19:18:13 +0800 Subject: [PATCH] Refactor SegmentsConnector. --- src/graph/planner/CMakeLists.txt | 4 - .../planner/match/AddDependencyStrategy.cpp | 18 ---- .../planner/match/AddDependencyStrategy.h | 26 ----- src/graph/planner/match/AddInputStrategy.cpp | 27 ------ src/graph/planner/match/AddInputStrategy.h | 30 ------ .../match/CartesianProductStrategy.cpp | 29 ------ .../planner/match/CartesianProductStrategy.h | 30 ------ src/graph/planner/match/InnerJoinStrategy.cpp | 51 ---------- src/graph/planner/match/InnerJoinStrategy.h | 44 --------- .../planner/match/LeftOuterJoinStrategy.h | 17 ---- .../planner/match/MatchClausePlanner.cpp | 25 +---- src/graph/planner/match/MatchPlanner.cpp | 35 ++----- .../planner/match/ReturnClausePlanner.cpp | 6 +- .../planner/match/SegmentsConnectStrategy.h | 28 ------ src/graph/planner/match/SegmentsConnector.cpp | 96 +++++++++++++------ src/graph/planner/match/SegmentsConnector.h | 44 ++++----- src/graph/planner/match/UnionStrategy.h | 17 ---- src/graph/planner/match/WithClausePlanner.cpp | 9 +- 18 files changed, 100 insertions(+), 436 deletions(-) delete mode 100644 src/graph/planner/match/AddDependencyStrategy.cpp delete mode 100644 src/graph/planner/match/AddDependencyStrategy.h delete mode 100644 src/graph/planner/match/AddInputStrategy.cpp delete mode 100644 src/graph/planner/match/AddInputStrategy.h delete mode 100644 src/graph/planner/match/CartesianProductStrategy.cpp delete mode 100644 src/graph/planner/match/CartesianProductStrategy.h delete mode 100644 src/graph/planner/match/InnerJoinStrategy.cpp delete mode 100644 src/graph/planner/match/InnerJoinStrategy.h delete mode 100644 src/graph/planner/match/LeftOuterJoinStrategy.h delete mode 100644 src/graph/planner/match/SegmentsConnectStrategy.h delete mode 100644 src/graph/planner/match/UnionStrategy.h diff --git a/src/graph/planner/CMakeLists.txt b/src/graph/planner/CMakeLists.txt index 885bce6abf0..8bf193b1153 100644 --- a/src/graph/planner/CMakeLists.txt +++ b/src/graph/planner/CMakeLists.txt @@ -9,10 +9,6 @@ nebula_add_library( SequentialPlanner.cpp match/MatchSolver.cpp match/SegmentsConnector.cpp - match/InnerJoinStrategy.cpp - match/AddDependencyStrategy.cpp - match/AddInputStrategy.cpp - match/CartesianProductStrategy.cpp match/MatchPlanner.cpp match/MatchClausePlanner.cpp match/UnwindClausePlanner.cpp diff --git a/src/graph/planner/match/AddDependencyStrategy.cpp b/src/graph/planner/match/AddDependencyStrategy.cpp deleted file mode 100644 index c56e091a462..00000000000 --- a/src/graph/planner/match/AddDependencyStrategy.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include "graph/planner/match/AddDependencyStrategy.h" - -namespace nebula { -namespace graph { -PlanNode* AddDependencyStrategy::connect(const PlanNode* left, const PlanNode* right) { - auto* mutableLeft = const_cast(left); - auto* siLeft = static_cast(mutableLeft); - siLeft->dependsOn(const_cast(right)); - // siLeft->setColNames(right->colNames()); - return nullptr; -} -} // namespace graph -} // namespace nebula diff --git a/src/graph/planner/match/AddDependencyStrategy.h b/src/graph/planner/match/AddDependencyStrategy.h deleted file mode 100644 index 0e27517a966..00000000000 --- a/src/graph/planner/match/AddDependencyStrategy.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_MATCH_ADDDEPENDENCYSTRATEGY_H_ -#define GRAPH_PLANNER_MATCH_ADDDEPENDENCYSTRATEGY_H_ - -#include "graph/planner/match/SegmentsConnectStrategy.h" -#include "graph/planner/plan/PlanNode.h" - -namespace nebula { -namespace graph { -/* - * The AddDependencyStrategy was designed to connect two subplan by adding - * dependency. - */ -class AddDependencyStrategy final : public SegmentsConnectStrategy { - public: - AddDependencyStrategy() : SegmentsConnectStrategy(nullptr) {} - - PlanNode* connect(const PlanNode* left, const PlanNode* right) override; -}; -} // namespace graph -} // namespace nebula -#endif // GRAPH_PLANNER_MATCH_SIMPLECONNECTSTRATEGY_H_ diff --git a/src/graph/planner/match/AddInputStrategy.cpp b/src/graph/planner/match/AddInputStrategy.cpp deleted file mode 100644 index 1a6d6d07cd5..00000000000 --- a/src/graph/planner/match/AddInputStrategy.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include "graph/planner/match/AddInputStrategy.h" - -namespace nebula { -namespace graph { -PlanNode* AddInputStrategy::connect(const PlanNode* left, const PlanNode* right) { - DCHECK(left->isSingleInput()); - auto* mutableLeft = const_cast(left); - auto* siLeft = static_cast(mutableLeft); - siLeft->dependsOn(const_cast(right)); - siLeft->setInputVar(right->outputVar()); - if (copyColNames_) { - siLeft->setColNames(right->colNames()); - } else if (siLeft->kind() == PlanNode::Kind::kUnwind) { - // An unwind bypass all aliases, so merge the columns here - auto colNames = right->colNames(); - colNames.insert(colNames.end(), siLeft->colNames().begin(), siLeft->colNames().end()); - siLeft->setColNames(std::move(colNames)); - } - return nullptr; -} -} // namespace graph -} // namespace nebula diff --git a/src/graph/planner/match/AddInputStrategy.h b/src/graph/planner/match/AddInputStrategy.h deleted file mode 100644 index 97f54e9e8f7..00000000000 --- a/src/graph/planner/match/AddInputStrategy.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_MATCH_ADDINPUTSTRATEGY_H_ -#define GRAPH_PLANNER_MATCH_ADDINPUTSTRATEGY_H_ - -#include "graph/planner/match/SegmentsConnectStrategy.h" -#include "graph/planner/plan/PlanNode.h" - -namespace nebula { -namespace graph { -/* - * The AddInputStrategy was designed to connect two subplan by adding - * dependency. - */ -class AddInputStrategy final : public SegmentsConnectStrategy { - public: - explicit AddInputStrategy(bool copyColNames) - : SegmentsConnectStrategy(nullptr), copyColNames_(copyColNames) {} - - PlanNode* connect(const PlanNode* left, const PlanNode* right) override; - - private: - bool copyColNames_{false}; -}; -} // namespace graph -} // namespace nebula -#endif // GRAPH_PLANNER_MATCH_SIMPLECONNECTSTRATEGY_H_ diff --git a/src/graph/planner/match/CartesianProductStrategy.cpp b/src/graph/planner/match/CartesianProductStrategy.cpp deleted file mode 100644 index ecd6aae13a0..00000000000 --- a/src/graph/planner/match/CartesianProductStrategy.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include "graph/planner/match/CartesianProductStrategy.h" - -#include "graph/planner/match/MatchSolver.h" -#include "graph/planner/plan/Algo.h" -#include "graph/planner/plan/Query.h" -#include "graph/util/ExpressionUtils.h" - -namespace nebula { -namespace graph { -PlanNode* CartesianProductStrategy::connect(const PlanNode* left, const PlanNode* right) { - return joinDataSet(left, right); -} - -PlanNode* CartesianProductStrategy::joinDataSet(const PlanNode* left, const PlanNode* right) { - DCHECK(left->outputVar() != right->outputVar()); - - auto* cartesianProduct = CartesianProduct::make(qctx_, nullptr); - cartesianProduct->addVar(left->outputVar()); - cartesianProduct->addVar(right->outputVar()); - - return cartesianProduct; -} -} // namespace graph -} // namespace nebula diff --git a/src/graph/planner/match/CartesianProductStrategy.h b/src/graph/planner/match/CartesianProductStrategy.h deleted file mode 100644 index 2daa6917f25..00000000000 --- a/src/graph/planner/match/CartesianProductStrategy.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_MATCH_CARTESIANPRODUCTSTRATEGY_H_ -#define GRAPH_PLANNER_MATCH_CARTESIANPRODUCTSTRATEGY_H_ - -#include "graph/planner/match/SegmentsConnector.h" -#include "graph/planner/plan/PlanNode.h" - -namespace nebula { -namespace graph { -/* - * The CartersionProductStrategy was designed to connect two unrelated subplans - * by a CARTESIAN product. - */ - -class CartesianProductStrategy final : public SegmentsConnectStrategy { - public: - explicit CartesianProductStrategy(QueryContext* qctx) : SegmentsConnectStrategy(qctx) {} - - PlanNode* connect(const PlanNode* left, const PlanNode* right) override; - - private: - PlanNode* joinDataSet(const PlanNode* left, const PlanNode* right); -}; -} // namespace graph -} // namespace nebula -#endif // GRAPH_PLANNER_MATCH_CARTESIANPRODUCTSTRATEGY_H_ diff --git a/src/graph/planner/match/InnerJoinStrategy.cpp b/src/graph/planner/match/InnerJoinStrategy.cpp deleted file mode 100644 index b3cf005a868..00000000000 --- a/src/graph/planner/match/InnerJoinStrategy.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include "graph/planner/match/InnerJoinStrategy.h" - -#include "common/expression/AttributeExpression.h" -#include "graph/planner/match/MatchSolver.h" -#include "graph/planner/plan/Query.h" -#include "graph/util/ExpressionUtils.h" - -namespace nebula { -namespace graph { -PlanNode* InnerJoinStrategy::connect(const PlanNode* left, const PlanNode* right) { - return joinDataSet(left, right); -} - -PlanNode* InnerJoinStrategy::joinDataSet(const PlanNode* left, const PlanNode* right) { - Expression* buildExpr = nullptr; - if (leftPos_ == JoinPos::kStart) { - auto& leftKey = left->colNames().front(); - buildExpr = MatchSolver::getStartVidInPath(qctx_, leftKey); - } else { - auto& leftKey = left->colNames().back(); - buildExpr = MatchSolver::getEndVidInPath(qctx_, leftKey); - } - - Expression* probeExpr = nullptr; - if (rightPos_ == JoinPos::kStart) { - auto& rightKey = right->colNames().front(); - probeExpr = MatchSolver::getStartVidInPath(qctx_, rightKey); - } else { - auto& rightKey = right->colNames().back(); - probeExpr = MatchSolver::getEndVidInPath(qctx_, rightKey); - } - - auto join = InnerJoin::make(qctx_, - const_cast(right), - {left->outputVar(), 0}, - {right->outputVar(), 0}, - {buildExpr}, - {probeExpr}); - std::vector colNames = left->colNames(); - const auto& rightColNames = right->colNames(); - colNames.insert(colNames.end(), rightColNames.begin(), rightColNames.end()); - join->setColNames(std::move(colNames)); - return join; -} -} // namespace graph -} // namespace nebula diff --git a/src/graph/planner/match/InnerJoinStrategy.h b/src/graph/planner/match/InnerJoinStrategy.h deleted file mode 100644 index b5bd3b6104b..00000000000 --- a/src/graph/planner/match/InnerJoinStrategy.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_PLANNERS_MATCH_INNERJOINSTRATEGY_H_ -#define GRAPH_PLANNER_PLANNERS_MATCH_INNERJOINSTRATEGY_H_ - -#include "graph/planner/match/SegmentsConnectStrategy.h" -#include "graph/planner/plan/PlanNode.h" - -namespace nebula { -namespace graph { -/* - * The InnerJoinStrategy was designed to connect two expand part by an inner - * join. - */ -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 -#endif diff --git a/src/graph/planner/match/LeftOuterJoinStrategy.h b/src/graph/planner/match/LeftOuterJoinStrategy.h deleted file mode 100644 index 8eb2efee960..00000000000 --- a/src/graph/planner/match/LeftOuterJoinStrategy.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_MATCH_LEFTOUTERJOINSTRATEGY_H_ -#define GRAPH_PLANNER_MATCH_LEFTOUTERJOINSTRATEGY_H_ -namespace nebula { -namespace graph { -/* - * The LeftOuterJoinStrategy was designed to connect two expand part by left - * outer join in optional match situation. - */ -class LeftOuterJoinStrategy final {}; -} // namespace graph -} // namespace nebula -#endif // GRAPH_PLANNER_MATCH_LEFTOUTERJOINSTRATEGY_H_ diff --git a/src/graph/planner/match/MatchClausePlanner.cpp b/src/graph/planner/match/MatchClausePlanner.cpp index e71dca39c2a..39a174fcd1f 100644 --- a/src/graph/planner/match/MatchClausePlanner.cpp +++ b/src/graph/planner/match/MatchClausePlanner.cpp @@ -17,8 +17,6 @@ #include "graph/util/SchemaUtil.h" #include "graph/visitor/RewriteVisitor.h" -using JoinStrategyPos = nebula::graph::InnerJoinStrategy::JoinPos; - namespace nebula { namespace graph { static std::vector genTraverseColNames(const std::vector& inputCols, @@ -458,8 +456,7 @@ Status MatchClausePlanner::appendFilterPlan(MatchClauseContext* matchClauseCtx, auto wherePlan = std::make_unique()->transform(matchClauseCtx->where.get()); NG_RETURN_IF_ERROR(wherePlan); auto plan = std::move(wherePlan).value(); - SegmentsConnector::addInput(plan.tail, subplan.root, true); - subplan.root = plan.root; + subplan = SegmentsConnector::addInput(plan, subplan, true); VLOG(1) << subplan; return Status::OK(); } @@ -485,24 +482,12 @@ Status MatchClausePlanner::connectPathPlan(const std::vector& nodeInfo matchClausePlan = subplan; } else { if (intersectedAliases.empty()) { - matchClausePlan.root = - BiCartesianProduct::make(matchClauseCtx->qctx, matchClausePlan.root, subplan.root); + matchClausePlan = + SegmentsConnector::cartesianProduct(matchClauseCtx->qctx, matchClausePlan, subplan); } else { // TODO: Actually a natural join would be much easy use. - auto innerJoin = BiInnerJoin::make(matchClauseCtx->qctx, matchClausePlan.root, subplan.root); - std::vector hashKeys; - std::vector probeKeys; - auto pool = matchClauseCtx->qctx->objPool(); - for (auto& alias : intersectedAliases) { - auto* args = ArgumentList::make(pool); - args->addArgument(InputPropertyExpression::make(pool, alias)); - auto* expr = FunctionCallExpression::make(pool, "id", args); - hashKeys.emplace_back(expr); - probeKeys.emplace_back(expr->clone()); - } - innerJoin->setHashKeys(std::move(hashKeys)); - innerJoin->setProbeKeys(std::move(probeKeys)); - matchClausePlan.root = innerJoin; + matchClausePlan = SegmentsConnector::innerJoin( + matchClauseCtx->qctx, matchClausePlan, subplan, intersectedAliases); } } return Status::OK(); diff --git a/src/graph/planner/match/MatchPlanner.cpp b/src/graph/planner/match/MatchPlanner.cpp index 23820f80182..9bd2a22b8fa 100644 --- a/src/graph/planner/match/MatchPlanner.cpp +++ b/src/graph/planner/match/MatchPlanner.cpp @@ -78,29 +78,15 @@ void MatchPlanner::connectMatch(const MatchClauseContext* match, } if (!intersectedAliases.empty()) { - std::vector hashKeys; - std::vector probeKeys; - auto pool = match->qctx->objPool(); - for (auto& alias : intersectedAliases) { - auto* args = ArgumentList::make(pool); - args->addArgument(InputPropertyExpression::make(pool, alias)); - auto* expr = FunctionCallExpression::make(pool, "id", args); - hashKeys.emplace_back(expr); - probeKeys.emplace_back(expr->clone()); - } if (match->isOptional) { - auto leftJoin = BiLeftJoin::make(match->qctx, queryPartPlan.root, matchPlan.root); - leftJoin->setHashKeys(std::move(hashKeys)); - leftJoin->setProbeKeys(std::move(probeKeys)); - queryPartPlan.root = leftJoin; + queryPartPlan = + SegmentsConnector::leftJoin(match->qctx, queryPartPlan, matchPlan, intersectedAliases); } else { - auto innerJoin = BiInnerJoin::make(match->qctx, queryPartPlan.root, matchPlan.root); - innerJoin->setHashKeys(std::move(hashKeys)); - innerJoin->setProbeKeys(std::move(probeKeys)); - queryPartPlan.root = innerJoin; + queryPartPlan = + SegmentsConnector::innerJoin(match->qctx, queryPartPlan, matchPlan, intersectedAliases); } } else { - queryPartPlan.root = BiCartesianProduct::make(match->qctx, queryPartPlan.root, matchPlan.root); + queryPartPlan = SegmentsConnector::cartesianProduct(match->qctx, queryPartPlan, matchPlan); } } @@ -114,8 +100,7 @@ Status MatchPlanner::connectQueryParts(const QueryPart& queryPart, if (queryPlan.root == nullptr) { auto subplan = std::move(boundaryPlan).value(); if (partPlan.root != nullptr) { - SegmentsConnector::addInput(subplan.tail, partPlan.root); - subplan.tail = partPlan.tail; + subplan = SegmentsConnector::addInput(subplan, partPlan); } queryPlan = subplan; if (queryPlan.tail->isSingleInput()) { @@ -127,9 +112,7 @@ Status MatchPlanner::connectQueryParts(const QueryPart& queryPart, // Otherwise, there might only a with/unwind/return in a query part if (partPlan.root == nullptr) { auto subplan = std::move(boundaryPlan).value(); - SegmentsConnector::addInput(subplan.tail, queryPlan.root); - subplan.tail = queryPlan.tail; - queryPlan = subplan; + queryPlan = SegmentsConnector::addInput(subplan, queryPlan); return Status::OK(); } @@ -160,9 +143,7 @@ Status MatchPlanner::connectQueryParts(const QueryPart& queryPart, queryPlan.root = BiCartesianProduct::make(qctx, queryPlan.root, partPlan.root); } - SegmentsConnector::addInput(boundaryPlan.value().tail, queryPlan.root); - queryPlan.root = boundaryPlan.value().root; - + queryPlan = SegmentsConnector::addInput(boundaryPlan.value(), queryPlan); return Status::OK(); } } // namespace graph diff --git a/src/graph/planner/match/ReturnClausePlanner.cpp b/src/graph/planner/match/ReturnClausePlanner.cpp index 6a0044e63bd..43a6d838f7c 100644 --- a/src/graph/planner/match/ReturnClausePlanner.cpp +++ b/src/graph/planner/match/ReturnClausePlanner.cpp @@ -35,8 +35,7 @@ Status ReturnClausePlanner::buildReturn(ReturnClauseContext* rctx, SubPlan& subP auto orderPlan = std::make_unique()->transform(rctx->order.get()); NG_RETURN_IF_ERROR(orderPlan); auto plan = std::move(orderPlan).value(); - SegmentsConnector::addInput(plan.tail, subPlan.root, true); - subPlan.root = plan.root; + subPlan = SegmentsConnector::addInput(plan, subPlan, true); } if (rctx->pagination != nullptr && @@ -45,8 +44,7 @@ Status ReturnClausePlanner::buildReturn(ReturnClauseContext* rctx, SubPlan& subP auto paginationPlan = std::make_unique()->transform(rctx->pagination.get()); NG_RETURN_IF_ERROR(paginationPlan); auto plan = std::move(paginationPlan).value(); - SegmentsConnector::addInput(plan.tail, subPlan.root, true); - subPlan.root = plan.root; + subPlan = SegmentsConnector::addInput(plan, subPlan, true); } VLOG(1) << "return root: " << subPlan.root->outputVar() diff --git a/src/graph/planner/match/SegmentsConnectStrategy.h b/src/graph/planner/match/SegmentsConnectStrategy.h deleted file mode 100644 index 4cb6e431c26..00000000000 --- a/src/graph/planner/match/SegmentsConnectStrategy.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_MATCH_SEGMENTSCONNECTSTRATEGY_H_ -#define GRAPH_PLANNER_MATCH_SEGMENTSCONNECTSTRATEGY_H_ - -namespace nebula { -namespace graph { - -class PlanNode; -class QueryContext; - -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 // GRAPH_PLANNER_MATCH_SEGMENTSCONNECTSTRATEGY_H_ diff --git a/src/graph/planner/match/SegmentsConnector.cpp b/src/graph/planner/match/SegmentsConnector.cpp index 1c50a352002..6e6d4bc50db 100644 --- a/src/graph/planner/match/SegmentsConnector.cpp +++ b/src/graph/planner/match/SegmentsConnector.cpp @@ -5,50 +5,84 @@ #include "graph/planner/match/SegmentsConnector.h" -#include "graph/planner/match/AddDependencyStrategy.h" -#include "graph/planner/match/AddInputStrategy.h" -#include "graph/planner/match/CartesianProductStrategy.h" +#include "graph/planner/plan/Algo.h" +#include "graph/planner/plan/Query.h" namespace nebula { namespace graph { -StatusOr SegmentsConnector::connectSegments(CypherClauseContextBase* leftCtx, - CypherClauseContextBase* rightCtx, - SubPlan& left, - SubPlan& right) { - UNUSED(rightCtx); - if (leftCtx->kind == CypherClauseKind::kReturn || leftCtx->kind == CypherClauseKind::kWith || - leftCtx->kind == CypherClauseKind::kUnwind) { - VLOG(1) << "left tail: " << left.tail->outputVar() << "right root: " << right.root->outputVar(); - addInput(left.tail, right.root); - left.tail = right.tail; - return left; +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; + std::vector probeKeys; + auto pool = qctx->objPool(); + for (auto& alias : intersectedAliases) { + auto* args = ArgumentList::make(pool); + args->addArgument(InputPropertyExpression::make(pool, alias)); + auto* expr = FunctionCallExpression::make(pool, "id", args); + hashKeys.emplace_back(expr); + probeKeys.emplace_back(expr->clone()); } + innerJoin->setHashKeys(std::move(hashKeys)); + innerJoin->setProbeKeys(std::move(probeKeys)); - return Status::Error("Can not solve the connect strategy of the two subplan.."); + newPlan.root = innerJoin; + return newPlan; } -PlanNode* SegmentsConnector::innerJoinSegments(QueryContext* qctx, - const PlanNode* left, - const PlanNode* right, - InnerJoinStrategy::JoinPos leftPos, - InnerJoinStrategy::JoinPos rightPos) { - return std::make_unique(qctx)->leftPos(leftPos)->rightPos(rightPos)->connect( - left, right); -} +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; + std::vector probeKeys; + auto pool = qctx->objPool(); + for (auto& alias : intersectedAliases) { + auto* args = ArgumentList::make(pool); + args->addArgument(InputPropertyExpression::make(pool, alias)); + auto* expr = FunctionCallExpression::make(pool, "id", args); + hashKeys.emplace_back(expr); + probeKeys.emplace_back(expr->clone()); + } + leftJoin->setHashKeys(std::move(hashKeys)); + leftJoin->setProbeKeys(std::move(probeKeys)); -PlanNode* SegmentsConnector::cartesianProductSegments(QueryContext* qctx, - const PlanNode* left, - const PlanNode* right) { - return std::make_unique(qctx)->connect(left, right); + newPlan.root = leftJoin; + return newPlan; } -void SegmentsConnector::addDependency(const PlanNode* left, const PlanNode* right) { - std::make_unique()->connect(left, right); +SubPlan SegmentsConnector::cartesianProduct(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right) { + SubPlan newPlan = left; + newPlan.root = BiCartesianProduct::make(qctx, left.root, right.root); + return newPlan; } -void SegmentsConnector::addInput(const PlanNode* left, const PlanNode* right, bool copyColNames) { - std::make_unique(copyColNames)->connect(left, right); +SubPlan SegmentsConnector::addInput(const SubPlan& left, const SubPlan& right, bool copyColNames) { + SubPlan newPlan = left; + DCHECK(left.root->isSingleInput()); + auto* mutableLeft = const_cast(left.tail); + auto* siLeft = static_cast(mutableLeft); + siLeft->dependsOn(const_cast(right.root)); + siLeft->setInputVar(right.root->outputVar()); + if (copyColNames) { + siLeft->setColNames(right.root->colNames()); + } else if (siLeft->kind() == PlanNode::Kind::kUnwind) { + // An unwind bypass all aliases, so merge the columns here + auto colNames = right.root->colNames(); + colNames.insert(colNames.end(), siLeft->colNames().begin(), siLeft->colNames().end()); + siLeft->setColNames(std::move(colNames)); + } + + newPlan.tail = right.tail; + return newPlan; } } // namespace graph } // namespace nebula diff --git a/src/graph/planner/match/SegmentsConnector.h b/src/graph/planner/match/SegmentsConnector.h index a90d2139f2e..1594879c348 100644 --- a/src/graph/planner/match/SegmentsConnector.h +++ b/src/graph/planner/match/SegmentsConnector.h @@ -9,7 +9,6 @@ #include "graph/context/QueryContext.h" #include "graph/context/ast/CypherAstContext.h" #include "graph/planner/Planner.h" -#include "graph/planner/match/InnerJoinStrategy.h" #include "graph/planner/plan/PlanNode.h" namespace nebula { @@ -20,42 +19,33 @@ namespace graph { */ class SegmentsConnector final { public: - enum class ConnectStrategy : int8_t { - kAddDependency, - kInnerJoin, - kLeftOuterJoin, - kCartesianProduct, - kUnion, - }; - SegmentsConnector() = delete; - // Analyse the relation of two segments and connect them. - static StatusOr connectSegments(CypherClauseContextBase* leftCtx, - CypherClauseContextBase* rightCtx, - SubPlan& left, - SubPlan& right); - - static PlanNode* innerJoinSegments( - QueryContext* qctx, - const PlanNode* left, - const PlanNode* right, - InnerJoinStrategy::JoinPos leftPos = InnerJoinStrategy::JoinPos::kEnd, - InnerJoinStrategy::JoinPos rightPos = InnerJoinStrategy::JoinPos::kStart); + /** + * InnerJoin two plan on node id + */ + static SubPlan innerJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases); - static PlanNode* cartesianProductSegments(QueryContext* qctx, - const PlanNode* left, - const PlanNode* right); + /** + * LeftJoin two plan on node id + */ + static SubPlan leftJoin(QueryContext* qctx, + const SubPlan& left, + const SubPlan& right, + const std::unordered_set& intersectedAliases); /** - * left->right + * Simply do a CartesianProduct of two plan root. */ - static void addDependency(const PlanNode* left, const PlanNode* right); + static SubPlan cartesianProduct(QueryContext* qctx, const SubPlan& left, const SubPlan& right); /* * left->right */ - static void addInput(const PlanNode* left, const PlanNode* right, bool copyColNames = false); + static SubPlan addInput(const SubPlan& left, const SubPlan& right, bool copyColNames = false); }; } // namespace graph } // namespace nebula diff --git a/src/graph/planner/match/UnionStrategy.h b/src/graph/planner/match/UnionStrategy.h deleted file mode 100644 index 43d9299f666..00000000000 --- a/src/graph/planner/match/UnionStrategy.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef GRAPH_PLANNER_MATCH_UNIONSTRATEGY_H_ -#define GRAPH_PLANNER_MATCH_UNIONSTRATEGY_H_ - -namespace nebula { -namespace graph { -/* - * The UnionStrategy was designed to union two subplan by union. - */ -class UnionStrategy final {}; -} // namespace graph -} // namespace nebula -#endif // GRAPH_PLANNER_MATCH_UNIONSTRATEGY_H_ diff --git a/src/graph/planner/match/WithClausePlanner.cpp b/src/graph/planner/match/WithClausePlanner.cpp index 142d59acdeb..a92fdb32808 100644 --- a/src/graph/planner/match/WithClausePlanner.cpp +++ b/src/graph/planner/match/WithClausePlanner.cpp @@ -36,8 +36,7 @@ Status WithClausePlanner::buildWith(WithClauseContext* wctx, SubPlan& subPlan) { auto orderPlan = std::make_unique()->transform(wctx->order.get()); NG_RETURN_IF_ERROR(orderPlan); auto plan = std::move(orderPlan).value(); - SegmentsConnector::addInput(plan.tail, subPlan.root, true); - subPlan.root = plan.root; + subPlan = SegmentsConnector::addInput(plan, subPlan, true); } if (wctx->pagination != nullptr && @@ -46,8 +45,7 @@ Status WithClausePlanner::buildWith(WithClauseContext* wctx, SubPlan& subPlan) { auto paginationPlan = std::make_unique()->transform(wctx->pagination.get()); NG_RETURN_IF_ERROR(paginationPlan); auto plan = std::move(paginationPlan).value(); - SegmentsConnector::addInput(plan.tail, subPlan.root, true); - subPlan.root = plan.root; + subPlan = SegmentsConnector::addInput(plan, subPlan, true); } if (wctx->where != nullptr) { @@ -56,8 +54,7 @@ Status WithClausePlanner::buildWith(WithClauseContext* wctx, SubPlan& subPlan) { std::make_unique(needStableFilter)->transform(wctx->where.get()); NG_RETURN_IF_ERROR(wherePlan); auto plan = std::move(wherePlan).value(); - SegmentsConnector::addInput(plan.tail, subPlan.root, true); - subPlan.root = plan.root; + subPlan = SegmentsConnector::addInput(plan, subPlan, true); } VLOG(1) << "with root: " << subPlan.root->outputVar()