Skip to content

Commit

Permalink
Fix after EliminateAppendVerticesRule merged
Browse files Browse the repository at this point in the history
and linting
  • Loading branch information
wey-gu committed Jun 7, 2022
1 parent 3259cd7 commit 4c4cb37
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 38 deletions.
3 changes: 2 additions & 1 deletion src/graph/optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ nebula_add_library(
rule/PushLimitDownProjectRule.cpp
rule/EliminateRowCollectRule.cpp
rule/PushLimitDownScanAppendVerticesRule.cpp
rule/GetEdgesTransformLimitRule.cpp
rule/GetEdgesTransformAppendVerticesLimitRule.cpp
rule/GetEdgesTransformRule.cpp
rule/PushLimitDownScanEdgesAppendVerticesRule.cpp
rule/PushTopNDownIndexScanRule.cpp
rule/EliminateAppendVerticesRule.cpp
Expand Down
187 changes: 187 additions & 0 deletions src/graph/optimizer/rule/GetEdgesTransformAppendVerticesLimitRule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/* Copyright (c) 2021 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#include "graph/optimizer/rule/GetEdgesTransformAppendVerticesLimitRule.h"

#include "common/expression/Expression.h"
#include "graph/optimizer/OptContext.h"
#include "graph/optimizer/OptGroup.h"
#include "graph/planner/plan/PlanNode.h"
#include "graph/planner/plan/Query.h"
#include "graph/visitor/ExtractFilterExprVisitor.h"

using nebula::Expression;
using nebula::graph::AppendVertices;
using nebula::graph::Limit;
using nebula::graph::PlanNode;
using nebula::graph::Project;
using nebula::graph::QueryContext;
using nebula::graph::ScanEdges;
using nebula::graph::ScanVertices;
using nebula::graph::Traverse;

namespace nebula {
namespace opt {

std::unique_ptr<OptRule> GetEdgesTransformAppendVerticesLimitRule::kInstance =
std::unique_ptr<GetEdgesTransformAppendVerticesLimitRule>(
new GetEdgesTransformAppendVerticesLimitRule());

GetEdgesTransformAppendVerticesLimitRule::GetEdgesTransformAppendVerticesLimitRule() {
RuleSet::QueryRules().addRule(this);
}

const Pattern &GetEdgesTransformAppendVerticesLimitRule::pattern() const {
static Pattern pattern = Pattern::create(
PlanNode::Kind::kProject,
{Pattern::create(
PlanNode::Kind::kLimit,
{Pattern::create(PlanNode::Kind::kAppendVertices,
{Pattern::create(PlanNode::Kind::kTraverse,
{Pattern::create(PlanNode::Kind::kScanVertices)})})})});
return pattern;
}

bool GetEdgesTransformAppendVerticesLimitRule::match(OptContext *ctx,
const MatchedResult &matched) const {
if (!OptRule::match(ctx, matched)) {
return false;
}
auto traverse = static_cast<const Traverse *>(matched.planNode({0, 0, 0, 0}));
auto project = static_cast<const Project *>(matched.planNode({0}));
const auto &colNames = traverse->colNames();
auto colSize = colNames.size();
DCHECK_GE(colSize, 2);
if (colNames[colSize - 2][0] != '_') { // src
return false;
}
if (traverse->stepRange() != nullptr) {
return false;
}
for (auto yieldColumn : project->columns()->columns()) {
// exclude p=()-[e]->() return p limit 10
if (yieldColumn->expr()->kind() == nebula::Expression::Kind::kPathBuild) {
return false;
}
}
return true;
}

StatusOr<OptRule::TransformResult> GetEdgesTransformAppendVerticesLimitRule::transform(
OptContext *ctx, const MatchedResult &matched) const {
auto projectGroupNode = matched.node;
auto project = static_cast<const Project *>(projectGroupNode->node());

auto newProject = project->clone();
auto newProjectGroupNode = OptGroupNode::create(ctx, newProject, projectGroupNode->group());
newProject->setOutputVar(project->outputVar());

auto limitGroupNode = matched.dependencies.front().node;
auto limit = static_cast<const Limit *>(limitGroupNode->node());

auto newLimit = limit->clone();
auto newLimitGroup = OptGroup::create(ctx);
auto newLimitGroupNode = newLimitGroup->makeGroupNode(newLimit);
newLimit->setOutputVar(limit->outputVar());
newProject->setInputVar(newLimit->outputVar());

newProjectGroupNode->dependsOn(newLimitGroup);

auto appendVerticesGroupNode = matched.dependencies.front().dependencies.front().node;
auto appendVertices = static_cast<const AppendVertices *>(appendVerticesGroupNode->node());
auto traverseGroupNode =
matched.dependencies.front().dependencies.front().dependencies.front().node;
auto traverse = static_cast<const Traverse *>(traverseGroupNode->node());
auto scanVerticesGroupNode = matched.dependencies.front()
.dependencies.front()
.dependencies.front()
.dependencies.front()
.node;
auto qctx = ctx->qctx();

auto newAppendVertices = appendVertices->clone();
auto newAppendVerticesGroup = OptGroup::create(ctx);
auto colSize = appendVertices->colNames().size();
newAppendVertices->setOutputVar(appendVertices->outputVar());
newLimit->setInputVar(newAppendVertices->outputVar());
newAppendVertices->setColNames(
{appendVertices->colNames()[colSize - 2], appendVertices->colNames()[colSize - 1]});
auto newAppendVerticesGroupNode = newAppendVerticesGroup->makeGroupNode(newAppendVertices);

newLimitGroupNode->dependsOn(newAppendVerticesGroup);

auto *newScanEdges = traverseToScanEdges(traverse, limit->count(qctx));
if (newScanEdges == nullptr) {
return TransformResult::noTransform();
}
auto newScanEdgesGroup = OptGroup::create(ctx);
auto newScanEdgesGroupNode = newScanEdgesGroup->makeGroupNode(newScanEdges);

auto *newProj = projectEdges(qctx, newScanEdges, traverse->colNames().back());
newProj->setInputVar(newScanEdges->outputVar());
newProj->setOutputVar(newAppendVertices->inputVar());
newProj->setColNames({traverse->colNames().back()});
auto newProjGroup = OptGroup::create(ctx);
auto newProjGroupNode = newProjGroup->makeGroupNode(newProj);

newAppendVerticesGroupNode->dependsOn(newProjGroup);
newProjGroupNode->dependsOn(newScanEdgesGroup);
for (auto dep : scanVerticesGroupNode->dependencies()) {
newScanEdgesGroupNode->dependsOn(dep);
}

TransformResult result;
result.eraseCurr = true;
result.newGroupNodes.emplace_back(newProjectGroupNode);
return result;
}

std::string GetEdgesTransformAppendVerticesLimitRule::toString() const {
return "GetEdgesTransformAppendVerticesLimitRule";
}

/*static*/ graph::ScanEdges *GetEdgesTransformAppendVerticesLimitRule::traverseToScanEdges(
const graph::Traverse *traverse, const int64_t limit_count = -1) {
const auto *edgeProps = traverse->edgeProps();
if (edgeProps == nullptr) {
return nullptr;
}
for (std::size_t i = 0; i < edgeProps->size(); i++) {
auto type = (*edgeProps)[i].get_type();
for (std::size_t j = i + 1; j < edgeProps->size(); j++) {
if (type == -((*edgeProps)[j].get_type())) {
// Don't support to retrieve edges of the inbound/outbound together
return nullptr;
}
}
}
auto scanEdges = ScanEdges::make(
traverse->qctx(),
nullptr,
traverse->space(),
edgeProps == nullptr ? nullptr
: std::make_unique<std::vector<storage::cpp2::EdgeProp>>(*edgeProps),
nullptr,
traverse->dedup(),
limit_count,
{},
traverse->filter() == nullptr ? nullptr : traverse->filter()->clone());
return scanEdges;
}

/*static*/ graph::Project *GetEdgesTransformAppendVerticesLimitRule::projectEdges(
graph::QueryContext *qctx, PlanNode *input, const std::string &colName) {
auto *yieldColumns = qctx->objPool()->makeAndAdd<YieldColumns>();
auto *edgeExpr = EdgeExpression::make(qctx->objPool());
auto *listEdgeExpr = ListExpression::make(qctx->objPool());
listEdgeExpr->setItems({edgeExpr});
yieldColumns->addColumn(new YieldColumn(listEdgeExpr, colName));
auto project = Project::make(qctx, input, yieldColumns);
project->setColNames({colName});
return project;
}

} // namespace opt
} // namespace nebula
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* Copyright (c) 2021 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#pragma once

