Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

push limit down index scan #5019

Merged
merged 3 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions src/graph/optimizer/rule/PushLimitDownScanAppendVerticesRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "graph/planner/plan/Query.h"

using nebula::graph::AppendVertices;
using nebula::graph::Explore;
using nebula::graph::IndexScan;
using nebula::graph::Limit;
using nebula::graph::PlanNode;
using nebula::graph::QueryContext;
Expand All @@ -19,7 +21,8 @@ using nebula::graph::ScanVertices;
namespace nebula {
namespace opt {

// Limit->AppendVertices->ScanVertices ==> Limit->AppendVertices->ScanVertices(Limit)
// Limit->AppendVertices->ScanVertices/IndexScan ==>
// Limit->AppendVertices->ScanVertices/IndexScan(Limit)

std::unique_ptr<OptRule> PushLimitDownScanAppendVerticesRule::kInstance =
std::unique_ptr<PushLimitDownScanAppendVerticesRule>(new PushLimitDownScanAppendVerticesRule());
Expand All @@ -32,7 +35,8 @@ const Pattern &PushLimitDownScanAppendVerticesRule::pattern() const {
static Pattern pattern =
Pattern::create(graph::PlanNode::Kind::kLimit,
{Pattern::create(graph::PlanNode::Kind::kAppendVertices,
{Pattern::create(graph::PlanNode::Kind::kScanVertices)})});
{Pattern::create({graph::PlanNode::Kind::kScanVertices,
graph::PlanNode::Kind::kIndexScan})})});
return pattern;
}

Expand All @@ -53,8 +57,22 @@ bool PushLimitDownScanAppendVerticesRule::match(OptContext *ctx,
}
auto *filter = av->filter();
auto *vFilter = av->vFilter();
// Limit can't push over filter operation
return filter == nullptr && vFilter == nullptr;

if (vFilter != nullptr) return false;
if (filter == nullptr) return true;
auto scanNode = matched.planNode({0, 0, 0});
if (scanNode->kind() == PlanNode::Kind::kScanVertices) return false;
// If the scanNode is kIndexScan, and the filter looks like `player._tag IS NOT EMPTY`,
// the limit could also be pushed down
if (filter->kind() != Expression::Kind::kIsNotEmpty) {
return false;
}
auto *isNotEmpty = static_cast<const UnaryExpression *>(filter);
auto *operand = isNotEmpty->operand();
if (operand->kind() != Expression::Kind::kTagProperty) {
return false;
}
return true;
Comment on lines +63 to +75
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be cautious about adding these case-by-case codes.

}

StatusOr<OptRule::TransformResult> PushLimitDownScanAppendVerticesRule::transform(
Expand All @@ -65,7 +83,7 @@ StatusOr<OptRule::TransformResult> PushLimitDownScanAppendVerticesRule::transfor

const auto limit = static_cast<const Limit *>(limitGroupNode->node());
const auto appendVertices = static_cast<const AppendVertices *>(appendVerticesGroupNode->node());
const auto scanVertices = static_cast<const ScanVertices *>(scanVerticesGroupNode->node());
const auto scanVertices = static_cast<const Explore *>(scanVerticesGroupNode->node());

int64_t limitRows = limit->offset() + limit->count();
if (scanVertices->limit() >= 0 && limitRows >= scanVertices->limit()) {
Expand All @@ -80,7 +98,7 @@ StatusOr<OptRule::TransformResult> PushLimitDownScanAppendVerticesRule::transfor
auto newAppendVerticesGroup = OptGroup::create(octx);
auto newAppendVerticesGroupNode = newAppendVerticesGroup->makeGroupNode(newAppendVertices);

auto newScanVertices = static_cast<ScanVertices *>(scanVertices->clone());
auto newScanVertices = static_cast<Explore *>(scanVertices->clone());
newScanVertices->setLimit(limitRows);
auto newScanVerticesGroup = OptGroup::create(octx);
auto newScanVerticesGroupNode = newScanVerticesGroup->makeGroupNode(newScanVertices);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ namespace opt {
// | AppendVertices |
// +---------+---------+
// |
// +---------+---------+
// | ScanVertices |
// +---------+---------+
// +---------+-------------------+
// | ScanVertices/IndexScan |
// +---------+-------------------+
//
// After:
//
Expand All @@ -47,6 +47,7 @@ namespace opt {
// |
// +---------+---------+
// | ScanVertices |
// |    IndexScan |
// | (limit=3) |
// +---------+---------+

Expand Down
22 changes: 22 additions & 0 deletions tests/tck/features/match/Base.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@ Feature: Basic match
Then the result should be, in any order, with relax comparison:
| v |
| ("Yao Ming") |
When profiling query:
"""
MATCH (v:player) RETURN v.player.age LIMIT 3
"""
Then the result should be, in any order, with relax comparison:
| v.player.age |
| /\d+/ |
| /\d+/ |
| /\d+/ |
Then the execution plan should be:
| id | name | dependencies | operator info |
| 5 | Project | 4 | |
| 4 | Limit | 3 | {"offset": "0", "count": "3"} |
| 3 | AppendVertices | 2 | |
| 2 | IndexScan | 1 | {"limit": "3"} |
| 1 | Start | | |
When executing query:
"""
MATCH (v:player) WHERE v.player.age < 0 RETURN v
Expand Down Expand Up @@ -629,6 +645,12 @@ Feature: Basic match
MATCH (v:player:bachelor) RETURN v
"""
Then a ExecutionError should be raised at runtime: Scan vertices or edges need to specify a limit number, or limit number can not push down.
# TODO(jie): Optimize this case
When executing query:
"""
MATCH (v) WHERE v.player.age == 18 RETURN v LIMIT 3
"""
Then a ExecutionError should be raised at runtime: Scan vertices or edges need to specify a limit number, or limit number can not push down.
When executing query:
"""
MATCH (v:player{age:23}:bachelor) RETURN v
Expand Down