Skip to content

Commit

Permalink
add skip_degree arg for shortest-path API (#433)
Browse files Browse the repository at this point in the history
implements: #391

Change-Id: I6e1916c709b329aa97fde8e2e165703088278e19

Co-authored-by:platypus0127 <[email protected]>
Co-authored-by:zhoney <[email protected]>
  • Loading branch information
zhoney authored and Linary committed Apr 8, 2019
1 parent 58a439a commit 7c7ffe0
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 13 deletions.
2 changes: 1 addition & 1 deletion hugegraph-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>0.36.0.0</Implementation-Version>
<Implementation-Version>0.37.0.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@
import com.baidu.hugegraph.server.RestServer;
import com.baidu.hugegraph.traversal.algorithm.ShortestPathTraverser;
import com.baidu.hugegraph.type.define.Directions;
import com.baidu.hugegraph.util.E;
import com.baidu.hugegraph.util.Log;
import com.codahale.metrics.annotation.Timed;

import static com.baidu.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY;
import static com.baidu.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_DEGREE;
import static com.baidu.hugegraph.traversal.algorithm.HugeTraverser.*;

@Path("graphs/{graph}/traversers/shortestpath")
@Singleton
Expand All @@ -65,13 +65,15 @@ public String get(@Context GraphManager manager,
@QueryParam("max_depth") int depth,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_DEGREE) long degree,
@QueryParam("skip_degree")
@DefaultValue("0") long skipDegree,
@QueryParam("capacity")
@DefaultValue(DEFAULT_CAPACITY) long capacity) {
LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " +
"direction {}, edge label {}, max depth '{}', " +
"max degree '{}' and capacity '{}'",
"max degree '{}', skipped degree '{}' and capacity '{}'",
graph, source, target, direction, edgeLabel, depth,
degree, capacity);
degree, skipDegree, capacity);

Id sourceId = VertexAPI.checkAndParseVertexId(source);
Id targetId = VertexAPI.checkAndParseVertexId(target);
Expand All @@ -82,7 +84,7 @@ public String get(@Context GraphManager manager,
ShortestPathTraverser traverser = new ShortestPathTraverser(g);
List<Id> path = traverser.shortestPath(sourceId, targetId, dir,
edgeLabel, depth, degree,
capacity);
skipDegree, capacity);
return manager.serializer(g).writeIds("path", path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ public final class ApiVersion {
* [0.34] Issue-307: Let VertexAPI use simplified property serializer
* [0.35] Issue-287: Support pagination when do index query
* [0.36] Issue-360: Support paging for scan api
* [0.37] Issue-391: Add skip_super_node for shortest path
*/

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

public static final void check() {
// Check version of hugegraph-core. Firstly do check from version 0.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@

package com.baidu.hugegraph.traversal.algorithm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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;
Expand All @@ -41,21 +43,22 @@ public ShortestPathTraverser(HugeGraph graph) {

public List<Id> shortestPath(Id sourceV, Id targetV, Directions dir,
String label, int depth, long degree,
long capacity) {
long skipDegree, long capacity) {
E.checkNotNull(sourceV, "source vertex id");
E.checkNotNull(targetV, "target vertex id");
E.checkNotNull(dir, "direction");
checkPositive(depth, "max depth");
checkDegree(degree);
checkCapacity(capacity);
checkSkipDegree(skipDegree, degree, capacity);

if (sourceV.equals(targetV)) {
return ImmutableList.of(sourceV);
}

Id labelId = this.getEdgeLabelId(label);
Traverser traverser = new Traverser(sourceV, targetV, dir, labelId,
degree, capacity);
degree, skipDegree, capacity);
List<Id> path;
while (true) {
// Found, reach max depth or reach capacity, stop searching
Expand All @@ -73,6 +76,25 @@ public List<Id> shortestPath(Id sourceV, Id targetV, Directions dir,
return path;
}

private static void checkSkipDegree(long skipDegree, long degree,
long capacity) {
E.checkArgument(skipDegree >= 0L,
"The skipped degree must be >= 0, but got '%s'",
skipDegree);
if (capacity != NO_LIMIT) {
E.checkArgument(degree != NO_LIMIT && degree < capacity,
"The degree must be < capacity");
E.checkArgument(skipDegree < capacity,
"The skipped degree must be < capacity");
}
if (skipDegree > 0L) {
E.checkArgument(degree != NO_LIMIT && skipDegree >= degree,
"The skipped degree must be >= degree, " +
"but got skipped degree '%s' and degree '%s'",
skipDegree, degree);
}
}

private class Traverser {

// TODO: change Map to Set to reduce memory cost
Expand All @@ -82,16 +104,18 @@ private class Traverser {
private final Directions direction;
private final Id label;
private final long degree;
private final long skipDegree;
private final long capacity;
private long size;

public Traverser(Id sourceV, Id targetV, Directions dir,
Id label, long degree, long capacity) {
public Traverser(Id sourceV, Id targetV, Directions dir, Id label,
long degree, long skipDegree, long capacity) {
this.sources.put(sourceV, new Node(sourceV));
this.targets.put(targetV, new Node(targetV));
this.direction = dir;
this.label = label;
this.degree = degree;
this.skipDegree = skipDegree;
this.capacity = capacity;
this.size = 0L;
}
Expand All @@ -101,16 +125,21 @@ public Traverser(Id sourceV, Id targetV, Directions dir,
*/
public List<Id> forward() {
Map<Id, Node> newVertices = newMap();
long degree = this.skipDegree > 0L ? this.skipDegree : this.degree;
// Traversal vertices of previous level
for (Node v : this.sources.values()) {
Iterator<Edge> edges = edgesOfVertex(v.id(), this.direction,
this.label, this.degree);
this.label, degree);
edges = this.skipSuperNodeIfNeeded(edges);
while (edges.hasNext()) {
HugeEdge edge = (HugeEdge) edges.next();
Id target = edge.id().otherVertexId();

// If cross point exists, shortest path found, concat them
if (this.targets.containsKey(target)) {
if (this.superNode(target, this.direction)) {
continue;
}
return v.joinPath(this.targets.get(target));
}

Expand Down Expand Up @@ -140,17 +169,22 @@ public List<Id> forward() {
*/
public List<Id> backward() {
Map<Id, Node> newVertices = newMap();
long degree = this.skipDegree > 0L ? this.skipDegree : this.degree;
Directions opposite = this.direction.opposite();
// Traversal vertices of previous level
for (Node v : this.targets.values()) {
Iterator<Edge> edges = edgesOfVertex(v.id(), opposite,
this.label, this.degree);
this.label, degree);
edges = this.skipSuperNodeIfNeeded(edges);
while (edges.hasNext()) {
HugeEdge edge = (HugeEdge) edges.next();
Id target = edge.id().otherVertexId();

// If cross point exists, shortest path found, concat them
if (this.sources.containsKey(target)) {
if (this.superNode(target, opposite)) {
continue;
}
return v.joinPath(this.sources.get(target));
}

Expand All @@ -174,5 +208,30 @@ public List<Id> backward() {

return PATH_NONE;
}

private Iterator<Edge> skipSuperNodeIfNeeded(Iterator<Edge> edges) {
if (this.skipDegree <= 0L) {
return edges;
}
List<Edge> edgeList = new ArrayList<>();
for (int i = 1; edges.hasNext(); i++) {
if (i <= this.degree) {
edgeList.add(edges.next());
}
if (i >= this.skipDegree) {
return Collections.emptyIterator();
}
}
return edgeList.iterator();
}

private boolean superNode(Id vertex, Directions direction) {
if (this.skipDegree <= 0L) {
return false;
}
Iterator<Edge> edges = edgesOfVertex(vertex, direction,
this.label, this.skipDegree);
return IteratorUtils.count(edges) >= this.skipDegree;
}
}
}

0 comments on commit 7c7ffe0

Please sign in to comment.