Skip to content

Commit fc5735a

Browse files
authored
extract attribute from properties function (#4604)
* extract attribute from properties function * fix error * fix subscript error * add test case * process scanEdges * fix test error
1 parent cdec60f commit fc5735a

10 files changed

+464
-38
lines changed

src/graph/executor/query/ScanEdgesExecutor.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ folly::Future<Status> ScanEdgesExecutor::scanEdges() {
4040
SCOPED_TIMER(&execTime_);
4141
otherStats_.emplace("total_rpc", folly::sformat("{}(us)", scanEdgesTime.elapsedInUSec()));
4242
})
43-
.thenValue([this, se](StorageRpcResponse<ScanResponse> &&rpcResp) {
43+
.thenValue([this](StorageRpcResponse<ScanResponse> &&rpcResp) {
4444
SCOPED_TIMER(&execTime_);
4545
addStats(rpcResp, otherStats_);
46-
return handleResp(std::move(rpcResp), se->colNames());
46+
return handleResp(std::move(rpcResp), {});
4747
});
4848
}
4949

src/graph/optimizer/rule/GetEdgesTransformUtils.h

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class GetEdgesTransformUtils final {
4848
limit_count,
4949
{},
5050
traverse->filter() == nullptr ? nullptr : traverse->filter()->clone());
51+
auto &colNames = traverse->colNames();
52+
DCHECK_EQ(colNames.size(), 2);
53+
scanEdges->setColNames({colNames.back()});
5154
return scanEdges;
5255
}
5356

