forked from vesoft-inc/nebula
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVariablePropIndexSeek.cpp
146 lines (127 loc) · 5.12 KB
/
VariablePropIndexSeek.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* Copyright (c) 2023 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/
#include "graph/planner/match/VariablePropIndexSeek.h"
#include "graph/planner/match/MatchSolver.h"
#include "graph/planner/plan/Logic.h"
#include "graph/planner/plan/Query.h"
#include "graph/util/ExpressionUtils.h"
using nebula::meta::cpp2::IndexItem;
using nebula::storage::cpp2::IndexQueryContext;
namespace nebula {
namespace graph {
bool VariablePropIndexSeek::matchNode(NodeContext* nodeCtx) {
const auto& nodeInfo = *DCHECK_NOTNULL(nodeCtx->info);
const auto& labels = nodeInfo.labels;
if (labels.size() != 1 || labels.size() != nodeInfo.tids.size()) {
// TODO multiple tag index seek need the IndexScan support
VLOG(2) << "Multiple tag index seek is not supported now.";
return false;
}
const std::string& label = labels.front();
if (nodeInfo.alias.empty() || nodeInfo.anonymous) {
return false;
}
auto whereClause = nodeCtx->bindWhereClause;
if (!whereClause || !whereClause->filter) return false;
auto filter = whereClause->filter;
std::string refVarName;
std::shared_ptr<IndexItem> idxItem;
Expression* indexFilter = nullptr;
if (filter->kind() == Expression::Kind::kLogicalAnd) {
auto logExpr = static_cast<const LogicalExpression*>(filter);
bool found = false;
for (auto op : logExpr->operands()) {
if (getIndexItem(nodeCtx, op, label, nodeInfo.alias, &refVarName, &indexFilter, &idxItem)) {
// TODO(yee): Only select the first index as candidate filter expression and not support
// the combined index
found = true;
break;
}
}
if (!found) return false;
} else {
if (!getIndexItem(
nodeCtx, filter, label, nodeInfo.alias, &refVarName, &indexFilter, &idxItem)) {
return false;
}
}
if (!nodeCtx->aliasesAvailable->count(refVarName)) {
return false;
}
nodeCtx->refVarName = refVarName;
nodeCtx->scanInfo.filter = DCHECK_NOTNULL(indexFilter);
nodeCtx->scanInfo.schemaIds = nodeInfo.tids;
nodeCtx->scanInfo.schemaNames = nodeInfo.labels;
return true;
}
StatusOr<SubPlan> VariablePropIndexSeek::transformNode(NodeContext* nodeCtx) {
SubPlan plan;
const auto& schemaIds = nodeCtx->scanInfo.schemaIds;
DCHECK_EQ(schemaIds.size(), 1u) << "Not supported multiple tag properties seek.";
auto qctx = nodeCtx->qctx;
auto argument = Argument::make(qctx, nodeCtx->refVarName);
argument->setColNames({nodeCtx->refVarName});
argument->setInputVertexRequired(false);
IndexQueryContext iqctx;
iqctx.filter_ref() = Expression::encode(*nodeCtx->scanInfo.filter);
auto scan = IndexScan::make(
qctx, argument, nodeCtx->spaceId, {std::move(iqctx)}, {kVid}, false, schemaIds.back());
scan->setColNames({kVid});
scan->setLazyIndexHint(true);
plan.tail = argument;
plan.root = scan;
// initialize start expression in project node
auto* pool = nodeCtx->qctx->objPool();
nodeCtx->initialExpr = VariablePropertyExpression::make(pool, "", kVid);
return plan;
}
bool VariablePropIndexSeek::getIndexItem(const NodeContext* nodeCtx,
const Expression* filter,
const std::string& label,
const std::string& alias,
std::string* refVarName,
Expression** indexFilter,
std::shared_ptr<IndexItem>* idxItem) {
if (filter->kind() != Expression::Kind::kRelEQ && filter->kind() != Expression::Kind::kRelIn) {
return false;
}
auto relInExpr = static_cast<const RelationalExpression*>(filter);
auto right = relInExpr->right();
if (right->kind() != Expression::Kind::kLabel) {
// TODO(yee): swap the right and left side exprs when the left expr is label expr
return false;
}
std::string propName;
if (!MatchSolver::extractTagPropName(relInExpr->left(), alias, label, &propName)) {
return false;
}
// TODO(yee): workaround for index selection
auto metaClient = nodeCtx->qctx->getMetaClient();
auto status = metaClient->getTagIndexesFromCache(nodeCtx->spaceId);
if (!status.ok()) return false;
std::vector<std::shared_ptr<IndexItem>> idxItemList;
for (auto itemPtr : status.value()) {
auto schemaId = itemPtr->get_schema_id();
if (schemaId.get_tag_id() == nodeCtx->info->tids.back()) {
const auto& fields = itemPtr->get_fields();
if (!fields.empty() && fields.front().get_name() == propName) {
idxItemList.push_back(itemPtr);
}
}
}
if (idxItemList.empty()) return false;
std::sort(idxItemList.begin(), idxItemList.end(), [](auto rhs, auto lhs) {
return rhs->get_fields().size() < lhs->get_fields().size();
});
*refVarName = static_cast<const LabelExpression*>(right)->name();
*idxItem = idxItemList.front();
auto objPool = nodeCtx->qctx->objPool();
auto tagPropExpr = TagPropertyExpression::make(objPool, label, propName);
*indexFilter =
RelationalExpression::makeKind(objPool, filter->kind(), tagPropExpr, right->clone());
return true;
}
} // namespace graph
} // namespace nebula