#include "graph/optimizer/OptRule.h"

namespace nebula {

namespace graph {
class ScanEdges;
class Project;
class Traverse;
class PlanNode;
} // namespace graph

namespace opt {

// Convert [[ScanVertices]] to [[ScanEdges]] in certain cases
// Required conditions:
// 1. Match the pattern
// Benefits:
// 1. Avoid doing Traverse to optimize performance
// Query example:
// 1. match ()-[e]->() return e limit 1
//
// Tranformation:
// Before:
// +---------+---------+
// | Project |
// +---------+---------+
// |
// +---------+---------+
// | Limit |
// +---------+---------+
// |
// +---------+---------+
// | AppendVertices |
// +---------+---------+
// |
// +---------+---------+
// | Traverse |
// +---------+---------+
// |
// +---------+---------+
// | ScanVertices |
// +---------+---------+
//
// After:
// +---------+---------+
// | Project |
// +---------+---------+
// |
// +---------+---------+
// | Limit |
// +---------+---------+
// |
// +---------+---------+
// | AppendVertices |
// +---------+---------+
// |
// +---------+---------+
// | Project |
// +---------+---------+
// |
// +---------+---------+
// | ScanEdges |
// +---------+---------+

class GetEdgesTransformAppendVerticesLimitRule final : public OptRule {
public:
const Pattern &pattern() const override;

bool match(OptContext *ctx, const MatchedResult &matched) const override;
StatusOr<TransformResult> transform(OptContext *ctx, const MatchedResult &matched) const override;

std::string toString() const override;

private:
GetEdgesTransformAppendVerticesLimitRule();

static graph::ScanEdges *traverseToScanEdges(const graph::Traverse *traverse,
const int64_t limit_count);

static graph::Project *projectEdges(graph::QueryContext *qctx,
graph::PlanNode *input,
const std::string &colName);

static std::unique_ptr<OptRule> kInstance;
};

} // namespace opt
} // namespace nebula
Loading

0 comments on commit 4c4cb37

Please sign in to comment.