src/graph/planner/plan/PlanNodeVisitor.h

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class PlanNodeVisitor {
2222
virtual void visit(Project *node) = 0;
2323
virtual void visit(Aggregate *node) = 0;
2424
virtual void visit(Traverse *node) = 0;
25+
virtual void visit(ScanEdges *node) = 0;
2526
virtual void visit(AppendVertices *node) = 0;
2627
virtual void visit(BiJoin *node) = 0;
2728
virtual void visit(Union *node) = 0;

src/graph/planner/plan/Query.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ PlanNode* ScanEdges::clone() const {
260260
return newGE;
261261
}
262262

263+
void ScanEdges::accept(PlanNodeVisitor* visitor) {
264+
visitor->visit(this);
265+
}
266+
263267
void ScanEdges::cloneMembers(const ScanEdges& ge) {
264268
Explore::cloneMembers(ge);
265269

src/graph/planner/plan/Query.h

+2
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ class ScanEdges final : public Explore {
719719
PlanNode* clone() const override;
720720
std::unique_ptr<PlanNodeDescription> explain() const override;
721721

722+
void accept(PlanNodeVisitor* visitor) override;
723+
722724
private:
723725
friend ObjectPool;
724726
ScanEdges(QueryContext* qctx,

src/graph/visitor/PropertyTrackerVisitor.cpp

+58-20
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55

66
#include "graph/visitor/PropertyTrackerVisitor.h"
77

8-
#include <sstream>
9-
#include <unordered_set>
10-
118
#include "common/expression/Expression.h"
129
#include "graph/context/QueryContext.h"
1310

@@ -174,27 +171,78 @@ void PropertyTrackerVisitor::visit(AttributeExpression *expr) {
174171
return;
175172
}
176173
auto &propName = constVal.getStr();
177-
static const int kUnknownEdgeType = 0;
178174
switch (lhs->kind()) {
179175
case Expression::Kind::kInputProperty:
180176
case Expression::Kind::kVarProperty: { // $e.name
181177
auto *varPropExpr = static_cast<PropertyExpression *>(lhs);
182178
auto &edgeAlias = varPropExpr->prop();
183-
propsUsed_.insertEdgeProp(edgeAlias, kUnknownEdgeType, propName);
179+
propsUsed_.insertEdgeProp(edgeAlias, unKnowType_, propName);
184180
break;
185181
}
186182
case Expression::Kind::kSubscript: { // $-.e[0].name
187183
auto *subscriptExpr = static_cast<SubscriptExpression *>(lhs);
188184
auto *subLeftExpr = subscriptExpr->left();
189-
if (subLeftExpr->kind() == Expression::Kind::kInputProperty) {
190-
auto *inputPropExpr = static_cast<InputPropertyExpression *>(subLeftExpr);
191-
auto &edgeAlias = inputPropExpr->prop();
192-
propsUsed_.insertEdgeProp(edgeAlias, kUnknownEdgeType, propName);
185+
auto kind = subLeftExpr->kind();
186+
if (kind == Expression::Kind::kInputProperty || kind == Expression::Kind::kVarProperty) {
187+
auto *propExpr = static_cast<PropertyExpression *>(subLeftExpr);
188+
auto &edgeAlias = propExpr->prop();
189+
propsUsed_.insertEdgeProp(edgeAlias, unKnowType_, propName);
190+
} else if (kind == Expression::Kind::kListComprehension) {
191+
// match (src_v:player{name:"Manu Ginobili"})-[e*2]-(dst_v) return e[0].start_year
192+
auto *listExpr = static_cast<ListComprehensionExpression *>(subLeftExpr);
193+
auto *collectExpr = listExpr->collection();
194+
if (collectExpr->kind() == Expression::Kind::kInputProperty) {
195+
auto *inputPropExpr = static_cast<InputPropertyExpression *>(collectExpr);
196+
auto &aliasName = inputPropExpr->prop();
197+
propsUsed_.insertEdgeProp(aliasName, unKnowType_, propName);
198+
}
193199
}
194200
break;
195201
}
196202
case Expression::Kind::kFunctionCall: { // properties(t3).name
197-
// TODO(jmq) determine whether it is a vertex or edge
203+
auto *funCallExpr = static_cast<FunctionCallExpression *>(lhs);
204+
auto funName = funCallExpr->name();
205+
std::transform(funName.begin(), funName.end(), funName.begin(), ::tolower);
206+
if (funName != "properties") {
207+
break;
208+
}
209+
auto *argExpr = funCallExpr->args()->args().front();
210+
auto kind = argExpr->kind();
211+
switch (kind) {
212+
case Expression::Kind::kVarProperty:
213+
case Expression::Kind::kInputProperty: {
214+
// match (v) return properties(v).name
215+
auto *inputPropExpr = static_cast<InputPropertyExpression *>(argExpr);
216+
auto &aliasName = inputPropExpr->prop();
217+
propsUsed_.insertVertexProp(aliasName, unKnowType_, propName);
218+
break;
219+
}
220+
case Expression::Kind::kSubscript: {
221+
auto *subscriptExpr = static_cast<SubscriptExpression *>(argExpr);
222+
auto *subLeftExpr = subscriptExpr->left();
223+
auto leftKind = subLeftExpr->kind();
224+
if (leftKind == Expression::Kind::kInputProperty ||
225+
leftKind == Expression::Kind::kVarProperty) {
226+
// match (v)-[e]->(b) return properties(e).start_year
227+
auto *propExpr = static_cast<PropertyExpression *>(subLeftExpr);
228+
auto &aliasName = propExpr->prop();
229+
propsUsed_.insertEdgeProp(aliasName, unKnowType_, propName);
230+
} else if (leftKind == Expression::Kind::kListComprehension) {
231+
// match (v)-[c*2]->(b) retrun properties(c[0]).start_year
232+
// properties([e IN $-.c WHERE is_edge($e)][0]).start_year
233+
auto *listExpr = static_cast<ListComprehensionExpression *>(subLeftExpr);
234+
auto *collectExpr = listExpr->collection();
235+
if (collectExpr->kind() == Expression::Kind::kInputProperty) {
236+
auto *inputPropExpr = static_cast<InputPropertyExpression *>(collectExpr);
237+
auto &aliasName = inputPropExpr->prop();
238+
propsUsed_.insertEdgeProp(aliasName, unKnowType_, propName);
239+
}
240+
}
241+
break;
242+
}
243+
default:
244+
break;
245+
}
198246
break;
199247
}
200248
default:
@@ -294,15 +342,5 @@ void PropertyTrackerVisitor::visit(EdgeExpression *expr) {
294342
UNUSED(expr);
295343
}
296344

297-
std::string PropertyTrackerVisitor::extractColNameFromInputPropOrVarPropExpr(
298-
const Expression *expr) {
299-
if (expr->kind() == Expression::Kind::kInputProperty ||
300-
expr->kind() == Expression::Kind::kVarProperty) {
301-
auto *propExpr = static_cast<const PropertyExpression *>(expr);
302-
return propExpr->prop();
303-
}
304-
return "";
305-
}
306-
307345
} // namespace graph
308346
} // namespace nebula

src/graph/visitor/PropertyTrackerVisitor.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,8 @@ class PropertyTrackerVisitor : public ExprVisitorImpl {
7474
void visit(ColumnExpression* expr) override;
7575
void visit(AggregateExpression* expr) override;
7676

77-
std::string extractColNameFromInputPropOrVarPropExpr(const Expression* expr);
78-
7977
const QueryContext* qctx_{nullptr};
78+
const int unKnowType_{0};
8079
GraphSpaceID space_;
8180
PropertyTracker& propsUsed_;
8281
std::string entityAlias_;

src/graph/visitor/PrunePropertiesVisitor.cpp

+84-11
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,61 @@ void PrunePropertiesVisitor::visitCurrent(Aggregate *node) {
129129
}
130130
}
131131

132+
void PrunePropertiesVisitor::visit(ScanEdges *node) {
133+
rootNode_ = false;
134+
pruneCurrent(node);
135+
status_ = depsPruneProperties(node->dependencies());
136+
}
137+
138+
void PrunePropertiesVisitor::pruneCurrent(ScanEdges *node) {
139+
auto &colNames = node->colNames();
140+
DCHECK(!colNames.empty());
141+
auto &edgeAlias = colNames.back();
142+
auto it = propsUsed_.colsSet.find(edgeAlias);
143+
if (it != propsUsed_.colsSet.end()) {
144+
// all properties are used
145+
return;
146+
}
147+
auto *edgeProps = node->props();
148+
auto &edgePropsMap = propsUsed_.edgePropsMap;
149+
150+
auto prunedEdgeProps = std::make_unique<std::vector<EdgeProp>>();
151+
prunedEdgeProps->reserve(edgeProps->size());
152+
auto edgeAliasIter = edgePropsMap.find(edgeAlias);
153+
154+
for (auto &edgeProp : *edgeProps) {
155+
auto edgeType = edgeProp.type_ref().value();
156+
auto &props = edgeProp.props_ref().value();
157+
EdgeProp newEdgeProp;
158+
newEdgeProp.type_ref() = edgeType;
159+
if (edgeAliasIter == edgePropsMap.end()) {
160+
// only type, dst are used
161+
newEdgeProp.props_ref() = {nebula::kSrc, nebula::kDst, nebula::kType, nebula::kRank};
162+
} else {
163+
std::unordered_set<std::string> uniqueProps{
164+
nebula::kSrc, nebula::kDst, nebula::kType, nebula::kRank};
165+
std::vector<std::string> newProps;
166+
auto &usedEdgeProps = edgeAliasIter->second;
167+
auto edgeTypeIter = usedEdgeProps.find(std::abs(edgeType));
168+
if (edgeTypeIter != usedEdgeProps.end()) {
169+
uniqueProps.insert(edgeTypeIter->second.begin(), edgeTypeIter->second.end());
170+
}
171+
auto unKnowEdgeIter = usedEdgeProps.find(unKnowType_);
172+
if (unKnowEdgeIter != usedEdgeProps.end()) {
173+
uniqueProps.insert(unKnowEdgeIter->second.begin(), unKnowEdgeIter->second.end());
174+
}
175+
for (auto &prop : props) {
176+
if (uniqueProps.find(prop) != uniqueProps.end()) {
177+
newProps.emplace_back(prop);
178+
}
179+
}
180+
newEdgeProp.props_ref() = std::move(newProps);
181+
}
182+
prunedEdgeProps->emplace_back(std::move(newEdgeProp));
183+
}
184+
node->setEdgeProps(std::move(prunedEdgeProps));
185+
}
186+
132187
void PrunePropertiesVisitor::visit(Traverse *node) {
133188
rootNode_ = false;
134189
visitCurrent(node);
@@ -176,24 +231,34 @@ void PrunePropertiesVisitor::pruneCurrent(Traverse *node) {
176231
if (usedVertexProps.empty()) {
177232
node->setVertexProps(nullptr);
178233
} else {
234+
auto unknowIter = usedVertexProps.find(unKnowType_);
179235
auto prunedVertexProps = std::make_unique<std::vector<VertexProp>>();
180236
prunedVertexProps->reserve(usedVertexProps.size());
181237
for (auto &vertexProp : *vertexProps) {
182238
auto tagId = vertexProp.tag_ref().value();
183239
auto &props = vertexProp.props_ref().value();
240+
std::unordered_set<std::string> usedProps;
241+
if (unknowIter != usedVertexProps.end()) {
242+
usedProps.insert(unknowIter->second.begin(), unknowIter->second.end());
243+
}
184244
auto tagIter = usedVertexProps.find(tagId);
185-
if (tagIter == usedVertexProps.end()) {
245+
if (tagIter != usedVertexProps.end()) {
246+
usedProps.insert(tagIter->second.begin(), tagIter->second.end());
247+
}
248+
if (usedProps.empty()) {
186249
continue;
187250
}
188-
auto &usedProps = tagIter->second;
189-
VertexProp newVProp;
190-
newVProp.tag_ref() = tagId;
191251
std::vector<std::string> newProps;
192252
for (auto &prop : props) {
193253
if (usedProps.find(prop) != usedProps.end()) {
194254
newProps.emplace_back(prop);
195255
}
196256
}
257+
if (newProps.empty()) {
258+
continue;
259+
}
260+
VertexProp newVProp;
261+
newVProp.tag_ref() = tagId;
197262
newVProp.props_ref() = std::move(newProps);
198263
prunedVertexProps->emplace_back(std::move(newVProp));
199264
}
@@ -227,8 +292,7 @@ void PrunePropertiesVisitor::pruneCurrent(Traverse *node) {
227292
if (edgeTypeIter != usedEdgeProps.end()) {
228293
uniqueProps.insert(edgeTypeIter->second.begin(), edgeTypeIter->second.end());
229294
}
230-
int kUnknowEdgeType = 0;
231-
auto unKnowEdgeIter = usedEdgeProps.find(kUnknowEdgeType);
295+
auto unKnowEdgeIter = usedEdgeProps.find(unKnowType_);
232296
if (unKnowEdgeIter != usedEdgeProps.end()) {
233297
uniqueProps.insert(unKnowEdgeIter->second.begin(), unKnowEdgeIter->second.end());
234298
}
@@ -318,24 +382,33 @@ void PrunePropertiesVisitor::pruneCurrent(AppendVertices *node) {
318382
}
319383
return;
320384
}
321-
385+
auto unknowIter = usedVertexProps.find(unKnowType_);
322386
prunedVertexProps->reserve(usedVertexProps.size());
323387
for (auto &vertexProp : *vertexProps) {
324388
auto tagId = vertexProp.tag_ref().value();
325389
auto &props = vertexProp.props_ref().value();
326390
auto tagIter = usedVertexProps.find(tagId);
327-
if (tagIter == usedVertexProps.end()) {
391+
std::unordered_set<std::string> usedProps;
392+
if (unknowIter != usedVertexProps.end()) {
393+
usedProps.insert(unknowIter->second.begin(), unknowIter->second.end());
394+
}
395+
if (tagIter != usedVertexProps.end()) {
396+
usedProps.insert(tagIter->second.begin(), tagIter->second.end());
397+
}
398+
if (usedProps.empty()) {
328399
continue;
329400
}
330-
auto &usedProps = tagIter->second;
331-
VertexProp newVProp;
332-
newVProp.tag_ref() = tagId;
333401
std::vector<std::string> newProps;
334402
for (auto &prop : props) {
335403
if (usedProps.find(prop) != usedProps.end()) {
336404
newProps.emplace_back(prop);
337405
}
338406
}
407+
if (newProps.empty()) {
408+
continue;
409+
}
410+
VertexProp newVProp;
411+
newVProp.tag_ref() = tagId;
339412
newVProp.props_ref() = std::move(newProps);
340413
prunedVertexProps->emplace_back(std::move(newVProp));
341414
}

src/graph/visitor/PrunePropertiesVisitor.h

+5
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class PrunePropertiesVisitor final : public PlanNodeVisitor {
5555
// prune properties in Traverse according to the used properties collected previous
5656
void pruneCurrent(Traverse *node);
5757

58+
void visit(ScanEdges *node) override;
59+
60+
void pruneCurrent(ScanEdges *node);
61+
5862
void visit(AppendVertices *node) override;
5963
// \param node, the current node to visit
6064
// \param used, whether properties in current node are used
@@ -80,6 +84,7 @@ class PrunePropertiesVisitor final : public PlanNodeVisitor {
8084
GraphSpaceID spaceID_;
8185
Status status_;
8286
bool rootNode_{true};
87+
const int unKnowType_ = 0;
8388
};
8489

8590
} // namespace graph

0 commit comments

Comments
 (0)