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

Add source_in_ring args for rings API #528

Merged
merged 4 commits into from
Jul 1, 2019
Merged
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
2 changes: 1 addition & 1 deletion hugegraph-api/pom.xml
Original file line number Diff line number Diff line change
@@ -86,7 +86,7 @@
</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>0.39.0.0</Implementation-Version>
<Implementation-Version>0.40.0.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
Original file line number Diff line number Diff line change
@@ -72,8 +72,9 @@ public String get(@Context GraphManager manager,
@DefaultValue(DEFAULT_PATHS_LIMIT) long limit) {
LOG.debug("Graph [{}] get rays paths from '{}' with " +
"direction '{}', edge label '{}', max depth '{}', " +
"max degree '{}' and limit '{}'",
graph, sourceV, direction, edgeLabel, depth, degree, limit);
"max degree '{}', capacity '{}' and limit '{}'",
zhoney marked this conversation as resolved.
Show resolved Hide resolved
graph, sourceV, direction, edgeLabel, depth, degree,
capacity, limit);

Id source = VertexAPI.checkAndParseVertexId(sourceV);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
Original file line number Diff line number Diff line change
@@ -64,6 +64,8 @@ public String get(@Context GraphManager manager,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_depth") int depth,
@QueryParam("source_in_ring")
@DefaultValue("true") boolean sourceInRing,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_DEGREE) long degree,
@QueryParam("capacity")
@@ -72,8 +74,10 @@ public String get(@Context GraphManager manager,
@DefaultValue(DEFAULT_PATHS_LIMIT) long limit) {
LOG.debug("Graph [{}] get rings paths reachable from '{}' with " +
"direction '{}', edge label '{}', max depth '{}', " +
"max degree '{}' and limit '{}'",
graph, sourceV, direction, edgeLabel, depth, degree, limit);
"source in ring '{}', max degree '{}', capacity '{}' " +
"and limit '{}'",
zhoney marked this conversation as resolved.
Show resolved Hide resolved
graph, sourceV, direction, edgeLabel, depth, sourceInRing,
degree, capacity, limit);

Id source = VertexAPI.checkAndParseVertexId(sourceV);
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));
@@ -82,8 +86,9 @@ public String get(@Context GraphManager manager,

SubGraphTraverser traverser = new SubGraphTraverser(g);
List<HugeTraverser.Path> paths = traverser.rings(source, dir, edgeLabel,
depth, degree,
capacity, limit);
depth, sourceInRing,
degree, capacity,
limit);
return manager.serializer(g).writePaths("rings", paths, false);
}
}
Original file line number Diff line number Diff line change
@@ -87,10 +87,11 @@ public final class ApiVersion {
*
* version 0.10:
* [0.39] Issue-522: Add profile RESTful API
* [0.40] Issue-523: Add source_in_ring args for rings RESTful API
*/

// The second parameter of Version.of() is for IDE running without JAR
public static final Version VERSION = Version.of(ApiVersion.class, "0.39");
public static final Version VERSION = Version.of(ApiVersion.class, "0.40");

public static final void check() {
// Check version of hugegraph-core. Firstly do check from version 0.3
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.ws.rs.core.MultivaluedHashMap;
@@ -379,7 +380,8 @@ public boolean equals(Object object) {
return false;
}
Node other = (Node) object;
return this.id.equals(other.id);
return Objects.equals(this.id, other.id) &&
Objects.equals(this.parent, other.parent);
}
}

Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
package com.baidu.hugegraph.traversal.algorithm;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -28,6 +29,7 @@
import javax.ws.rs.core.MultivaluedMap;

import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;

import com.baidu.hugegraph.HugeGraph;
import com.baidu.hugegraph.backend.id.Id;
@@ -44,18 +46,20 @@ public SubGraphTraverser(HugeGraph graph) {
public List<Path> rays(Id sourceV, Directions dir, String label,
int depth, long degree, long capacity, long limit) {
return this.subGraphPaths(sourceV, dir, label, depth, degree,
capacity, limit, false);
capacity, limit, false, false);
}

