-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove useless AppendVertices. (#4277)
* Remove useless AppendVertices. * Add function to check anonymous variable.
- Loading branch information
1 parent
8a4921c
commit fba3b18
Showing
9 changed files
with
316 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// Copyright (c) 2022 vesoft inc. All rights reserved. | ||
// | ||
// This source code is licensed under Apache 2.0 License. | ||
|
||
#include "graph/optimizer/rule/EliminateAppendVerticesRule.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/util/ExpressionUtils.h" | ||
|
||
using nebula::graph::AppendVertices; | ||
using nebula::graph::PlanNode; | ||
using nebula::graph::Project; | ||
using nebula::graph::QueryContext; | ||
|
||
namespace nebula { | ||
namespace opt { | ||
|
||
// TODO If we prune properties in Optimizer Rules, we could check properties of AppendVertices, | ||
// and drop AppendVertices if it has no properties directly. | ||
std::unique_ptr<OptRule> EliminateAppendVerticesRule::kInstance = | ||
std::unique_ptr<EliminateAppendVerticesRule>(new EliminateAppendVerticesRule()); | ||
|
||
EliminateAppendVerticesRule::EliminateAppendVerticesRule() { | ||
RuleSet::QueryRules().addRule(this); | ||
} | ||
|
||
const Pattern& EliminateAppendVerticesRule::pattern() const { | ||
static Pattern pattern = Pattern::create( | ||
graph::PlanNode::Kind::kProject, {Pattern::create(graph::PlanNode::Kind::kAppendVertices)}); | ||
return pattern; | ||
} | ||
|
||
bool EliminateAppendVerticesRule::match(OptContext* octx, const MatchedResult& matched) const { | ||
if (!OptRule::match(octx, matched)) { | ||
return false; | ||
} | ||
const auto* project = static_cast<const Project*>(matched.planNode({0})); | ||
DCHECK_EQ(project->kind(), graph::PlanNode::Kind::kProject); | ||
for (const auto& col : project->columns()->columns()) { | ||
const auto* expr = graph::ExpressionUtils::findAny(col->expr(), {Expression::Kind::kPathBuild}); | ||
if (expr != nullptr) { | ||
return false; | ||
} | ||
} | ||
const auto* appendVertices = static_cast<const AppendVertices*>(matched.planNode({0, 0})); | ||
DCHECK_EQ(appendVertices->kind(), graph::PlanNode::Kind::kAppendVertices); | ||
if (appendVertices->vFilter() != nullptr || appendVertices->filter() != nullptr) { | ||
return false; | ||
} | ||
if (!graph::AnonVarGenerator::isAnnoVar(appendVertices->colNames().back())) { // Anonymous node | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
StatusOr<OptRule::TransformResult> EliminateAppendVerticesRule::transform( | ||
OptContext* octx, const MatchedResult& matched) const { | ||
auto projectGroupNode = matched.node; | ||
auto appendVerticesGroupNode = matched.dependencies.front().node; | ||
|
||
const auto project = static_cast<const Project*>(projectGroupNode->node()); | ||
const auto appendVertices = static_cast<const AppendVertices*>(appendVerticesGroupNode->node()); | ||
|
||
auto newProj = static_cast<Project*>(project->clone()); | ||
newProj->setOutputVar(project->outputVar()); | ||
newProj->setInputVar(appendVertices->inputVar()); | ||
auto newProjGroupNode = OptGroupNode::create(octx, newProj, projectGroupNode->group()); | ||
newProjGroupNode->setDeps(appendVerticesGroupNode->dependencies()); | ||
|
||
TransformResult result; | ||
result.eraseAll = true; | ||
result.newGroupNodes.emplace_back(newProjGroupNode); | ||
return result; | ||
} | ||
|
||
std::string EliminateAppendVerticesRule::toString() const { | ||
return "EliminateAppendVerticesRule"; | ||
} | ||
|
||
} // namespace opt | ||
} // namespace nebula |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Copyright (c) 2022 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 opt { | ||
|
||
// Eliminate useless AppendVertices node | ||
class EliminateAppendVerticesRule 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: | ||
EliminateAppendVerticesRule(); | ||
|
||
static std::unique_ptr<OptRule> kInstance; | ||
}; | ||
|
||
} // namespace opt | ||
} // namespace nebula |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) 2022 vesoft inc. All rights reserved. | ||
// | ||
// This source code is licensed under Apache 2.0 License. | ||
|
||
#include "graph/optimizer/rule/PushLimitDownScanEdgesRule.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/util/ExpressionUtils.h" | ||
|
||
using nebula::graph::Limit; | ||
using nebula::graph::PlanNode; | ||
using nebula::graph::QueryContext; | ||
using nebula::graph::ScanEdges; | ||
|
||
namespace nebula { | ||
namespace opt { | ||
|
||
std::unique_ptr<OptRule> PushLimitDownScanEdgesRule::kInstance = | ||
std::unique_ptr<PushLimitDownScanEdgesRule>(new PushLimitDownScanEdgesRule()); | ||
|
||
PushLimitDownScanEdgesRule::PushLimitDownScanEdgesRule() { | ||
RuleSet::QueryRules().addRule(this); | ||
} | ||
|
||
const Pattern &PushLimitDownScanEdgesRule::pattern() const { | ||
static Pattern pattern = Pattern::create(graph::PlanNode::Kind::kLimit, | ||
{Pattern::create(graph::PlanNode::Kind::kScanEdges)}); | ||
return pattern; | ||
} | ||
|
||
StatusOr<OptRule::TransformResult> PushLimitDownScanEdgesRule::transform( | ||
OptContext *octx, const MatchedResult &matched) const { | ||
auto *qctx = octx->qctx(); | ||
auto limitGroupNode = matched.node; | ||
auto seGroupNode = matched.dependencies.front().node; | ||
|
||
const auto limit = static_cast<const Limit *>(limitGroupNode->node()); | ||
const auto se = static_cast<const ScanEdges *>(seGroupNode->node()); | ||
|
||
if (!graph::ExpressionUtils::isEvaluableExpr(limit->countExpr())) { | ||
return TransformResult::noTransform(); | ||
} | ||
int64_t limitRows = limit->offset() + limit->count(qctx); | ||
if (se->limit(qctx) >= 0 && limitRows >= se->limit(qctx)) { | ||
return TransformResult::noTransform(); | ||
} | ||
|
||
auto newLimit = static_cast<Limit *>(limit->clone()); | ||
newLimit->setOutputVar(limit->outputVar()); | ||
auto newLimitGroupNode = OptGroupNode::create(octx, newLimit, limitGroupNode->group()); | ||
|
||
auto newSe = static_cast<ScanEdges *>(se->clone()); | ||
newSe->setLimit(limitRows); | ||
auto newSeGroup = OptGroup::create(octx); | ||
auto newSeGroupNode = newSeGroup->makeGroupNode(newSe); | ||
|
||
newLimitGroupNode->dependsOn(newSeGroup); | ||
newLimit->setInputVar(newSe->outputVar()); | ||
for (auto dep : seGroupNode->dependencies()) { | ||
newSeGroupNode->dependsOn(dep); | ||
} | ||
|
||
TransformResult result; | ||
result.eraseAll = true; | ||
result.newGroupNodes.emplace_back(newLimitGroupNode); | ||
return result; | ||
} | ||
|
||
std::string PushLimitDownScanEdgesRule::toString() const { | ||
return "PushLimitDownScanEdgesRule"; | ||
} | ||
|
||
} // namespace opt | ||
} // namespace nebula |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright (c) 2022 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 opt { | ||
|
||
// Embedding limit to [[ScanEdges]] | ||
// Required conditions: | ||
// 1. Match the pattern | ||
// Benefits: | ||
// 1. Limit data early to optimize performance | ||
// | ||
// Transformation: | ||
// Before: | ||
// | ||
// +--------+--------+ | ||
// | Limit | | ||
// | (limit=3) | | ||
// +--------+--------+ | ||
// | | ||
// +---------+---------+ | ||
// | ScanEdges | | ||
// +---------+---------+ | ||
// | ||
// After: | ||
// | ||
// +--------+--------+ | ||
// | Limit | | ||
// | (limit=3) | | ||
// +--------+--------+ | ||
// | | ||
// +---------+---------+ | ||
// | ScanEdges | | ||
// | (limit=3) | | ||
// +---------+---------+ | ||
|
||
class PushLimitDownScanEdgesRule final : public OptRule { | ||
public: | ||
const Pattern &pattern() const override; | ||
|
||
StatusOr<OptRule::TransformResult> transform(OptContext *ctx, | ||
const MatchedResult &matched) const override; | ||
|
||
std::string toString() const override; | ||
|
||
private: | ||
PushLimitDownScanEdgesRule(); | ||
|
||
static std::unique_ptr<OptRule> kInstance; | ||
}; | ||
|
||
} // namespace opt | ||
} // namespace nebula |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
tests/tck/features/optimizer/EliminateAppendVerticesRule.feature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Copyright (c) 2022 vesoft inc. All rights reserved. | ||
# | ||
# This source code is licensed under Apache 2.0 License. | ||
Feature: Eliminate AppendVertices rule | ||
|
||
Background: Prepare space | ||
Given a graph with space named "nba" | ||
|
||
Scenario: eliminate AppendVertices | ||
When profiling query: | ||
""" | ||
MATCH (v:player{name: 'Tim Duncan'})-[e:like{likeness: 95}]->() return v.player.name AS name | ||
""" | ||
Then the result should be, in any order: | ||
| name | | ||
| "Tim Duncan" | | ||
| "Tim Duncan" | | ||
And the execution plan should be: | ||
| id | name | dependencies | operator info | | ||
| 5 | Project | 8 | | | ||
| 8 | Traverse | 7 | | | ||
| 7 | IndexScan | 0 | | | ||
| 0 | Start | | | | ||
|
||
Scenario: eliminate AppendVertices failed with returned path | ||
When profiling query: | ||
""" | ||
MATCH p = (v:player{name: 'Tim Duncan'})-[e:like{likeness: 95}]->() return p | ||
""" | ||
Then the result should be, in any order, with relax comparison: | ||
| p | | ||
| <("Tim Duncan")-[:like@0]->("Tony Parker")> | | ||
| <("Tim Duncan")-[:like@0]->("Manu Ginobili")> | | ||
And the execution plan should be: | ||
| id | name | dependencies | operator info | | ||
| 5 | Project | 9 | | | ||
| 9 | AppendVertices | 8 | | | ||
| 8 | Traverse | 7 | | | ||
| 7 | IndexScan | 0 | | | ||
| 0 | Start | | | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters