Skip to content

Commit

Permalink
Feature/match path expression (#3997)
Browse files Browse the repository at this point in the history
* Add match path pattern expression.

* Change to relationship pattern.

* Fix typo.

* Resolve shift/reduce conflict by precedence.

* Resolve reduce/reduce/conflict by GLR.

* Add benchmark.

* Update benchmark info.

* Disable undefined variable.

* Separate check function.

* Implement pattern expression in where.

* Remove unsued variable.

* Don't group by edge variable.

* Support in filter.

* Add more test cases.

* Add multiple patterns in filter.

* Collect path by RollUpApply.

* Modify ldbc cases.

* Fix case.

* Forbid special case.

* Tune ldbc cases.

* Tune some cases.

* Remove skip.

* Fix scanner test case.

* Tune ldbc case.

Co-authored-by: Sophie <[email protected]>
  • Loading branch information
Shylock-Hg and Sophie-Xie authored Mar 24, 2022
1 parent 166e70c commit 7d12727
Show file tree
Hide file tree
Showing 77 changed files with 1,781 additions and 511 deletions.
1 change: 1 addition & 0 deletions src/codec/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(CODEC_TEST_LIBS
$<TARGET_OBJECTS:meta_obj>
$<TARGET_OBJECTS:process_obj>
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:function_manager_obj>
$<TARGET_OBJECTS:wkt_wkb_io_obj>
$<TARGET_OBJECTS:agg_function_manager_obj>
Expand Down
34 changes: 28 additions & 6 deletions src/common/datatypes/Value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,28 @@ Value Value::equal(const Value& v) const {
return Value::kNullBadType;
}

bool Value::isImplicitBool() const {
switch (type_) {
case Type::BOOL:
case Type::LIST:
return true;
default:
return false;
}
}

bool Value::implicitBool() const {
DCHECK(isImplicitBool());
switch (type_) {
case Type::BOOL:
return getBool();
case Type::LIST:
return !getList().empty();
default:
LOG(FATAL) << "Impossible to reach here!";
}
}

void swap(Value& a, Value& b) {
Value temp(std::move(a));
a = std::move(b);
Expand Down Expand Up @@ -2760,11 +2782,11 @@ Value operator!(const Value& rhs) {
return rhs;
}

if (rhs.type() != Value::Type::BOOL) {
if (!rhs.isImplicitBool()) {
return Value::kNullBadType;
}

auto val = rhs.getBool();
auto val = rhs.implicitBool();
return !val;
}

Expand Down Expand Up @@ -2973,8 +2995,8 @@ Value operator&&(const Value& lhs, const Value& rhs) {
return Value::kEmpty;
}

if (lhs.type() == Value::Type::BOOL && rhs.type() == Value::Type::BOOL) {
return lhs.getBool() && rhs.getBool();
if (lhs.isImplicitBool() && rhs.isImplicitBool()) {
return lhs.implicitBool() && rhs.implicitBool();
} else {
return Value::kNullBadType;
}
Expand All @@ -2993,8 +3015,8 @@ Value operator||(const Value& lhs, const Value& rhs) {
return Value::kEmpty;
}

if (lhs.type() == Value::Type::BOOL && rhs.type() == Value::Type::BOOL) {
return lhs.getBool() || rhs.getBool();
if (lhs.isImplicitBool() && rhs.isImplicitBool()) {
return lhs.implicitBool() || rhs.implicitBool();
} else {
return Value::kNullBadType;
}
Expand Down
6 changes: 6 additions & 0 deletions src/common/datatypes/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ struct Value {

Value equal(const Value& v) const;

// Whether the value can be converted to bool implicitly
bool isImplicitBool() const;

// Convert Value to bool implicitly
bool implicitBool() const;

private:
Type type_;

Expand Down
2 changes: 2 additions & 0 deletions src/common/datatypes/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ nebula_add_test(
OBJECTS
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:datatypes_obj>
$<TARGET_OBJECTS:function_manager_obj>
$<TARGET_OBJECTS:wkt_wkb_io_obj>
Expand Down Expand Up @@ -107,6 +108,7 @@ nebula_add_test(
OBJECTS
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:datatypes_obj>
$<TARGET_OBJECTS:wkt_wkb_io_obj>
$<TARGET_OBJECTS:function_manager_obj>
Expand Down
1 change: 1 addition & 0 deletions src/common/expression/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ nebula_add_library(
PredicateExpression.cpp
ListComprehensionExpression.cpp
ReduceExpression.cpp
MatchPathPatternExpression.cpp
)

nebula_add_subdirectory(test)
3 changes: 3 additions & 0 deletions src/common/expression/ExprVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "common/expression/LabelExpression.h"
#include "common/expression/ListComprehensionExpression.h"
#include "common/expression/LogicalExpression.h"
#include "common/expression/MatchPathPatternExpression.h"
#include "common/expression/PathBuildExpression.h"
#include "common/expression/PredicateExpression.h"
#include "common/expression/PropertyExpression.h"
Expand Down Expand Up @@ -89,6 +90,8 @@ class ExprVisitor {
virtual void visit(ReduceExpression *expr) = 0;
// subscript range expression
virtual void visit(SubscriptRangeExpression *expr) = 0;
// match path pattern expression
virtual void visit(MatchPathPatternExpression *expr) = 0;
};

} // namespace nebula
Expand Down
7 changes: 7 additions & 0 deletions src/common/expression/Expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,10 @@ Expression* Expression::decode(ObjectPool* pool, Expression::Decoder& decoder) {
case Expression::Kind::kTSFuzzy: {
LOG(FATAL) << "Should not decode text search expression";
return exp;
}
case Expression::Kind::kMatchPathPattern: {
LOG(FATAL) << "Should not decode match path pattern expression.";
return exp;
}
// no default so the compiler will warning when lack
}
Expand Down Expand Up @@ -737,6 +741,9 @@ std::ostream& operator<<(std::ostream& os, Expression::Kind kind) {
case Expression::Kind::kReduce:
os << "Reduce";
break;
case Expression::Kind::kMatchPathPattern:
os << "MatchPathPattern";
break;
}
return os;
}
Expand Down
2 changes: 2 additions & 0 deletions src/common/expression/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class Expression {
kIsNotEmpty,

kSubscriptRange,

kMatchPathPattern,
};

Expression(ObjectPool* pool, Kind kind);
Expand Down
10 changes: 10 additions & 0 deletions src/common/expression/FunctionCallExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ class FunctionCallExpression final : public Expression {
: pool->add(new FunctionCallExpression(pool, name, args));
}

static FunctionCallExpression* make(ObjectPool* pool,
const std::string& name,
std::vector<Expression*> args) {
auto* argList = ArgumentList::make(pool, args.size());
for (auto* arg : args) {
argList->addArgument(arg);
}
return pool->add(new FunctionCallExpression(pool, name, argList));
}

const Value& eval(ExpressionContext& ctx) override;

bool operator==(const Expression& rhs) const override;
Expand Down
14 changes: 7 additions & 7 deletions src/common/expression/LogicalExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ const Value &LogicalExpression::evalAnd(ExpressionContext &ctx) {
result_ = true;
for (auto i = 0u; i < operands_.size(); i++) {
auto &value = operands_[i]->eval(ctx);
if (value.isBadNull() || (value.isBool() && !value.getBool())) {
if (value.isBadNull() || (value.isImplicitBool() && !value.implicitBool())) {
result_ = value;
return result_;
}
if (!value.isBool()) {
if (!value.isImplicitBool()) {
if (value.isNull()) {
result_ = value;
} else if (value.empty() && !result_.isNull()) {
Expand All @@ -52,11 +52,11 @@ const Value &LogicalExpression::evalOr(ExpressionContext &ctx) {
result_ = false;
for (auto i = 0u; i < operands_.size(); i++) {
auto &value = operands_[i]->eval(ctx);
if (value.isBadNull() || (value.isBool() && value.getBool())) {
if (value.isBadNull() || (value.isImplicitBool() && value.implicitBool())) {
result_ = value;
return result_;
}
if (!value.isBool()) {
if (!value.isImplicitBool()) {
if (value.isNull()) {
result_ = value;
} else if (value.empty() && !result_.isNull()) {
Expand All @@ -81,7 +81,7 @@ const Value &LogicalExpression::evalXor(ExpressionContext &ctx) {
result_ = value;
return result_;
}
if (!value.isBool()) {
if (!value.isImplicitBool()) {
if (value.empty()) {
result_ = value;
hasEmpty = 1;
Expand All @@ -92,10 +92,10 @@ const Value &LogicalExpression::evalXor(ExpressionContext &ctx) {
}
if (hasEmpty) continue;
if (firstBool) {
result_ = static_cast<bool>(value.getBool());
result_ = static_cast<bool>(value.implicitBool());
firstBool = 0u;
} else {
result_ = static_cast<bool>(result_.getBool() ^ value.getBool());
result_ = static_cast<bool>(result_.implicitBool() ^ value.implicitBool());
}
}

Expand Down
50 changes: 50 additions & 0 deletions src/common/expression/MatchPathPatternExpression.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* Copyright (c) 2022 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#include "common/expression/MatchPathPatternExpression.h"

#include "common/expression/ExprVisitor.h"

namespace nebula {

const Value& MatchPathPatternExpression::eval(ExpressionContext& ctx) {
result_ = DCHECK_NOTNULL(prop_)->eval(ctx);
return result_;
}

bool MatchPathPatternExpression::operator==(const Expression& rhs) const {
if (kind() != rhs.kind()) {
return false;
}

if (matchPath_ != matchPath_) {
return false;
}

// The prop_ field is used for evaluation internally, so it don't identify the expression.
// We don't compare it here.
// Ditto for result_ field.

return true;
}

std::string MatchPathPatternExpression::toString() const {
return matchPath_->toString();
}

void MatchPathPatternExpression::accept(ExprVisitor* visitor) {
visitor->visit(this);
}

Expression* MatchPathPatternExpression::clone() const {
auto expr =
MatchPathPatternExpression::make(pool_, std::make_unique<MatchPath>(matchPath_->clone()));
if (prop_ != nullptr) {
expr->setInputProp(static_cast<InputPropertyExpression*>(prop_->clone()));
}
return expr;
}

} // namespace nebula
78 changes: 78 additions & 0 deletions src/common/expression/MatchPathPatternExpression.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* Copyright (c) 2022 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#ifndef COMMON_EXPRESSION_MATCHPATHPATTERNEXPRESSION_H_
#define COMMON_EXPRESSION_MATCHPATHPATTERNEXPRESSION_H_

#include "common/expression/Expression.h"
#include "parser/MatchSentence.h"

namespace nebula {

// For expression like (v:player)-[e:like]->(p)
// Evaluate to [[v, e, p], [v, e, p]...]
class MatchPathPatternExpression final : public Expression {
public:
MatchPathPatternExpression& operator=(const MatchPathPatternExpression& rhs) = delete;
MatchPathPatternExpression& operator=(MatchPathPatternExpression&&) = delete;

static MatchPathPatternExpression* make(ObjectPool* pool,
std::unique_ptr<MatchPath>&& matchPath) {
return pool->add(new MatchPathPatternExpression(pool, std::move(matchPath)));
}

const Value& eval(ExpressionContext& ctx) override;

bool operator==(const Expression& rhs) const override;

std::string toString() const override;

void accept(ExprVisitor* visitor) override;

Expression* clone() const override;

// Evaluate expression by fetch result from input variable
void setInputProp(const std::string& prop) {
prop_ = InputPropertyExpression::make(pool_, prop);
}

void setInputProp(InputPropertyExpression* expr) {
prop_ = expr;
}

InputPropertyExpression* inputProp() const {
return prop_;
}

const MatchPath& matchPath() const {
return *matchPath_;
}

MatchPath& matchPath() {
return *matchPath_;
}

private:
explicit MatchPathPatternExpression(ObjectPool* pool, std::unique_ptr<MatchPath>&& matchPath)
: Expression(pool, Kind::kMatchPathPattern), matchPath_(std::move(matchPath)) {}

// This expression contains variable implicitly, so we don't support persist or transform it.
void writeTo(Encoder&) const override {
LOG(FATAL) << "Not implemented";
}

// This expression contains variable implicitly, so we don't support persist or transform it.
void resetFrom(Decoder&) override {
LOG(FATAL) << "Not implemented";
}

private:
std::unique_ptr<MatchPath> matchPath_;
InputPropertyExpression* prop_{
nullptr}; // The column of input stored the result of the expression
Value result_;
};
} // namespace nebula
#endif // COMMON_EXPRESSION_MATCHPATHPATTERNEXPRESSION_H_
4 changes: 4 additions & 0 deletions src/common/expression/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

set(expression_test_common_libs
$<TARGET_OBJECTS:parser_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:network_obj>
$<TARGET_OBJECTS:fs_obj>
$<TARGET_OBJECTS:stats_obj>
Expand Down Expand Up @@ -117,6 +119,7 @@ nebula_add_executable(
FunctionCallExpressionBenchmark.cpp
OBJECTS
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:datatypes_obj>
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:expr_ctx_mock_obj>
Expand All @@ -140,6 +143,7 @@ nebula_add_executable(
AggregateExpressionBenchmark.cpp
OBJECTS
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
$<TARGET_OBJECTS:datatypes_obj>
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:expr_ctx_mock_obj>
Expand Down
2 changes: 2 additions & 0 deletions src/common/id/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ nebula_add_executable(
$<TARGET_OBJECTS:fs_obj>
$<TARGET_OBJECTS:meta_client_stats_obj>
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
LIBRARIES
follybenchmark
boost_regex
Expand Down Expand Up @@ -72,6 +73,7 @@ nebula_add_test(
$<TARGET_OBJECTS:fs_obj>
$<TARGET_OBJECTS:meta_client_stats_obj>
$<TARGET_OBJECTS:expression_obj>
$<TARGET_OBJECTS:ast_match_path_obj>
LIBRARIES
gtest
gtest_main
Expand Down
Loading

0 comments on commit 7d12727

Please sign in to comment.