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

Commit

Permalink
add IndexScan patch for or filter
Browse files Browse the repository at this point in the history
add tck cases
  • Loading branch information
czpmango committed May 7, 2021
1 parent a4a9071 commit 9f21f84
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 2 deletions.
47 changes: 47 additions & 0 deletions src/planner/match/LabelIndexSeek.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,53 @@ StatusOr<SubPlan> LabelIndexSeek::transformNode(NodeContext* nodeCtx) {
plan.tail = scan;
plan.root = scan;

// This if-block is a patch for or-filter-embeding to avoid OOM,
// and it should be converted to an `optRule` after the match validator is refactored
auto& whereCtx = matchClauseCtx->where;
if (whereCtx && whereCtx->filter) {
auto* filter = whereCtx->filter;
const auto nodeAlias = *nodeCtx->info->alias;
auto* objPool = matchClauseCtx->qctx->objPool();
if (filter->kind() == Expression::Kind::kLogicalOr) {
auto labelExprs = ExpressionUtils::collectAll(filter, {Expression::Kind::kLabel});
bool labelMatched = true;
for (auto* labelExpr : labelExprs) {
DCHECK_EQ(labelExpr->kind(), Expression::Kind::kLabel);
if (*(static_cast<const LabelExpression*>(labelExpr)->name()) != nodeAlias) {
labelMatched = false;
break;
}
}
if (labelMatched) {
auto* flattenFilter = ExpressionUtils::flattenInnerLogicalExpr(filter);
DCHECK_EQ(flattenFilter->kind(), Expression::Kind::kLogicalOr);
auto& filterItems = static_cast<LogicalExpression*>(flattenFilter)->operands();
auto canBeEmbeded = [](Expression::Kind k) -> bool {
return k == Expression::Kind::kRelEQ || k == Expression::Kind::kRelLT ||
k == Expression::Kind::kRelLE || k == Expression::Kind::kRelGT ||
k == Expression::Kind::kRelGE;
};
bool canBeEmbeded2IndexScan = true;
for (auto& f : filterItems) {
if (!canBeEmbeded(f->kind())) {
canBeEmbeded2IndexScan = false;
}
}
if (canBeEmbeded2IndexScan) {
auto* srcFilter =
objPool->add(ExpressionUtils::rewriteLabelAttr2TagProp(flattenFilter));
delete (flattenFilter);
storage::cpp2::IndexQueryContext ctx;
ctx.set_filter(Expression::encode(*srcFilter));
auto context =
std::make_unique<std::vector<storage::cpp2::IndexQueryContext>>();
context->emplace_back(std::move(ctx));
scan->setIndexQueryContext(std::move(context));
whereCtx.reset();
}
}
}
}
// initialize start expression in project node
nodeCtx->initialExpr.reset(ExpressionUtils::newVarPropExpr(kVid));
return plan;
Expand Down
32 changes: 32 additions & 0 deletions src/util/ExpressionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,38 @@ ExpressionUtils::pullOrsImpl(LogicalExpression *expr,
}
}

Expression *ExpressionUtils::flattenInnerLogicalAndExpr(const Expression *expr) {
auto matcher = [](const Expression *e) -> bool {
return e->kind() == Expression::Kind::kLogicalAnd;
};
auto rewriter = [](const Expression *e) -> Expression * {
pullAnds(const_cast<Expression *>(e));
return e->clone().release();
};

return RewriteVisitor::transform(expr, std::move(matcher), std::move(rewriter));
}

Expression *ExpressionUtils::flattenInnerLogicalOrExpr(const Expression *expr) {
auto matcher = [](const Expression *e) -> bool {
return e->kind() == Expression::Kind::kLogicalOr;
};
auto rewriter = [](const Expression *e) -> Expression * {
pullOrs(const_cast<Expression *>(e));
return e->clone().release();
};

return RewriteVisitor::transform(expr, std::move(matcher), std::move(rewriter));
}

Expression *ExpressionUtils::flattenInnerLogicalExpr(const Expression *expr) {
auto* andFlattenExpr = flattenInnerLogicalAndExpr(expr);
auto* allFlattenExpr = flattenInnerLogicalOrExpr(andFlattenExpr);
delete(andFlattenExpr);

return allFlattenExpr;
}