public List<Path> rings(Id sourceV, Directions dir, String label,
int depth, long degree, long capacity, long limit) {
public List<Path> rings(Id sourceV, Directions dir, String label, int depth,
boolean sourceInRing, long degree, long capacity,
long limit) {
return this.subGraphPaths(sourceV, dir, label, depth, degree,
capacity, limit, true);
capacity, limit, true, sourceInRing);
}

private List<Path> subGraphPaths(Id sourceV, Directions dir, String label,
int depth, long degree, long capacity,
long limit, boolean rings) {
long limit, boolean rings,
boolean sourceInRing) {
E.checkNotNull(sourceV, "source vertex id");
E.checkNotNull(dir, "direction");
checkPositive(depth, "max depth");
@@ -64,41 +68,61 @@ private List<Path> subGraphPaths(Id sourceV, Directions dir, String label,
checkLimit(limit);

Id labelId = this.getEdgeLabelId(label);
Traverser traverser = new Traverser(sourceV, labelId, degree,
capacity, limit, rings);
Traverser traverser = new Traverser(sourceV, labelId, depth, degree,
capacity, limit, rings,
sourceInRing);
List<Path> paths = new ArrayList<>();
while (true) {
paths.addAll(traverser.forward(dir));
boolean reachDepth = rings ? --depth <= 0 : depth-- <= 0;
if (reachDepth || traverser.reachLimit() ||
if (--depth <= 0 || traverser.reachLimit() ||
traverser.finished()) {
break;
}
}
return paths;
}

private static boolean hasMultiEdges(List<Edge> edges, Id target) {
int count = 0;
for (Edge edge : edges) {
if (((HugeEdge) edge).id().otherVertexId().equals(target)) {
if (++count > 1) {
return true;
}
}
}
assert count == 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems count maybe = 0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there already exists one edge connected to 'target', so count must be >= 1, false means count == 1

return false;
}

private class Traverser {

private final Id source;
private MultivaluedMap<Id, Node> sources = newMultivalueMap();
private Set<Id> accessedVertices = newSet();

private final Id label;
private int depth;
private final long degree;
private final long capacity;
private final long limit;
private final boolean rings;
private final boolean sourceInRing;
private long pathCount;

public Traverser(Id sourceV, Id label, long degree,
long capacity, long limit, boolean rings) {
public Traverser(Id sourceV, Id label, int depth, long degree,
long capacity, long limit, boolean rings,
boolean sourceInRing) {
this.source = sourceV;
this.sources.add(sourceV, new Node(sourceV));
this.accessedVertices.add(sourceV);
this.label = label;
this.depth = depth;
this.degree = degree;
this.capacity = capacity;
this.limit = limit;
this.rings = rings;
this.sourceInRing = sourceInRing;
this.pathCount = 0L;
}

@@ -112,7 +136,10 @@ public List<Path> forward(Directions direction) {
// Traversal vertices of previous level
for (Map.Entry<Id, List<Node>> entry : this.sources.entrySet()) {
Id vid = entry.getKey();
edges = edgesOfVertex(vid, direction, this.label, this.degree);
// Record edgeList to determine if multiple edges exist
List<Edge> edgeList = IteratorUtils.list(edgesOfVertex(
zhoney marked this conversation as resolved.
Show resolved Hide resolved
vid, direction, this.label, this.degree));
edges = edgeList.iterator();

if (!edges.hasNext()) {
// Reach the end, rays found
@@ -128,33 +155,80 @@ public List<Path> forward(Directions direction) {
}
}
}

int neighborCount = 0;
Set<Id> currentNeighbors = new HashSet<>();
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 n : entry.getValue()) {
if (!n.contains(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, n));
newVertices.add(target, new Node(target, node));
continue;
}
// Rings found and expect rings
if (this.rings) {
assert n.contains(target);
List<Id> prePath = n.path();
prePath.add(target);
paths.add(new Path(null, prePath));

// 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(null, node.path()));
this.pathCount++;
if (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 Path(null, path));
this.pathCount++;
if (reachLimit()) {
return paths;
}
}
}
}
}
}
// Re-init sources
this.sources = newVertices;

if (!rings && --this.depth <= 0) {
for (List<Node> list : newVertices.values()) {
for (Node n : list) {
paths.add(new Path(null, n.path()));
}
}
}

return paths;
}