Skip to content

Commit

Permalink
Skip redudant self-reflective edges in GetNeighborsNode (#4943)
Browse files Browse the repository at this point in the history
* skipped duplicated self-reflective edges in GetNeighbors.

* add tck.

* update tck

* update tck.

* change string to folly:StringPiece for srcID and dstID.
  • Loading branch information
xtcyclist authored Dec 6, 2022
1 parent 04ea700 commit 81feb43
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
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);
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

0 comments on commit 81feb43

Please sign in to comment.