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

Enhancement/eliminate invalid filter #5634

Merged
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
6 changes: 4 additions & 2 deletions src/common/expression/PredicateExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ const Value& PredicateExpression::evalExists(ExpressionContext& ctx) {
DCHECK(collection_->kind() == Expression::Kind::kAttribute ||
collection_->kind() == Expression::Kind::kSubscript ||
collection_->kind() == Expression::Kind::kLabelTagProperty ||
collection_->kind() == Expression::Kind::kTagProperty)
collection_->kind() == Expression::Kind::kTagProperty ||
collection_->kind() == Expression::Kind::kConstant)
<< "actual kind: " << collection_->kind() << ", toString: " << toString();

if (collection_->kind() == Expression::Kind::kLabelTagProperty ||
collection_->kind() == Expression::Kind::kTagProperty) {
collection_->kind() == Expression::Kind::kTagProperty ||
collection_->kind() == Expression::Kind::kConstant) {
auto v = collection_->eval(ctx);
result_ = (!v.isNull()) && (!v.empty());
return result_;
Expand Down
1 change: 1 addition & 0 deletions src/graph/executor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ nebula_add_library(
query/AppendVerticesExecutor.cpp
query/RollUpApplyExecutor.cpp
query/PatternApplyExecutor.cpp
query/ValueExecutor.cpp
algo/BFSShortestPathExecutor.cpp
algo/MultiShortestPathExecutor.cpp
algo/AllPathsExecutor.cpp
Expand Down
4 changes: 4 additions & 0 deletions src/graph/executor/Executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
#include "graph/executor/query/UnionAllVersionVarExecutor.h"
#include "graph/executor/query/UnionExecutor.h"
#include "graph/executor/query/UnwindExecutor.h"
#include "graph/executor/query/ValueExecutor.h"
#include "graph/planner/plan/Admin.h"
#include "graph/planner/plan/Logic.h"
#include "graph/planner/plan/Maintain.h"
Expand Down Expand Up @@ -257,6 +258,9 @@ Executor *Executor::makeExecutor(QueryContext *qctx, const PlanNode *node) {
case PlanNode::Kind::kDedup: {
return pool->makeAndAdd<DedupExecutor>(node, qctx);
}
case PlanNode::Kind::kValue: {
return pool->makeAndAdd<ValueExecutor>(node, qctx);
}
case PlanNode::Kind::kAssign: {
return pool->makeAndAdd<AssignExecutor>(node, qctx);
}
Expand Down
21 changes: 21 additions & 0 deletions src/graph/executor/query/ValueExecutor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2023 vesoft inc. All rights reserved.
//
// This source code is licensed under Apache 2.0 License.

#include "graph/executor/query/ValueExecutor.h"

#include "graph/context/Result.h"
#include "graph/planner/plan/Query.h"
#include "graph/service/GraphFlags.h"

namespace nebula {
namespace graph {

folly::Future<Status> ValueExecutor::execute() {
SCOPED_TIMER(&execTime_);
auto value = asNode<ValueNode>(node())->value();
return finish(ResultBuilder().value(std::move(value)).build());
}

} // namespace graph
} // namespace nebula
22 changes: 22 additions & 0 deletions src/graph/executor/query/ValueExecutor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2023 vesoft inc. All rights reserved.
//
// This source code is licensed under Apache 2.0 License.

#pragma once

#include "graph/executor/Executor.h"

// delete the corresponding iterator when the row in the dataset does not meet the conditions
// and save the filtered iterator to the result
namespace nebula {
namespace graph {

class ValueExecutor final : public Executor {
public:
ValueExecutor(const PlanNode *node, QueryContext *qctx) : Executor("ValueExecutor", node, qctx) {}

folly::Future<Status> execute() override;
};

} // namespace graph
} // namespace nebula
1 change: 1 addition & 0 deletions src/graph/optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ nebula_add_library(
rule/RemoveAppendVerticesBelowJoinRule.cpp
rule/EmbedEdgeAllPredIntoTraverseRule.cpp
rule/PushFilterThroughAppendVerticesRule.cpp
rule/EliminateFilterRule.cpp
)

nebula_add_subdirectory(test)
14 changes: 14 additions & 0 deletions src/graph/optimizer/OptRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ RuleSet &RuleSet::DefaultRules() {
return kDefaultRules;
}

RuleSet &RuleSet::QueryRules0() {
static RuleSet kQueryRules0("QueryRuleSet0");
return kQueryRules0;
}

RuleSet &RuleSet::QueryRules() {
static RuleSet kQueryRules("QueryRuleSet");
return kQueryRules;
Expand All @@ -231,6 +236,15 @@ RuleSet *RuleSet::addRule(const OptRule *rule) {
return this;
}

std::string RuleSet::toString() const {
std::stringstream ss;
ss << "RuleSet: " << name_ << std::endl;
for (auto rule : rules_) {
ss << rule->toString() << std::endl;
}
return ss.str();
}

void RuleSet::merge(const RuleSet &ruleset) {
for (auto rule : ruleset.rules()) {
addRule(rule);
Expand Down
3 changes: 3 additions & 0 deletions src/graph/optimizer/OptRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class OptRule {
class RuleSet final {
public:
static RuleSet &DefaultRules();
static RuleSet &QueryRules0();
static RuleSet &QueryRules();

RuleSet *addRule(const OptRule *rule);
Expand All @@ -138,6 +139,8 @@ class RuleSet final {
return rules_;
}

std::string toString() const;

private:
explicit RuleSet(const std::string &name);

Expand Down
77 changes: 77 additions & 0 deletions src/graph/optimizer/rule/EliminateFilterRule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* Copyright (c) 2023 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

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

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

using nebula::graph::Filter;
using nebula::graph::QueryContext;
using nebula::graph::StartNode;
using nebula::graph::ValueNode;

namespace nebula {
namespace opt {

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

EliminateFilterRule::EliminateFilterRule() {
RuleSet::QueryRules0().addRule(this);
}

// TODO match Filter->(Any Node with real result)
const Pattern& EliminateFilterRule::pattern() const {
static Pattern pattern = Pattern::create(graph::PlanNode::Kind::kFilter);
return pattern;
}

bool EliminateFilterRule::match(OptContext* octx, const MatchedResult& matched) const {
if (!OptRule::match(octx, matched)) {
return false;
}
const auto* filterNode = static_cast<const Filter*>(matched.node->node());
const auto* expr = filterNode->condition();
if (expr->kind() != Expression::Kind::kConstant) {
return false;
}
const auto* constant = static_cast<const ConstantExpression*>(expr);
auto ret = (constant->value().isImplicitBool() && constant->value().getBool() == false) ||
constant->value().isNull();
return ret;
}

StatusOr<OptRule::TransformResult> EliminateFilterRule::transform(
OptContext* octx, const MatchedResult& matched) const {
auto filterGroupNode = matched.node;
auto filter = static_cast<const Filter*>(filterGroupNode->node());

auto newValue = ValueNode::make(octx->qctx(), nullptr, DataSet(filter->colNames()));
newValue->setOutputVar(filter->outputVar());
auto newValueGroupNode = OptGroupNode::create(octx, newValue, filterGroupNode->group());

auto newStart = StartNode::make(octx->qctx());
auto newStartGroup = OptGroup::create(octx);
newStartGroup->makeGroupNode(newStart);

newValueGroupNode->dependsOn(newStartGroup);

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

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

} // namespace opt
} // namespace nebula
56 changes: 56 additions & 0 deletions src/graph/optimizer/rule/EliminateFilterRule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* Copyright (c) 2023 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 [[Filter(false)]] node
// Required conditions:
// 1. Match the pattern
// 2. Filter condition is false/null
// Benefits:
// 1. Delete unnecessary node
//
// Transformation:
// Before:
//
// +------+--------+
// | Filter(false) |
// +------+--------+
// |
// +------+------+
// | ..... |
// +------+------+
//
// After:
//
// +------+------+
// | Value |
// +------+------+
// | Start |
// +------+------+

class EliminateFilterRule 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:
EliminateFilterRule();

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

} // namespace opt
} // namespace nebula
2 changes: 2 additions & 0 deletions src/graph/planner/plan/PlanNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ const char* PlanNode::toString(PlanNode::Kind kind) {
return "Loop";
case Kind::kDedup:
return "Dedup";
case Kind::kValue:
return "Value";
case Kind::kPassThrough:
return "PassThrough";
case Kind::kAssign:
Expand Down
2 changes: 2 additions & 0 deletions src/graph/planner/plan/PlanNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class PlanNode {
kScanVertices,
kScanEdges,
kFulltextIndexScan,
// direct value
kValue,

// ------------------
kFilter,
Expand Down
22 changes: 22 additions & 0 deletions src/graph/planner/plan/Query.h
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,28 @@ class PatternApply : public BinaryInputNode {
bool isAntiPred_{false};
};

class ValueNode : public SingleInputNode {
public:
// Value with empty result
static ValueNode* make(QueryContext* qctx, PlanNode* dep, DataSet value) {
return qctx->objPool()->makeAndAdd<ValueNode>(qctx, dep, std::move(value));
}

Value value() const {
return value_;
}

private:
friend ObjectPool;
ValueNode(QueryContext* qctx, PlanNode* dep, DataSet value)
: SingleInputNode(qctx, Kind::kValue, dep), value_(std::move(value)) {
setColNames(value_.colNames);
}

private:
DataSet value_;
};

} // namespace graph
} // namespace nebula
#endif // GRAPH_PLANNER_PLAN_QUERY_H_
1 change: 1 addition & 0 deletions src/graph/service/QueryEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Status QueryEngine::init(std::shared_ptr<folly::IOThreadPoolExecutor> ioExecutor
// Set default optimizer rules
std::vector<const opt::RuleSet*> rulesets{&opt::RuleSet::DefaultRules()};
if (FLAGS_enable_optimizer) {
rulesets.emplace_back(&opt::RuleSet::QueryRules0());
rulesets.emplace_back(&opt::RuleSet::QueryRules());
}
optimizer_ = std::make_unique<opt::Optimizer>(rulesets);
Expand Down
27 changes: 27 additions & 0 deletions src/graph/util/ExpressionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "graph/context/QueryExpressionContext.h"
#include "graph/visitor/FoldConstantExprVisitor.h"
#include "graph/visitor/PropertyTrackerVisitor.h"
#include "graph/visitor/RewriteVisitor.h"

DEFINE_int32(max_expression_depth, 512, "Max depth of expression tree.");

Expand Down Expand Up @@ -1712,5 +1713,31 @@ bool ExpressionUtils::isOneStepEdgeProp(const std::string &edgeAlias, const Expr
return graph::RewriteVisitor::transform(expr, matcher, rewriter);
}

/*static*/ Expression *ExpressionUtils::rewriteAlwaysNullLabelTagProperty(
ObjectPool *pool, meta::SchemaManager *schemaMan, GraphSpaceID spaceId, Expression *expr) {
auto matcher = [spaceId, schemaMan](const Expression *e) -> bool {
if (e->kind() == Expression::Kind::kLabelTagProperty) {
auto *ltpExpr = static_cast<const LabelTagPropertyExpression *>(e);
auto tagSchema = schemaMan->getTagSchema(spaceId, ltpExpr->sym());
if (tagSchema == nullptr) {
// no such tag
return true;
}
auto found = tagSchema->getFieldIndex(ltpExpr->prop());
if (found < 0) {
// no such property
return true;
}
}
return false;
};
auto rewriter = [pool](const Expression *e) -> Expression * {
DCHECK_EQ(e->kind(), Expression::Kind::kLabelTagProperty);
UNUSED(e);
return ConstantExpression::make(pool);
};
return graph::RewriteVisitor::transform(expr, matcher, rewriter);
}

} // namespace graph
} // namespace nebula
7 changes: 7 additions & 0 deletions src/graph/util/ExpressionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "common/expression/PropertyExpression.h"
#include "common/expression/TypeCastingExpression.h"
#include "common/expression/UnaryExpression.h"
#include "common/thrift/ThriftTypes.h"
#include "graph/context/ast/CypherAstContext.h"
#include "graph/visitor/EvaluableExprVisitor.h"
#include "graph/visitor/FindVisitor.h"
Expand Down Expand Up @@ -265,6 +266,12 @@ class ExpressionUtils {
static Expression* rewriteVertexPropertyFilter(ObjectPool* pool,
const std::string& node,
Expression* expr);

// label.not_exists_tag.prop => null
static Expression* rewriteAlwaysNullLabelTagProperty(ObjectPool* pool,
meta::SchemaManager* schemaMan,
GraphSpaceID spaceId,
Expression* expr);
};

} // namespace graph
Expand Down
Loading