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

Commit

Permalink
add path filter
Browse files Browse the repository at this point in the history
  • Loading branch information
nevermore3 committed Jun 1, 2021
1 parent 28f9cf1 commit c610874
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 30 deletions.
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
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 @@ -1929,34 +1929,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
63 changes: 59 additions & 4 deletions src/planner/ngql/PathPlanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@

namespace nebula {
namespace graph {
GetNeighbors::VertexProps PathPlanner::buildSrcVertexProps() {
GetNeighbors::VertexProps vertexProps;
auto& srcTagProps = pathCtx_->exprProps.srcTagProps();
if (srcTagProps.empty()) {
return vertexProps;
}
vertexProps = std::make_unique<std::vector<storage::cpp2::VertexProp>>(srcTagProps.size());
auto fun = [] (auto& tag) {
storage::cpp2::VertexProp vp;
vp.set_tag(tag.first);
std::vector<std::string>props(tag.second.begin(), tag.second.end());
vp.set_props(std::move(props));
return vp;
};
std::transform(srcTagProps.begin(), srcTagProps.end(), vertexProps->begin(), fun);
return vertexProps;
}

GetNeighbors::EdgeProps PathPlanner::buildEdgeProps(bool reverse) {
auto edgeProps = std::make_unique<std::vector<storage::cpp2::EdgeProp>>();
switch (pathCtx_->over.direction) {
Expand All @@ -36,14 +54,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 @@ -208,13 +236,22 @@ PlanNode* PathPlanner::singlePairPath(PlanNode* dep, bool reverse) {
auto qctx = pathCtx_->qctx;
auto* src = qctx->objPool()->add(new ColumnExpression(0));

PlanNode* pathDep = nullptr;
auto* gn = GetNeighbors::make(qctx, dep, pathCtx_->space.id);
gn->setSrc(src);
gn->setVertexProps(buildSrcVertexProps());
gn->setEdgeProps(buildEdgeProps(reverse));
gn->setInputVar(vidsVar);
gn->setDedup();
pathDep = gn;

auto* path = BFSShortestPath::make(qctx, 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 @@ -258,13 +295,22 @@ PlanNode* PathPlanner::allPairPath(PlanNode* dep, bool reverse) {
auto qctx = pathCtx_->qctx;
auto* src = qctx->objPool()->add(new ColumnExpression(0));

PlanNode* pathDep = nullptr;
auto* gn = GetNeighbors::make(qctx, dep, pathCtx_->space.id);
gn->setSrc(src);
gn->setVertexProps(buildSrcVertexProps());
gn->setEdgeProps(buildEdgeProps(reverse));
gn->setInputVar(vidsVar);
gn->setDedup();
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, gn);
auto* path = ProduceAllPaths::make(qctx, pathDep);
path->setOutputVar(vidsVar);
path->setColNames({kVid, kPathStr});
return path;
Expand Down Expand Up @@ -303,13 +349,22 @@ PlanNode* PathPlanner::multiPairPath(PlanNode* dep, bool reverse) {
auto qctx = pathCtx_->qctx;
auto* src = qctx->objPool()->add(new ColumnExpression(0));

PlanNode* pathDep = nullptr;
auto* gn = GetNeighbors::make(qctx, dep, pathCtx_->space.id);
gn->setSrc(src);
gn->setVertexProps(buildSrcVertexProps());
gn->setEdgeProps(buildEdgeProps(reverse));
gn->setInputVar(vidsVar);
gn->setDedup();
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, gn);
auto* path = ProduceSemiShortestPath::make(qctx, pathDep);
path->setOutputVar(vidsVar);
path->setColNames({kDst, kSrc, kCostStr, kPathStr});

Expand Down
2 changes: 2 additions & 0 deletions src/planner/ngql/PathPlanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class PathPlanner final : public Planner {
PlanNode* buildEdgePlan(PlanNode* dep, const std::string& input);

private:
GetNeighbors::VertexProps buildSrcVertexProps();

GetNeighbors::EdgeProps buildEdgeProps(bool reverse);

void doBuildEdgeProps(GetNeighbors::EdgeProps& edgeProps, bool reverse, bool isInEdge);
Expand Down
35 changes: 35 additions & 0 deletions src/validator/FindPathValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,48 @@ 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、agg
auto expr = where->filter();
if (ExpressionUtils::findAny(expr,
{Expression::Kind::kAggregate,
Expression::Kind::kDstProperty,
Expression::Kind::kVarProperty,
Expression::Kind::kInputProperty})) {
return Status::SemanticError("Not support `%s' in where sentence.",
expr->toString().c_str());
}
auto filter = ExpressionUtils::rewriteLabelAttr2EdgeProp(expr);

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

0 comments on commit c610874

Please sign in to comment.