Skip to content

Commit

Permalink
Stop scanV -> scanE optRule when buildPath
Browse files Browse the repository at this point in the history
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
  • Loading branch information
wey-gu committed Jun 9, 2022
1 parent f9e699d commit 3723280
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 160 deletions.
2 changes: 1 addition & 1 deletion src/graph/optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ nebula_add_library(
rule/PushLimitDownProjectRule.cpp
rule/EliminateRowCollectRule.cpp
rule/PushLimitDownScanAppendVerticesRule.cpp
rule/GetEdgesTransformRule.cpp
rule/GetEdgesTransformLimitRule.cpp
rule/PushLimitDownScanEdgesAppendVerticesRule.cpp
rule/PushTopNDownIndexScanRule.cpp
rule/EliminateAppendVerticesRule.cpp
Expand Down
184 changes: 184 additions & 0 deletions src/graph/optimizer/rule/GetEdgesTransformLimitRule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/* Copyright (c) 2021 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#include "graph/optimizer/rule/GetEdgesTransformLimitRule.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> GetEdgesTransformLimitRule::kInstance =
std::unique_ptr<GetEdgesTransformLimitRule>(new GetEdgesTransformLimitRule());

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

const Pattern &GetEdgesTransformLimitRule::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 GetEdgesTransformLimitRule::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> GetEdgesTransformLimitRule::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);
newScanEdgesGroupNode->setDeps(scanVerticesGroupNode->dependencies());

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

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

/*static*/ graph::ScanEdges *GetEdgesTransformLimitRule::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 *GetEdgesTransformLimitRule::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
Expand Up @@ -3,8 +3,8 @@
* This source code is licensed under Apache 2.0 License.
*/

#ifndef GRAPH_OPTIMIZER_RULE_GETEDGESTRANSFORMRULE_H
#define GRAPH_OPTIMIZER_RULE_GETEDGESTRANSFORMRULE_H
#ifndef GRAPH_OPTIMIZER_RULE_GETEDGESTRANSFORMLIMITRULE_H
#define GRAPH_OPTIMIZER_RULE_GETEDGESTRANSFORMLIMITRULE_H

#include "graph/optimizer/OptRule.h"

Expand All @@ -24,12 +24,19 @@ namespace opt {
// 1. Match the pattern
// Benefits:
// 1. Avoid doing Traverse to optimize performance
// Quey example:
// 1. match ()-[e]->() return e limit 3
// Query example:
// 1. match ()-[e]->() return e limit 1
//
// Tranformation:
// Before:
//
// +---------+---------+
// | Project |
// +---------+---------+
// |
// +---------+---------+
// | Limit |
// +---------+---------+
// |
// +---------+---------+
// | AppendVertices |
// +---------+---------+
Expand All @@ -43,7 +50,14 @@ namespace opt {
// +---------+---------+
//
// After:
//
// +---------+---------+
// | Project |
// +---------+---------+
// |
// +---------+---------+
// | Limit |
// +---------+---------+
// |
// +---------+---------+
// | AppendVertices |
// +---------+---------+
Expand All @@ -56,7 +70,7 @@ namespace opt {
// | ScanEdges |
// +---------+---------+

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

Expand All @@ -66,9 +80,10 @@ class GetEdgesTransformRule final : public OptRule {
std::string toString() const override;

private:
GetEdgesTransformRule();
GetEdgesTransformLimitRule();

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

static graph::Project *projectEdges(graph::QueryContext *qctx,
graph::PlanNode *input,
Expand Down
Loading

0 comments on commit 3723280

Please sign in to comment.