in hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SubGraphTraverser.java [134:239]
public PathSet forward(Directions direction) {
PathSet paths = new PathSet();
MultivaluedMap<Id, Node> newVertices = newMultivalueMap();
Iterator<Edge> edges;
// Traversal vertices of previous level
for (Map.Entry<Id, List<Node>> entry : this.sources.entrySet()) {
Id vid = entry.getKey();
// Record edgeList to determine if multiple edges exist
List<Edge> edgeList = IteratorUtils.list(edgesOfVertex(
vid, direction, this.label, this.degree));
edges = edgeList.iterator();
if (!edges.hasNext()) {
// Reach the end, rays found
if (this.rings) {
continue;
}
for (Node n : entry.getValue()) {
// Store rays
paths.add(new Path(n.path()));
this.pathCount++;
if (this.reachLimit()) {
return paths;
}
}
}
int neighborCount = 0;
Set<Id> currentNeighbors = newIdSet();
while (edges.hasNext()) {
neighborCount++;
HugeEdge edge = (HugeEdge) edges.next();
Id target = edge.id().otherVertexId();
// Avoid deduplicate path
if (currentNeighbors.contains(target)) {
continue;
}
currentNeighbors.add(target);
this.accessedVertices.add(target);
for (Node node : entry.getValue()) {
// No ring, continue
if (!node.contains(target)) {
// Add node to next start-nodes
newVertices.add(target, new Node(target, node));
continue;
}
// Rays found if it's fake ring like:
// path is pattern: A->B<-A && A is only neighbor of B
boolean uniqueEdge = neighborCount == 1 &&
!edges.hasNext();
boolean bothBack = target.equals(node.parent().id()) &&
direction == Directions.BOTH;
if (!this.rings && bothBack && uniqueEdge) {
paths.add(new Path(node.path()));
this.pathCount++;
if (this.reachLimit()) {
return paths;
}
}
// Actual rings found
if (this.rings) {
boolean ringsFound = false;
// 1. sourceInRing is false, or
// 2. sourceInRing is true and target == source
if (!sourceInRing || target.equals(this.source)) {
if (!target.equals(node.parent().id())) {
ringsFound = true;
} else if (direction != Directions.BOTH) {
ringsFound = true;
} else if (hasMultiEdges(edgeList, target)) {
ringsFound = true;
}
}
if (ringsFound) {
List<Id> path = node.path();
path.add(target);
paths.add(new RingPath(null, path));
this.pathCount++;
if (this.reachLimit()) {
return paths;
}
}
}
}
}
}
// Re-init sources
this.sources = newVertices;
if (!this.rings && --this.depth <= 0) {
for (List<Node> list : newVertices.values()) {
for (Node n : list) {
paths.add(new Path(n.path()));
this.pathCount++;
if (this.reachLimit()) {
return paths;
}
}
}
}
return paths;
}