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

enhance same attribute name for different tags #3255

Merged
merged 16 commits into from
Dec 29, 2021
Merged
1 change: 1 addition & 0 deletions src/common/expression/ExprVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class ExprVisitor {
virtual void visit(MapExpression *expr) = 0;
// property Expression
virtual void visit(TagPropertyExpression *expr) = 0;
virtual void visit(LabelTagPropertyExpression *expr) = 0;
virtual void visit(EdgePropertyExpression *expr) = 0;
virtual void visit(InputPropertyExpression *expr) = 0;
virtual void visit(VariablePropertyExpression *expr) = 0;
Expand Down
11 changes: 10 additions & 1 deletion src/common/expression/Expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,11 @@ Expression* Expression::decode(ObjectPool* pool, Expression::Decoder& decoder) {
exp->resetFrom(decoder);
return exp;
}
case Expression::Kind::kLabelTagProperty: {
exp = LabelTagPropertyExpression::make(pool);
exp->resetFrom(decoder);
return exp;
}
case Expression::Kind::kLabelAttribute: {
exp = LabelAttributeExpression::make(pool);
exp->resetFrom(decoder);
Expand Down Expand Up @@ -394,7 +399,8 @@ Expression* Expression::decode(ObjectPool* pool, Expression::Decoder& decoder) {
return exp;
}
case Expression::Kind::kVarProperty: {
LOG(FATAL) << "Should not decode variable property expression";
exp = VariablePropertyExpression::make(pool);
exp->resetFrom(decoder);
return exp;
}
case Expression::Kind::kDstProperty: {
Expand Down Expand Up @@ -626,6 +632,9 @@ std::ostream& operator<<(std::ostream& os, Expression::Kind kind) {
case Expression::Kind::kLabelAttribute:
os << "LabelAttribute";
break;
case Expression::Kind::kLabelTagProperty:
os << "LabelTagProperty";
break;
case Expression::Kind::kLogicalAnd:
os << "LogicalAnd";
break;
Expand Down
1 change: 1 addition & 0 deletions src/common/expression/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class Expression {
kFunctionCall,
// Vertex/Edge/Path
kTagProperty,
kLabelTagProperty,
kEdgeProperty,
kInputProperty,
kVarProperty,
Expand Down
8 changes: 7 additions & 1 deletion src/common/expression/PredicateExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ std::unordered_map<std::string, PredicateExpression::Type> PredicateExpression::

const Value& PredicateExpression::evalExists(ExpressionContext& ctx) {
DCHECK(collection_->kind() == Expression::Kind::kAttribute ||
collection_->kind() == Expression::Kind::kSubscript);
collection_->kind() == Expression::Kind::kSubscript ||
collection_->kind() == Expression::Kind::kLabelTagProperty);

if (collection_->kind() == Expression::Kind::kLabelTagProperty) {
result_ = !collection_->eval(ctx).isNull();
return result_;
}

auto* attributeExpr = static_cast<BinaryExpression*>(collection_);
auto& container = attributeExpr->left()->eval(ctx);
Expand Down
43 changes: 43 additions & 0 deletions src/common/expression/PropertyExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,47 @@ std::string VariablePropertyExpression::toString() const {
return buf;
}

const Value& LabelTagPropertyExpression::eval(ExpressionContext& ctx) {
const auto& var = label_->eval(ctx);
if (var.type() != Value::Type::VERTEX) {
return Value::kNullBadType;
}
for (const auto& tag : var.getVertex().tags) {
if (tag.name == sym_) {
auto iter = tag.props.find(prop_);
if (iter != tag.props.end()) {
return iter->second;
}
}
}
return Value::kNullValue;
}

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

std::string LabelTagPropertyExpression::toString() const {
std::string labelStr = label_ != nullptr ? label_->toString().erase(0, 1) : "";
return labelStr + "." + sym_ + "." + prop_;
}

bool LabelTagPropertyExpression::operator==(const Expression& rhs) const {
if (kind_ != rhs.kind()) {
return false;
}
const auto& expr = static_cast<const LabelTagPropertyExpression&>(rhs);
return *label_ == *expr.label_ && sym_ == expr.sym_ && prop_ == expr.prop_;
}

void LabelTagPropertyExpression::writeTo(Encoder& encoder) const {
PropertyExpression::writeTo(encoder);
encoder << *label_;
}

void LabelTagPropertyExpression::resetFrom(Decoder& decoder) {
PropertyExpression::resetFrom(decoder);
label_ = decoder.readExpression(pool_);
}

} // namespace nebula
47 changes: 47 additions & 0 deletions src/common/expression/PropertyExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,53 @@ class TagPropertyExpression final : public PropertyExpression {
Value result_;
};

// label.tag_name.any_prop_name
class LabelTagPropertyExpression final : public PropertyExpression {
public:
LabelTagPropertyExpression& operator=(const LabelTagPropertyExpression& rhs) = delete;
LabelTagPropertyExpression& operator=(LabelTagPropertyExpression&&) = delete;

static LabelTagPropertyExpression* make(ObjectPool* pool,
Expression* label = nullptr,
const std::string& tag = "",
const std::string& prop = "") {
return pool->add(new LabelTagPropertyExpression(pool, label, tag, prop));
}

std::string toString() const override;

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

const Value& eval(ExpressionContext& ctx) override;

void accept(ExprVisitor* visitor) override;

Expression* clone() const override {
return LabelTagPropertyExpression::make(pool_, label_, sym(), prop());
}

const Expression* label() const {
return label_;
}

Expression* label() {
return label_;
}

private:
LabelTagPropertyExpression(ObjectPool* pool,
Expression* label = nullptr,
const std::string& tag = "",
const std::string& prop = "")
: PropertyExpression(pool, Kind::kLabelTagProperty, "", tag, prop), label_(label) {}

void writeTo(Encoder& encoder) const override;
void resetFrom(Decoder& decoder) override;

private:
Expression* label_{nullptr};
};

// $-.any_prop_name
class InputPropertyExpression final : public PropertyExpression {
public:
Expand Down
28 changes: 17 additions & 11 deletions src/graph/optimizer/rule/IndexScanRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
*/

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

#include "common/expression/LabelAttributeExpression.h"
#include "common/expression/VariableExpression.h"
#include "graph/context/QueryExpressionContext.h"
#include "graph/optimizer/OptContext.h"
#include "graph/optimizer/OptGroup.h"
#include "graph/optimizer/OptRule.h"
Expand All @@ -18,10 +14,10 @@
#include "graph/util/IndexUtil.h"
#include "graph/visitor/RewriteVisitor.h"

using nebula::graph::ExpressionUtils;
using nebula::graph::IndexScan;
using nebula::graph::IndexUtil;
using nebula::graph::OptimizerUtils;

using IndexQueryCtx = std::vector<nebula::graph::IndexScan::IndexQueryContext>;

namespace nebula {
Expand Down Expand Up @@ -378,9 +374,13 @@ Status IndexScanRule::analyzeExpression(
case Expression::Kind::kRelGT:
case Expression::Kind::kRelNE: {
auto* rExpr = static_cast<RelationalExpression*>(expr);
auto ret = isEdge ? addFilterItem<EdgePropertyExpression>(rExpr, items, qctx)
: addFilterItem<TagPropertyExpression>(rExpr, items, qctx);
NG_RETURN_IF_ERROR(ret);
if (isEdge) {
NG_RETURN_IF_ERROR(addFilterItem<EdgePropertyExpression>(rExpr, items, qctx));
} else if (ExpressionUtils::hasAny(rExpr, {Expression::Kind::kLabelTagProperty})) {
NG_RETURN_IF_ERROR(addFilterItem<LabelTagPropertyExpression>(rExpr, items, qctx));
} else {
NG_RETURN_IF_ERROR(addFilterItem<TagPropertyExpression>(rExpr, items, qctx));
}
if (kind->getKind() == ScanKind::Kind::kMultipleScan &&
expr->kind() == Expression::Kind::kRelNE) {
kind->setKind(ScanKind::Kind::kSingleScan);
Expand All @@ -400,8 +400,14 @@ Status IndexScanRule::addFilterItem(RelationalExpression* expr,
FilterItems* items,
QueryContext* qctx) const {
// TODO (sky) : Check illegal filter. for example : where c1 == 1 and c1 == 2
auto relType = std::is_same<E, EdgePropertyExpression>::value ? Expression::Kind::kEdgeProperty
: Expression::Kind::kTagProperty;
Expression::Kind relType;
if constexpr (std::is_same<E, EdgePropertyExpression>::value) {
relType = Expression::Kind::kEdgeProperty;
} else if constexpr (std::is_same<E, LabelTagPropertyExpression>::value) {
relType = Expression::Kind::kLabelTagProperty;
} else {
relType = Expression::Kind::kTagProperty;
}
if (expr->left()->kind() == relType &&
graph::ExpressionUtils::isEvaluableExpr(expr->right(), qctx)) {
auto* l = static_cast<const E*>(expr->left());
Expand Down Expand Up @@ -515,7 +521,7 @@ std::vector<IndexItem> IndexScanRule::findValidIndex(graph::QueryContext* qctx,
return item.col_ == fields[0].get_name();
});
if (it == items.items.end()) {
validIndexes.erase(index);
index = validIndexes.erase(index);
} else {
index++;
}
Expand Down
1 change: 1 addition & 0 deletions src/graph/optimizer/rule/IndexScanRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class IndexScanRule final : public OptRule {

template <typename E,
typename = std::enable_if_t<std::is_same<E, EdgePropertyExpression>::value ||
std::is_same<E, LabelTagPropertyExpression>::value ||
std::is_same<E, TagPropertyExpression>::value>>
Status addFilterItem(RelationalExpression* expr, FilterItems* items, QueryContext* qctx) const;

Expand Down
1 change: 1 addition & 0 deletions src/graph/optimizer/rule/PushFilterDownProjectRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ StatusOr<OptRule::TransformResult> PushFilterDownProjectRule::transform(
auto picker = [&projColumns, &projColNames, &rewriteMap](const Expression* e) -> bool {
auto varProps = graph::ExpressionUtils::collectAll(e,
{Expression::Kind::kTagProperty,
Expression::Kind::kLabelTagProperty,
Expression::Kind::kEdgeProperty,
Expression::Kind::kInputProperty,
Expression::Kind::kVarProperty,
Expand Down
11 changes: 5 additions & 6 deletions src/graph/planner/match/LabelIndexSeek.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ StatusOr<SubPlan> LabelIndexSeek::transformNode(NodeContext* nodeCtx) {
const auto& nodeAlias = nodeCtx->info->alias;

if (filter->kind() == Expression::Kind::kLogicalOr) {
auto labelExprs = ExpressionUtils::collectAll(filter, {Expression::Kind::kLabel});
auto exprs = ExpressionUtils::collectAll(filter, {Expression::Kind::kLabelTagProperty});
bool labelMatched = true;
for (auto* labelExpr : labelExprs) {
DCHECK_EQ(labelExpr->kind(), Expression::Kind::kLabel);
if (static_cast<const LabelExpression*>(labelExpr)->name() != nodeAlias) {
for (auto* expr : exprs) {
auto tagPropExpr = static_cast<const LabelTagPropertyExpression*>(expr);
if (static_cast<const PropertyExpression*>(tagPropExpr->label())->prop() != nodeAlias) {
labelMatched = false;
break;
}
Expand All @@ -117,9 +117,8 @@ StatusOr<SubPlan> LabelIndexSeek::transformNode(NodeContext* nodeCtx) {
}
}
if (canBeEmbedded2IndexScan) {
auto* srcFilter = ExpressionUtils::rewriteLabelAttr2TagProp(flattenFilter);
storage::cpp2::IndexQueryContext ctx;
ctx.filter_ref() = Expression::encode(*srcFilter);
ctx.filter_ref() = Expression::encode(*flattenFilter);
scan->setIndexQueryContext({ctx});
whereCtx.reset();
}
Expand Down
57 changes: 38 additions & 19 deletions src/graph/planner/match/MatchSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Expression* MatchSolver::doRewrite(QueryContext* qctx,
auto alias = aliases.find(labelExpr->name());
DCHECK(alias != aliases.end());
}

return rewriteLabel2VarProp(qctx, expr);
}

Expand Down Expand Up @@ -141,32 +140,52 @@ Expression* MatchSolver::makeIndexFilter(const std::string& label,
auto* binary = static_cast<const BinaryExpression*>(item);
auto* left = binary->left();
auto* right = binary->right();
const LabelAttributeExpression* la = nullptr;
const ConstantExpression* constant = nullptr;
std::string propName;
// TODO(aiee) extract the logic that applies to both match and lookup
if (left->kind() == Expression::Kind::kLabelAttribute &&
right->kind() == Expression::Kind::kConstant) {
la = static_cast<const LabelAttributeExpression*>(left);
constant = static_cast<const ConstantExpression*>(right);
} else if (right->kind() == Expression::Kind::kLabelAttribute &&
left->kind() == Expression::Kind::kConstant) {
la = static_cast<const LabelAttributeExpression*>(right);
constant = static_cast<const ConstantExpression*>(left);
if (isEdgeProperties) {
const LabelAttributeExpression* la = nullptr;
if (left->kind() == Expression::Kind::kLabelAttribute &&
right->kind() == Expression::Kind::kConstant) {
la = static_cast<const LabelAttributeExpression*>(left);
constant = static_cast<const ConstantExpression*>(right);
} else if (right->kind() == Expression::Kind::kLabelAttribute &&
left->kind() == Expression::Kind::kConstant) {
la = static_cast<const LabelAttributeExpression*>(right);
constant = static_cast<const ConstantExpression*>(left);
} else {
continue;
}
if (la->left()->name() != alias) {
continue;
}
propName = la->right()->value().getStr();
} else {
continue;
}

if (la->left()->name() != alias) {
continue;
const LabelTagPropertyExpression* la = nullptr;
if (left->kind() == Expression::Kind::kLabelTagProperty &&
right->kind() == Expression::Kind::kConstant) {
la = static_cast<const LabelTagPropertyExpression*>(left);
constant = static_cast<const ConstantExpression*>(right);
} else if (right->kind() == Expression::Kind::kLabelTagProperty &&
left->kind() == Expression::Kind::kConstant) {
la = static_cast<const LabelTagPropertyExpression*>(right);
constant = static_cast<const ConstantExpression*>(left);
} else {
continue;
}
if (static_cast<const PropertyExpression*>(la->label())->prop() != alias ||
la->sym() != label) {
continue;
}
propName = la->prop();
}

const auto& value = la->right()->value();
auto* tpExpr =
isEdgeProperties
? static_cast<Expression*>(EdgePropertyExpression::make(pool, label, value.getStr()))
: static_cast<Expression*>(TagPropertyExpression::make(pool, label, value.getStr()));
? static_cast<Expression*>(EdgePropertyExpression::make(pool, label, propName))
: static_cast<Expression*>(TagPropertyExpression::make(pool, label, propName));
auto* newConstant = constant->clone();
if (left->kind() == Expression::Kind::kLabelAttribute) {
if (right->kind() == Expression::Kind::kConstant) {
auto* rel = RelationalExpression::makeKind(pool, item->kind(), tpExpr, newConstant);
relationals.emplace_back(rel);
} else {
Expand Down
Loading