From 13ded46ca0a8a4e8a11ab18c68b18c25e4be0877 Mon Sep 17 00:00:00 2001 From: jimingquan Date: Fri, 31 Mar 2023 17:46:35 +0800 Subject: [PATCH] refactor traverse output --- src/graph/context/ast/CypherAstContext.h | 2 + src/graph/executor/query/TraverseExecutor.cpp | 66 ++++++++++++++----- src/graph/executor/query/TraverseExecutor.h | 1 + src/graph/planner/match/MatchPathPlanner.cpp | 13 +++- src/graph/planner/match/MatchSolver.cpp | 27 ++++---- src/graph/planner/plan/Query.cpp | 1 + src/graph/planner/plan/Query.h | 9 +++ src/graph/validator/MatchValidator.cpp | 3 +- .../match/VariableLengthPattern.feature | 1 + 9 files changed, 89 insertions(+), 34 deletions(-) diff --git a/src/graph/context/ast/CypherAstContext.h b/src/graph/context/ast/CypherAstContext.h index 1b7ca85c235..47b9a184bf2 100644 --- a/src/graph/context/ast/CypherAstContext.h +++ b/src/graph/context/ast/CypherAstContext.h @@ -51,6 +51,8 @@ struct EdgeInfo { MatchEdge::Direction direction{MatchEdge::Direction::OUT_EDGE}; std::vector types; std::string alias; + // use for construct path struct + std::string innerAlias; const MapExpression* props{nullptr}; Expression* filter{nullptr}; }; diff --git a/src/graph/executor/query/TraverseExecutor.cpp b/src/graph/executor/query/TraverseExecutor.cpp index 3c34b8c6255..2f5f3d7f779 100644 --- a/src/graph/executor/query/TraverseExecutor.cpp +++ b/src/graph/executor/query/TraverseExecutor.cpp @@ -24,6 +24,7 @@ namespace graph { folly::Future TraverseExecutor::execute() { range_ = traverse_->stepRange(); + genPath_ = traverse_->genPath(); NG_RETURN_IF_ERROR(buildRequestVids()); if (vids_.empty()) { DataSet emptyDs; @@ -477,38 +478,53 @@ std::vector TraverseExecutor::buildPath(const Value& initVertex, return std::vector(); } - std::vector result; - result.reserve(adjEdges.size()); + std::vector oneStepPath; + oneStepPath.reserve(adjEdges.size()); for (auto& edge : adjEdges) { List edgeList; edgeList.values.emplace_back(edge); Row row; row.values.emplace_back(src); - row.values.emplace_back(std::move(edgeList)); - result.emplace_back(std::move(row)); + // only contain edges + row.values.emplace_back(edgeList); + if (genPath_) { + // contain nodes & edges + row.values.emplace_back(std::move(edgeList)); + } + oneStepPath.emplace_back(std::move(row)); } if (maxStep == 1) { if (traverse_->trackPrevPath()) { - return joinPrevPath(initVertex, result); + return joinPrevPath(initVertex, oneStepPath); } - return result; + return oneStepPath; } size_t step = 2; std::vector newResult; std::queue*> queue; + std::queue*> edgeListQueue; std::list>> holder; for (auto& edge : adjEdges) { auto ptr = std::make_unique>(std::vector({edge})); queue.emplace(ptr.get()); + edgeListQueue.emplace(ptr.get()); holder.emplace_back(std::move(ptr)); } - size_t adjSize = queue.size(); - while (!queue.empty()) { - auto edgeListPtr = queue.front(); + + size_t adjSize = edgeListQueue.size(); + while (!edgeListQueue.empty()) { + auto edgeListPtr = edgeListQueue.front(); auto& dst = edgeListPtr->back().getEdge().dst; - queue.pop(); + edgeListQueue.pop(); + + std::vector* vertexEdgeListPtr = nullptr; + if (genPath_) { + vertexEdgeListPtr = queue.front(); + queue.pop(); + } + --adjSize; auto dstIter = adjList_.find(dst); if (dstIter == adjList_.end()) { @@ -516,7 +532,7 @@ std::vector TraverseExecutor::buildPath(const Value& initVertex, if (++step > maxStep) { break; } - adjSize = queue.size(); + adjSize = edgeListQueue.size(); } continue; } @@ -527,29 +543,44 @@ std::vector TraverseExecutor::buildPath(const Value& initVertex, continue; } auto newEdgeListPtr = std::make_unique>(*edgeListPtr); - newEdgeListPtr->emplace_back(dstIter->first); newEdgeListPtr->emplace_back(edge); + std::unique_ptr> newVertexEdgeListPtr = nullptr; + if (genPath_) { + newVertexEdgeListPtr = std::make_unique>(*vertexEdgeListPtr); + newVertexEdgeListPtr->emplace_back(dstIter->first); + newVertexEdgeListPtr->emplace_back(edge); + } + if (step >= minStep) { Row row; row.values.emplace_back(src); + // only contain edges row.values.emplace_back(List(*newEdgeListPtr)); + if (genPath_) { + // contain nodes & edges + row.values.emplace_back(List(*newVertexEdgeListPtr)); + } newResult.emplace_back(std::move(row)); } - queue.emplace(newEdgeListPtr.get()); + edgeListQueue.emplace(newEdgeListPtr.get()); holder.emplace_back(std::move(newEdgeListPtr)); + if (genPath_ && newVertexEdgeListPtr != nullptr) { + queue.emplace(newVertexEdgeListPtr.get()); + holder.emplace_back(std::move(newVertexEdgeListPtr)); + } } if (adjSize == 0) { if (++step > maxStep) { break; } - adjSize = queue.size(); + adjSize = edgeListQueue.size(); } } if (minStep <= 1) { newResult.insert(newResult.begin(), - std::make_move_iterator(result.begin()), - std::make_move_iterator(result.end())); + std::make_move_iterator(oneStepPath.begin()), + std::make_move_iterator(oneStepPath.end())); } if (traverse_->trackPrevPath()) { return joinPrevPath(initVertex, newResult); @@ -570,8 +601,7 @@ std::vector TraverseExecutor::joinPrevPath(const Value& initVertex, if (!hasSameEdgeInPath(prevPath, p)) { // copy Row row = prevPath; - row.values.emplace_back(p.values.front()); - row.values.emplace_back(p.values.back()); + row.values.insert(row.values.end(), p.values.begin(), p.values.end()); newPaths.emplace_back(std::move(row)); } } diff --git a/src/graph/executor/query/TraverseExecutor.h b/src/graph/executor/query/TraverseExecutor.h index 629718b34b5..e8cda9c798f 100644 --- a/src/graph/executor/query/TraverseExecutor.h +++ b/src/graph/executor/query/TraverseExecutor.h @@ -93,6 +93,7 @@ class TraverseExecutor final : public StorageAccessExecutor { private: ObjectPool objPool_; + bool genPath_{false}; VidHashSet vids_; std::vector initVertices_; DataSet result_; diff --git a/src/graph/planner/match/MatchPathPlanner.cpp b/src/graph/planner/match/MatchPathPlanner.cpp index 741c18f785b..13d7f5e18c0 100644 --- a/src/graph/planner/match/MatchPathPlanner.cpp +++ b/src/graph/planner/match/MatchPathPlanner.cpp @@ -26,13 +26,17 @@ MatchPathPlanner::MatchPathPlanner(CypherClauseContextBase* ctx, const Path& pat static std::vector genTraverseColNames(const std::vector& inputCols, const NodeInfo& node, const EdgeInfo& edge, - bool trackPrev) { + bool trackPrev, + bool genPath = false) { std::vector cols; if (trackPrev) { cols = inputCols; } cols.emplace_back(node.alias); cols.emplace_back(edge.alias); + if (genPath) { + cols.emplace_back(edge.innerAlias); + } return cols; } @@ -218,11 +222,13 @@ Status MatchPathPlanner::leftExpandFromNode(size_t startIndex, SubPlan& subplan) traverse->setEdgeDirection(edge.direction); traverse->setStepRange(stepRange); traverse->setDedup(); + traverse->setGenPath(path_.genPath); // If start from end of the path pattern, the first traverse would not // track the previous path, otherwise, it should. bool trackPrevPath = (startIndex + 1 == nodeInfos.size() ? i != startIndex : true); traverse->setTrackPrevPath(trackPrevPath); - traverse->setColNames(genTraverseColNames(subplan.root->colNames(), node, edge, trackPrevPath)); + traverse->setColNames( + genTraverseColNames(subplan.root->colNames(), node, edge, trackPrevPath, path_.genPath)); subplan.root = traverse; nextTraverseStart = genNextTraverseStart(qctx->objPool(), edge); if (expandInto) { @@ -290,8 +296,9 @@ Status MatchPathPlanner::rightExpandFromNode(size_t startIndex, SubPlan& subplan traverse->setStepRange(stepRange); traverse->setDedup(); traverse->setTrackPrevPath(i != startIndex); + traverse->setGenPath(path_.genPath); traverse->setColNames( - genTraverseColNames(subplan.root->colNames(), node, edge, i != startIndex)); + genTraverseColNames(subplan.root->colNames(), node, edge, i != startIndex, path_.genPath)); subplan.root = traverse; nextTraverseStart = genNextTraverseStart(qctx->objPool(), edge); if (expandInto) { diff --git a/src/graph/planner/match/MatchSolver.cpp b/src/graph/planner/match/MatchSolver.cpp index 8f91271ddb0..8687d906893 100644 --- a/src/graph/planner/match/MatchSolver.cpp +++ b/src/graph/planner/match/MatchSolver.cpp @@ -231,21 +231,17 @@ static YieldColumn* buildVertexColumn(ObjectPool* pool, const std::string& alias return new YieldColumn(InputPropertyExpression::make(pool, alias), alias); } -static YieldColumn* buildEdgeColumn(QueryContext* qctx, const EdgeInfo& edge) { +static YieldColumn* buildEdgeColumn(QueryContext* qctx, const EdgeInfo& edge, bool genPath) { Expression* expr = nullptr; + const std::string& edgeName = genPath ? edge.innerAlias : edge.alias; auto pool = qctx->objPool(); if (edge.range == nullptr) { expr = SubscriptExpression::make( - pool, InputPropertyExpression::make(pool, edge.alias), ConstantExpression::make(pool, 0)); + pool, InputPropertyExpression::make(pool, edgeName), ConstantExpression::make(pool, 0)); } else { - auto innerVar = qctx->vctx()->anonVarGen()->getVar(); - auto* args = ArgumentList::make(pool); - args->addArgument(VariableExpression::makeInner(pool, innerVar)); - auto* filter = FunctionCallExpression::make(pool, "is_edge", args); - expr = ListComprehensionExpression::make( - pool, innerVar, InputPropertyExpression::make(pool, edge.alias), filter); + expr = InputPropertyExpression::make(pool, edgeName); } - return new YieldColumn(expr, edge.alias); + return new YieldColumn(expr, edgeName); } // static @@ -262,16 +258,23 @@ void MatchSolver::buildProjectColumns(QueryContext* qctx, const Path& path, SubP } }; - auto addEdge = [columns, &colNames, qctx](auto& edgeInfo) { + auto addEdge = [columns, &colNames, qctx](auto& edgeInfo, bool genPath = false) { if (!edgeInfo.alias.empty() && !edgeInfo.anonymous) { - columns->addColumn(buildEdgeColumn(qctx, edgeInfo)); - colNames.emplace_back(edgeInfo.alias); + columns->addColumn(buildEdgeColumn(qctx, edgeInfo, genPath)); + if (genPath) { + colNames.emplace_back(edgeInfo.innerAlias); + } else { + colNames.emplace_back(edgeInfo.alias); + } } }; for (size_t i = 0; i < edgeInfos.size(); i++) { addNode(nodeInfos[i]); addEdge(edgeInfos[i]); + if (path.genPath) { + addEdge(edgeInfos[i], true); + } } // last vertex diff --git a/src/graph/planner/plan/Query.cpp b/src/graph/planner/plan/Query.cpp index 8d50e1f09a4..5a64b3e0c8d 100644 --- a/src/graph/planner/plan/Query.cpp +++ b/src/graph/planner/plan/Query.cpp @@ -832,6 +832,7 @@ void Traverse::cloneMembers(const Traverse& g) { if (g.tagFilter_ != nullptr) { setTagFilter(g.tagFilter_->clone()); } + genPath_ = g.genPath(); } std::unique_ptr Traverse::explain() const { diff --git a/src/graph/planner/plan/Query.h b/src/graph/planner/plan/Query.h index 60f8dadf859..c130d4361d7 100644 --- a/src/graph/planner/plan/Query.h +++ b/src/graph/planner/plan/Query.h @@ -1713,10 +1713,18 @@ class Traverse final : public GetNeighbors { firstStepFilter_ = filter; } + void setGenPath(bool genPath) { + genPath_ = genPath; + } + Expression* tagFilter() const { return tagFilter_; } + bool genPath() const { + return genPath_; + } + void setTagFilter(Expression* tagFilter) { tagFilter_ = tagFilter; } @@ -1738,6 +1746,7 @@ class Traverse final : public GetNeighbors { // Push down filter in first step Expression* firstStepFilter_{nullptr}; Expression* tagFilter_{nullptr}; + bool genPath_{false}; }; // Append vertices to a path. diff --git a/src/graph/validator/MatchValidator.cpp b/src/graph/validator/MatchValidator.cpp index a49e4fd7ed2..2403bbad5fe 100644 --- a/src/graph/validator/MatchValidator.cpp +++ b/src/graph/validator/MatchValidator.cpp @@ -181,7 +181,7 @@ Status MatchValidator::buildPathExpr(const MatchPath *path, auto pathBuild = PathBuildExpression::make(pool); for (size_t i = 0; i < edgeInfos.size(); ++i) { pathBuild->add(InputPropertyExpression::make(pool, nodeInfos[i].alias)); - pathBuild->add(InputPropertyExpression::make(pool, edgeInfos[i].alias)); + pathBuild->add(InputPropertyExpression::make(pool, edgeInfos[i].innerAlias)); } pathBuild->add(InputPropertyExpression::make(pool, nodeInfos.back().alias)); pathInfo.pathBuild = std::move(pathBuild); @@ -332,6 +332,7 @@ Status MatchValidator::buildEdgeInfo(const MatchPath *path, edgeInfos[i].anonymous = anonymous; edgeInfos[i].direction = direction; edgeInfos[i].alias = alias; + edgeInfos[i].innerAlias = "_" + alias; edgeInfos[i].props = props; edgeInfos[i].filter = filter; } diff --git a/tests/tck/features/match/VariableLengthPattern.feature b/tests/tck/features/match/VariableLengthPattern.feature index 5563b220f2c..0808939fa35 100644 --- a/tests/tck/features/match/VariableLengthPattern.feature +++ b/tests/tck/features/match/VariableLengthPattern.feature @@ -1,6 +1,7 @@ # Copyright (c) 2020 vesoft inc. All rights reserved. # # This source code is licensed under Apache 2.0 License. +@jmq Feature: Variable length Pattern match (m to n) Background: