Skip to content
This repository has been archived by the owner on Dec 1, 2022. It is now read-only.

add path filter #1091

Merged
merged 10 commits into from
Jun 11, 2021
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
3 changes: 0 additions & 3 deletions src/context/Iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,9 +748,6 @@ std::ostream& operator<<(std::ostream& os, Iterator::Kind kind) {
case Iterator::Kind::kGetNeighbors:
os << "get neighbors";
break;
case Iterator::Kind::kJoin:
os << "join";
break;
case Iterator::Kind::kProp:
os << "Prop";
break;
Expand Down
9 changes: 2 additions & 7 deletions src/context/Iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class Iterator {
kDefault,
kGetNeighbors,
kSequential,
kJoin,
kProp,
};

Expand Down Expand Up @@ -103,10 +102,6 @@ class Iterator {
return kind_ == Kind::kSequential;
}

bool isJoinIter() const {
return kind_ == Kind::kJoin;
}

bool isPropIter() const {
return kind_ == Kind::kProp;
}
Expand Down Expand Up @@ -270,9 +265,9 @@ class GetNeighborsIter final : public Iterator {
// Its unique based on the GN interface dedup
List getEdges();

// only return currentEdge, not currentRow, for test
const Row* row() const override {
DCHECK(false);
return nullptr;
return currentEdge_;
}

private:
Expand Down
3 changes: 3 additions & 0 deletions src/context/ast/QueryAstContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "common/base/Base.h"
#include "common/expression/Expression.h"
#include "context/ast/AstContext.h"
#include "visitor/DeducePropsVisitor.h"

namespace nebula {
namespace graph {
Expand Down Expand Up @@ -42,6 +43,7 @@ struct PathContext final : AstContext {
Starts to;
StepClause steps;
Over over;
Expression* filter{nullptr};

/*
* find path from A to B OR find path from $-.src to $-.dst
Expand Down Expand Up @@ -70,6 +72,7 @@ struct PathContext final : AstContext {
// just for pipe sentence,
// store the result of the previous sentence
std::string inputVarName;
ExpressionProps exprProps;
};

} // namespace graph
Expand Down
3 changes: 2 additions & 1 deletion src/optimizer/rule/PushFilterDownGetNbrsRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ std::unique_ptr<OptRule> PushFilterDownGetNbrsRule::kInstance =
std::unique_ptr<PushFilterDownGetNbrsRule>(new PushFilterDownGetNbrsRule());

PushFilterDownGetNbrsRule::PushFilterDownGetNbrsRule() {
RuleSet::QueryRules().addRule(this);
// There is a problem with the push-down of the storage layer filtering
// RuleSet::QueryRules().addRule(this);
}

const Pattern &PushFilterDownGetNbrsRule::pattern() const {
Expand Down
8 changes: 4 additions & 4 deletions src/parser/TraverseSentences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,15 @@ std::string FindPathSentence::toString() const {
buf += over_->toString();
buf += " ";
}
if (where_ != nullptr) {
buf += where_->toString();
buf += " ";
}
if (step_ != nullptr) {
buf += "UPTO ";
buf += step_->toString();
buf += " ";
}
if (where_ != nullptr) {
buf += where_->toString();
buf += " ";
}
return buf;
}

Expand Down
21 changes: 9 additions & 12 deletions src/parser/parser.yy
Original file line number Diff line number Diff line change
Expand Up @@ -1937,34 +1937,31 @@ fetch_sentence
;

find_path_sentence
: KW_FIND KW_ALL KW_PATH opt_with_properites from_clause to_clause over_clause find_path_upto_clause
/* where_clause */ {
: KW_FIND KW_ALL KW_PATH opt_with_properites from_clause to_clause over_clause where_clause find_path_upto_clause {
auto *s = new FindPathSentence(false, $4, false);
s->setFrom($5);
s->setTo($6);
s->setOver($7);
s->setStep($8);
/* s->setWhere($9); */
s->setWhere($8);
s->setStep($9);
$$ = s;
}
| KW_FIND KW_SHORTEST KW_PATH opt_with_properites from_clause to_clause over_clause find_path_upto_clause
/* where_clause */ {
| KW_FIND KW_SHORTEST KW_PATH opt_with_properites from_clause to_clause over_clause where_clause find_path_upto_clause {
auto *s = new FindPathSentence(true, $4, false);
s->setFrom($5);
s->setTo($6);
s->setOver($7);
s->setStep($8);
/* s->setWhere($9); */
s->setWhere($8);
s->setStep($9);
$$ = s;
}
| KW_FIND KW_NOLOOP KW_PATH opt_with_properites from_clause to_clause over_clause find_path_upto_clause
/* where_clause */ {
| KW_FIND KW_NOLOOP KW_PATH opt_with_properites from_clause to_clause over_clause where_clause find_path_upto_clause {
auto *s = new FindPathSentence(false, $4, true);
s->setFrom($5);
s->setTo($6);
s->setOver($7);
s->setStep($8);
/* s->setWhere($9) */
s->setWhere($8);
s->setStep($9);
$$ = s;
}
;
Expand Down
39 changes: 35 additions & 4 deletions src/planner/ngql/PathPlanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,24 @@ GetNeighbors::EdgeProps PathPlanner::buildEdgeProps(bool reverse) {
void PathPlanner::doBuildEdgeProps(GetNeighbors::EdgeProps& edgeProps,
bool reverse,
bool isInEdge) {
const auto& exprProps = pathCtx_->exprProps;
for (const auto& e : pathCtx_->over.edgeTypes) {
storage::cpp2::EdgeProp ep;
if (reverse == isInEdge) {
ep.set_type(e);
} else {
ep.set_type(-e);
}
ep.set_props({kDst, kType, kRank});
const auto& found = exprProps.edgeProps().find(e);
if (found == exprProps.edgeProps().end()) {
ep.set_props({kDst, kType, kRank});
} else {
std::set<std::string> props(found->second.begin(), found->second.end());
props.emplace(kDst);
props.emplace(kType);
props.emplace(kRank);
ep.set_props(std::vector<std::string>(props.begin(), props.end()));
}
edgeProps->emplace_back(std::move(ep));
}
}
Expand Down Expand Up @@ -214,7 +224,14 @@ PlanNode* PathPlanner::singlePairPath(PlanNode* dep, bool reverse) {
gn->setInputVar(vidsVar);
gn->setDedup();

auto* path = BFSShortestPath::make(qctx, gn);
PlanNode* pathDep = gn;
if (pathCtx_->filter != nullptr) {
auto* filterExpr = qctx->objPool()->add(pathCtx_->filter->clone().release());
auto* filter = Filter::make(qctx, gn, filterExpr);
pathDep = filter;
}

auto* path = BFSShortestPath::make(qctx, pathDep);
path->setOutputVar(vidsVar);
path->setColNames({kVid, kEdgeStr});

Expand Down Expand Up @@ -264,7 +281,14 @@ PlanNode* PathPlanner::allPairPath(PlanNode* dep, bool reverse) {
gn->setInputVar(vidsVar);
gn->setDedup();

auto* path = ProduceAllPaths::make(qctx, gn);
PlanNode* pathDep = gn;
if (pathCtx_->filter != nullptr) {
auto* filterExpr = qctx->objPool()->add(pathCtx_->filter->clone().release());
auto* filter = Filter::make(qctx, gn, filterExpr);
pathDep = filter;
}

auto* path = ProduceAllPaths::make(qctx, pathDep);
path->setOutputVar(vidsVar);
path->setColNames({kVid, kPathStr});
return path;
Expand Down Expand Up @@ -309,7 +333,14 @@ PlanNode* PathPlanner::multiPairPath(PlanNode* dep, bool reverse) {
gn->setInputVar(vidsVar);
gn->setDedup();

auto* path = ProduceSemiShortestPath::make(qctx, gn);
PlanNode* pathDep = gn;
if (pathCtx_->filter != nullptr) {
auto* filterExpr = qctx->objPool()->add(pathCtx_->filter->clone().release());
auto* filter = Filter::make(qctx, gn, filterExpr);
pathDep = filter;
}

auto* path = ProduceSemiShortestPath::make(qctx, pathDep);
path->setOutputVar(vidsVar);
path->setColNames({kDst, kSrc, kCostStr, kPathStr});

Expand Down
37 changes: 37 additions & 0 deletions src/validator/FindPathValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,50 @@ Status FindPathValidator::validateImpl() {
pathCtx_->noLoop = fpSentence->noLoop();
pathCtx_->withProp = fpSentence->withProperites();
pathCtx_->inputVarName = inputVarName_;

NG_RETURN_IF_ERROR(validateStarts(fpSentence->from(), pathCtx_->from));
NG_RETURN_IF_ERROR(validateStarts(fpSentence->to(), pathCtx_->to));
NG_RETURN_IF_ERROR(validateOver(fpSentence->over(), pathCtx_->over));
NG_RETURN_IF_ERROR(validateWhere(fpSentence->where()));
NG_RETURN_IF_ERROR(validateStep(fpSentence->step(), pathCtx_->steps));

outputs_.emplace_back("path", Value::Type::PATH);
return Status::OK();
}

Status FindPathValidator::validateWhere(WhereClause* where) {
if (where == nullptr) {
return Status::OK();
}
// Not Support $-、$var、$$.tag.prop、$^.tag.prop、agg
auto expr = where->filter();
if (ExpressionUtils::findAny(expr,
{Expression::Kind::kAggregate,
Expression::Kind::kSrcProperty,
Expression::Kind::kDstProperty,
Expression::Kind::kVarProperty,
Expression::Kind::kInputProperty})) {
return Status::SemanticError("Not support `%s' in where sentence.",
expr->toString().c_str());
}
where->setFilter(ExpressionUtils::rewriteLabelAttr2EdgeProp(expr));
auto filter = where->filter();

auto typeStatus = deduceExprType(filter);
NG_RETURN_IF_ERROR(typeStatus);
auto type = typeStatus.value();
if (type != Value::Type::BOOL && type != Value::Type::NULLVALUE &&
type != Value::Type::__EMPTY__) {
std::stringstream ss;
ss << "`" << filter->toString() << "', expected Boolean, "
<< "but was `" << type << "'";
return Status::SemanticError(ss.str());
}

NG_RETURN_IF_ERROR(deduceProps(filter, pathCtx_->exprProps));
pathCtx_->filter = filter;
return Status::OK();
}

} // namespace graph
} // namespace nebula
2 changes: 2 additions & 0 deletions src/validator/FindPathValidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class FindPathValidator final : public TraversalValidator {
return pathCtx_.get();
}

Status validateWhere(WhereClause* where);

private:
std::unique_ptr<PathContext> pathCtx_;
};
Expand Down
65 changes: 65 additions & 0 deletions src/validator/test/FindPathValidatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,71 @@ TEST_F(FindPathValidatorTest, RunTimePath) {
}
}

TEST_F(FindPathValidatorTest, PathWithFilter) {
{
std::string query =
"FIND ALL PATH FROM \"1\" TO \"2\" OVER like WHERE like.likeness > 30 UPTO 5 STEPS";
std::vector<PlanNode::Kind> expected = {
PK::kDataCollect,
PK::kLoop,
PK::kProject,
PK::kConjunctPath,
PK::kProject,
PK::kProduceAllPaths,
PK::kProduceAllPaths,
PK::kStart,
PK::kFilter,
PK::kFilter,
PK::kGetNeighbors,
PK::kGetNeighbors,
PK::kPassThrough,
PK::kStart,
};
EXPECT_TRUE(checkResult(query, expected));
}
{
std::string query = "FIND SHORTEST PATH FROM \"1\" TO \"2\" OVER like WHERE like.likeness "
"> 30 UPTO 5 STEPS";
std::vector<PlanNode::Kind> expected = {
PK::kDataCollect,
PK::kLoop,
PK::kStart,
PK::kConjunctPath,
PK::kBFSShortest,
PK::kBFSShortest,
PK::kFilter,
PK::kFilter,
PK::kGetNeighbors,
PK::kGetNeighbors,
PK::kPassThrough,
PK::kStart,
};
EXPECT_TRUE(checkResult(query, expected));
}
{
std::string query = "FIND SHORTEST PATH FROM \"1\" TO \"2\", \"3\" OVER like WHERE "
"like.likeness > 30 UPTO 5 STEPS";
std::vector<PlanNode::Kind> expected = {
PK::kDataCollect,
PK::kLoop,
PK::kCartesianProduct,
PK::kConjunctPath,
PK::kProject,
PK::kProduceSemiShortestPath,
PK::kProduceSemiShortestPath,
PK::kProject,
PK::kFilter,
PK::kFilter,
PK::kStart,
PK::kGetNeighbors,
PK::kGetNeighbors,
PK::kPassThrough,
PK::kStart,
};
EXPECT_TRUE(checkResult(query, expected));
}
}

} // namespace graph
} // namespace nebula

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# This source code is licensed under Apache 2.0 License,
# attached with Common Clause Condition 1.0, found in the LICENSES directory.
@skip
Feature: Push Filter down GetNeighbors rule

Background:
Expand Down
32 changes: 32 additions & 0 deletions tests/tck/features/path/AllPath.IntVid.feature
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,35 @@ Feature: Integer Vid All Path
| <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> |
| <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Manu Ginobili" :player{age: 41, name: "Manu Ginobili"})-[:like@0 {likeness: 90}]->("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> |
| <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})-[:like@0 {likeness: 90}]->("LaMarcus Aldridge" :player{age: 33, name: "LaMarcus Aldridge"})-[:like@0 {likeness: 75}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> |

Scenario: Integer Vid ALL Path WITH FILTER
When executing query:
"""
FIND ALL PATH WITH PROP FROM hash("Tim Duncan") TO hash("Yao Ming") OVER * BIDIRECT
WHERE (like.likeness >= 80 and like.likeness <= 90) OR (teammate.start_year is not EMPTY and teammate.start_year > 2001) UPTO 3 STEPS
"""
Then the result should be, in any order, with relax comparison:
| path |
| <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})<-[:like@0 {likeness: 80}]-("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})<-[:like@0 {likeness: 90}]-("Yao Ming" :player{age: 38, name: "Yao Ming"})> |
When executing query:
"""
FIND ALL PATH WITH PROP FROM hash("Tony Parker") TO hash("Yao Ming") OVER * BIDIRECT
WHERE teammate.start_year > 2000 OR (like.likeness is not EMPTY AND like.likeness >= 80) UPTO 3 STEPS
"""
Then the result should be, in any order, with relax comparison:
| path |
| <("Tony Parker" :player{age: 36, name: "Tony Parker"})<-[:like@0 {likeness: 95}]-("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})<-[:like@0 {likeness: 80}]-("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})<-[:like@0 {likeness: 90}]-("Yao Ming" :player{age: 38, name: "Yao Ming"})> |
| <("Tony Parker" :player{age: 36, name: "Tony Parker"})<-[:teammate@0 {end_year: 2016, start_year: 2001}]-("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})<-[:like@0 {likeness: 80}]-("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})<-[:like@0 {likeness: 90}]-("Yao Ming" :player{age: 38, name: "Yao Ming"})> |
| <("Tony Parker" :player{age: 36, name: "Tony Parker"})-[:like@0 {likeness: 95}]->("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})<-[:like@0 {likeness: 80}]-("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})<-[:like@0 {likeness: 90}]-("Yao Ming" :player{age: 38, name: "Yao Ming"})> |
| <("Tony Parker" :player{age: 36, name: "Tony Parker"})-[:teammate@0 {end_year: 2016, start_year: 2001}]->("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})<-[:like@0 {likeness: 80}]-("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})<-[:like@0 {likeness: 90}]-("Yao Ming" :player{age: 38, name: "Yao Ming"})> |
When executing query:
"""
FIND ALL PATH WITH PROP FROM hash("Yao Ming") TO hash("Danny Green") OVER * BIDIRECT
WHERE like.likeness is EMPTY OR like.likeness >= 80 UPTO 3 STEPS
"""
Then the result should be, in any order, with relax comparison:
| path |
| <("Yao Ming" :player{age: 38, name: "Yao Ming"})-[:like@0 {likeness: 90}]->("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})-[:serve@0 {end_year: 2010, start_year: 2009}]->("Cavaliers" :team{name: "Cavaliers"})<-[:serve@0 {end_year: 2010, start_year: 2009}]-("Danny Green" :player{age: 31, name: "Danny Green"})> |
| <("Yao Ming" :player{age: 38, name: "Yao Ming"})-[:like@0 {likeness: 90}]->("Shaquile O'Neal" :player{age: 47, name: "Shaquile O'Neal"})-[:like@0 {likeness: 80}]->("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:teammate@0 {end_year: 2016, start_year: 2010}]->("Danny Green" :player{age: 31, name: "Danny Green"})> |
| <("Yao Ming" :player{age: 38, name: "Yao Ming"})-[:like@0 {likeness: 90}]->("Tracy McGrady" :player{age: 39, name: "Tracy McGrady"})-[:serve@0 {end_year: 2000, start_year: 1997}]->("Raptors" :team{name: "Raptors"})<-[:serve@0 {end_year: 2019, start_year: 2018}]-("Danny Green" :player{age: 31, name: "Danny Green"})> |
| <("Yao Ming" :player{age: 38, name: "Yao Ming"})-[:like@0 {likeness: 90}]->("Tracy McGrady" :player{age: 39, name: "Tracy McGrady"})-[:serve@0 {end_year: 2013, start_year: 2013}]->("Spurs" :team{name: "Spurs"})<-[:serve@0 {end_year: 2018, start_year: 2010}]-("Danny Green" :player{age: 31, name: "Danny Green"})> |
Loading