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

Skip redudant self-reflective edges in GetNeighborsNode #4943

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/graph/executor/query/TraverseExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
// invoke the getNeighbors interface, according to the number of times specified by the user,
// and assemble the result into paths
//
// The definition of path is : array of vertex and edges
// Path is an array of vertex and edges physically.
// Its definition is a trail, in which all edges are distinct. It's different to a walk
// which allows duplicated vertices and edges, and a path where all vertices and edges
// are distinct.
//
// Eg a->b->c. path is [Vertex(a), [Edge(a->b), Vertex(b), Edge(b->c), Vertex(c)]]
// the purpose is to extract the path by pathBuildExpression
// `resDs_` : keep result dataSet
Expand Down
21 changes: 21 additions & 0 deletions src/storage/exec/GetNeighborsNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class GetNeighborsNode : public QueryNode<VertexID> {
return nebula::cpp2::ErrorCode::SUCCEEDED;
}
auto key = upstream_->key();
if (isDuplicatedSelfReflectiveEdge(key)) {
continue;
}
auto reader = upstream_->reader();
auto props = context_->props_;
auto columnIdx = context_->columnIdx_;
Expand All @@ -138,6 +141,24 @@ class GetNeighborsNode : public QueryNode<VertexID> {
return nebula::cpp2::ErrorCode::SUCCEEDED;
}

bool isDuplicatedSelfReflectiveEdge(const folly::StringPiece& key) {
folly::StringPiece srcID = NebulaKeyUtils::getSrcId(context_->vIdLen(), key);
folly::StringPiece dstID = NebulaKeyUtils::getDstId(context_->vIdLen(), key);
if (srcID == dstID) {
// self-reflective edge
std::string rank = std::to_string(NebulaKeyUtils::getRank(context_->vIdLen(), key));
auto edgeType = NebulaKeyUtils::getEdgeType(context_->vIdLen(), key);
edgeType = edgeType > 0 ? edgeType : -edgeType;
std::string type = std::to_string(edgeType);
std::string localKey = type + rank + srcID.str();
if (!visitedSelfReflectiveEdges_.insert(localKey).second) {
return true;
}
}
return false;
}

std::unordered_set<std::string> visitedSelfReflectiveEdges_;
RuntimeContext* context_;
IterateNode<VertexID>* hashJoinNode_;
IterateNode<VertexID>* upstream_;
Expand Down
40 changes: 40 additions & 0 deletions tests/tck/features/match/SelfReflectiveEdges.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (c) 2022 vesoft inc. All rights reserved.
#
# This source code is licensed under Apache 2.0 License.
Feature: Matches on self-reflective edges

Scenario: no duplicated self reflective edges
Given a graph with space named "nba"
And having executed:
"""
insert vertex player (name, age) values "Hades":("Hades", 99999);
xtcyclist marked this conversation as resolved.
Show resolved Hide resolved
insert vertex team (name) values "Underworld":("Underworld");
insert edge like (likeness) values "Hades"->"Hades":(3000);
insert edge teammate (start_year, end_year) values "Hades"->"Hades":(3000, 3000);
insert edge serve (start_year, end_year) values "Hades"->"Underworld":(0, 99999);
"""
When executing query:
"""
MATCH x = (n0)-[e1]->(n1)-[e2]-(n0) WHERE id(n0) == "Hades" and id(n1) == "Hades" return e1, e2
"""
Then the result should be, in any order:
| e1 | e2 |
| [:teammate "Hades"->"Hades" @0 {end_year: 3000, start_year: 3000}] | [:like "Hades"->"Hades" @0 {likeness: 3000}] |
| [:like "Hades"->"Hades" @0 {likeness: 3000}] | [:teammate "Hades"->"Hades" @0 {end_year: 3000, start_year: 3000}] |
When executing query:
"""
MATCH x = (n0)-[e1]->(n1)<-[e2]-(n0) WHERE id(n0) == "Hades" and id(n1) == "Hades" return e1, e2
"""
Then the result should be, in any order:
| e1 | e2 |
| [:teammate "Hades"->"Hades" @0 {end_year: 3000, start_year: 3000}] | [:like "Hades"->"Hades" @0 {likeness: 3000}] |
| [:like "Hades"->"Hades" @0 {likeness: 3000}] | [:teammate "Hades"->"Hades" @0 {end_year: 3000, start_year: 3000}] |
When executing query:
"""
DELETE EDGE serve "Hades"->"Underworld";
DELETE EDGE teammate "Hades"->"Hades";
DELETE EDGE like "Hades"->"Hades";
DELETE VERTEX "Underworld";
DELETE VERTEX "Hades";
"""
Then the execution should be successful