VariablePropertyExpression *ExpressionUtils::newVarPropExpr(const std::string &prop,
const std::string &var) {
return new VariablePropertyExpression(new std::string(var), new std::string(prop));
Expand Down
4 changes: 4 additions & 0 deletions src/util/ExpressionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ class ExpressionUtils {
Expression::Kind kind,
const std::vector<std::unique_ptr<Expression>>& rels);

static Expression* flattenInnerLogicalAndExpr(const Expression* expr);
static Expression* flattenInnerLogicalOrExpr(const Expression* expr);
static Expression* flattenInnerLogicalExpr(const Expression* expr);

static std::unique_ptr<Expression> expandExpr(const Expression* expr);

static std::unique_ptr<Expression> expandImplAnd(const Expression* expr);
Expand Down
108 changes: 108 additions & 0 deletions src/util/test/ExpressionUtilsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,114 @@ TEST_F(ExpressionUtilsTest, pushAnds) {
ASSERT_EQ(expected, t->toString());
}

TEST_F(ExpressionUtilsTest, flattenInnerLogicalExpr) {
using Kind = Expression::Kind;
// true AND false AND true
{
auto *first = new ConstantExpression(true);
auto *second = new ConstantExpression(false);
auto *third = new ConstantExpression(true);
LogicalExpression expr(Kind::kLogicalAnd,
new LogicalExpression(Kind::kLogicalAnd,
first,
second),
third);
LogicalExpression expected(Kind::kLogicalAnd);
expected.addOperand(first->clone().release());
expected.addOperand(second->clone().release());
expected.addOperand(third->clone().release());
auto* newExpr = ExpressionUtils::flattenInnerLogicalExpr(&expr);
ASSERT_EQ(expected, *newExpr);
delete(newExpr);
}
// true OR false OR true
{
auto *first = new ConstantExpression(true);
auto *second = new ConstantExpression(false);
auto *third = new ConstantExpression(true);
LogicalExpression expr(Kind::kLogicalOr,
new LogicalExpression(Kind::kLogicalOr,
first,
second),
third);
LogicalExpression expected(Kind::kLogicalOr);
expected.addOperand(first->clone().release());
expected.addOperand(second->clone().release());
expected.addOperand(third->clone().release());
auto* newExpr = ExpressionUtils::flattenInnerLogicalExpr(&expr);
ASSERT_EQ(expected, *newExpr);
delete(newExpr);
}
// (true OR false OR true)==(true AND false AND true)
{
auto *or1 = new ConstantExpression(true);
auto *or2 = new ConstantExpression(false);
auto *or3 = new ConstantExpression(true);
auto* logicOrExpr = new LogicalExpression(Kind::kLogicalOr,
new LogicalExpression(Kind::kLogicalOr,
or1,
or2),
or3);
auto *and1 = new ConstantExpression(false);
auto *and2 = new ConstantExpression(false);
auto *and3 = new ConstantExpression(true);
auto* logicAndExpr = new LogicalExpression(Kind::kLogicalAnd,
new LogicalExpression(Kind::kLogicalAnd,
and1,
and2),
and3);
RelationalExpression expr(Kind::kRelEQ, logicOrExpr, logicAndExpr);

auto* logicOrFlatten = new LogicalExpression(Kind::kLogicalOr);
logicOrFlatten->addOperand(or1->clone().release());
logicOrFlatten->addOperand(or2->clone().release());
logicOrFlatten->addOperand(or3->clone().release());
auto* logicAndFlatten = new LogicalExpression(Kind::kLogicalAnd);
logicAndFlatten->addOperand(and1->clone().release());
logicAndFlatten->addOperand(and2->clone().release());
logicAndFlatten->addOperand(and3->clone().release());
RelationalExpression expected(Kind::kRelEQ, logicOrFlatten, logicAndFlatten);

auto* newExpr = ExpressionUtils::flattenInnerLogicalExpr(&expr);
ASSERT_EQ(expected, *newExpr);
delete(newExpr);
}
// (true OR false OR true) AND (true AND false AND true)
{
auto *or1 = new ConstantExpression(true);
auto *or2 = new ConstantExpression(false);
auto *or3 = new ConstantExpression(true);
auto* logicOrExpr = new LogicalExpression(Kind::kLogicalOr,
new LogicalExpression(Kind::kLogicalOr,
or1,
or2),
or3);
auto *and1 = new ConstantExpression(false);
auto *and2 = new ConstantExpression(false);
auto *and3 = new ConstantExpression(true);
auto* logicAndExpr = new LogicalExpression(Kind::kLogicalAnd,
new LogicalExpression(Kind::kLogicalAnd,
and1,
and2),
and3);
LogicalExpression expr(Kind::kLogicalAnd, logicOrExpr, logicAndExpr);

auto* logicOrFlatten = new LogicalExpression(Kind::kLogicalOr);
logicOrFlatten->addOperand(or1->clone().release());
logicOrFlatten->addOperand(or2->clone().release());
logicOrFlatten->addOperand(or3->clone().release());
LogicalExpression expected(Kind::kLogicalAnd);
expected.addOperand(logicOrFlatten);
expected.addOperand(and1->clone().release());
expected.addOperand(and2->clone().release());
expected.addOperand(and3->clone().release());

auto* newExpr = ExpressionUtils::flattenInnerLogicalExpr(&expr);
ASSERT_EQ(expected, *newExpr);
delete(newExpr);
}
}

std::unique_ptr<Expression> parse(const std::string& expr) {
std::string query = "LOOKUP on t1 WHERE " + expr;
GQLParser parser;
Expand Down
4 changes: 2 additions & 2 deletions tests/common/plan_differ.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ def _check_op_info(self, exp, resp):
if resp is None:
if exp:
return f"expect: {exp} but resp plan node is None"
else:
if exp:
resp_dict = {
f"{bytes.decode(pair.key)}": f"{bytes.decode(pair.value)}"
for pair in resp
}
if exp and not self._is_subdict_nested(exp, resp_dict):
if not self._is_subdict_nested(exp, resp_dict):
return "Invalid descriptions, expect: {} vs. resp: {}".format(
json.dumps(exp), json.dumps(resp_dict))
return None
Expand Down
Loading

0 comments on commit 9f21f84

Please sign in to comment.