Skip to content

Commit

Permalink
Stop scan edge opt when build path (vesoft-inc#944)
Browse files Browse the repository at this point in the history
* Stop scanV -> scanE optRule when buildPath

delete: av->traverse->scanV
add: project-> limit -> av->traverse->sv
add: project-> av ->traverse->sv

exclude optRule for buildPath in project.colums()

Comments added

lint: clang-format

[WIP] Fixing regression when return e, e.foo.bar

The limit info is lost in this case

Fix after vesoft-inc#4146

OptGroup was refactored in vesoft-inc#4146

Removed GetEdgesTransformRule

* Rebase on vesoft-inc#4277 Remove useless AppendVertices

As this rule only aplied for
   match ()-[e]->() return e limit 1
when 1. there is no index on e and 2. limit cluase
exists, thus we could assert that AppendVertices
will be removed by EliminateAppendVerticesRule

//  Tranformation:
//  Before:
// +---------+---------+
// |      Project      |
// +---------+---------+
//           |
// +---------+---------+
// |       Limit       |
// +---------+---------+
//           |
// +---------+---------+
// |      Traverse     |
// +---------+---------+
//           |
// +---------+---------+
// |    ScanVertices   |
// +---------+---------+
//
//  After:
// +---------+---------+
// |      Project      |
// +---------+---------+
//           |
// +---------+---------+
// |       Limit       |
// +---------+---------+
//           |
// +---------+---------+
// |      Project      |
// +---------+---------+
//           |
// +---------+---------+
// |      ScanEdges    |
// +---------+---------+

* Addressing Shylock-Hg's comment

* Make linter happy

* Fix after EliminateAppendVerticesRule merged

and linting

* Reusing functions in GetEdgesTransformRule

* Addressing comment from Shylock-Hg & rebase

Co-authored-by: cpw <13495049+CPWstatic@users.noreply.github.com>

Co-authored-by: Wey Gu <weyl.gu@gmail.com>
Co-authored-by: cpw <13495049+CPWstatic@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 10, 2022
1 parent 63322aa commit e4b7e12
Show file tree
Hide file tree
Showing 7 changed files with 383 additions and 75 deletions.
1 change: 1 addition & 0 deletions src/graph/optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ nebula_add_library(
rule/PushLimitDownProjectRule.cpp
rule/EliminateRowCollectRule.cpp
rule/PushLimitDownScanAppendVerticesRule.cpp
rule/GetEdgesTransformAppendVerticesLimitRule.cpp
rule/GetEdgesTransformRule.cpp
rule/PushLimitDownScanEdgesAppendVerticesRule.cpp
rule/PushTopNDownIndexScanRule.cpp
Expand Down
148 changes: 148 additions & 0 deletions src/graph/optimizer/rule/GetEdgesTransformAppendVerticesLimitRule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/* 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/optimizer/rule/GetEdgesTransformUtils.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 = GetEdgesTransformUtils::traverseToScanEdges(traverse, limit->count(qctx));
if (newScanEdges == nullptr) {
return TransformResult::noTransform();
}
auto newScanEdgesGroup = OptGroup::create(ctx);
auto newScanEdgesGroupNode = newScanEdgesGroup->makeGroupNode(newScanEdges);

auto *newProj =
GetEdgesTransformUtils::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";
}

} // namespace opt
} // namespace nebula
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* 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::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 e4b7e12

Please sign in to comment.