Skip to content

Commit

Permalink
adapt for shortest path api with skip-degree
Browse files Browse the repository at this point in the history
implement: #391

Change-Id: Ied258ed24edf1529eb47f3fa874f3df0b870ca80
  • Loading branch information
zhoney committed Apr 4, 2019
1 parent dee81f6 commit 665f914
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 17 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.baidu.hugegraph</groupId>
<artifactId>hugegraph-client</artifactId>
<version>1.6.10</version>
<version>1.6.11</version>
<packaging>jar</packaging>

<name>hugegraph-client</name>
Expand Down Expand Up @@ -113,7 +113,7 @@
<manifestEntries>
<!-- Must be on one line, otherwise the automatic
upgrade script cannot replace the version number -->
<Implementation-Version>1.6.10.0</Implementation-Version>
<Implementation-Version>1.6.11.0</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.baidu.hugegraph.rest.RestResult;
import com.baidu.hugegraph.structure.constant.Direction;
import com.baidu.hugegraph.structure.graph.Path;
import com.baidu.hugegraph.util.E;

public class ShortestPathAPI extends TraversersAPI {

Expand All @@ -42,13 +43,14 @@ protected String type() {

public Path get(Object sourceId, Object targetId,
Direction direction, String label, int maxDepth,
long degree, long capacity) {
long degree, long skipDegree, long capacity) {
String source = GraphAPI.formatVertexId(sourceId, false);
String target = GraphAPI.formatVertexId(targetId, false);

checkPositive(maxDepth, "Max depth of shortest path");
checkDegree(degree);
checkCapacity(capacity);
checkSkipDegree(skipDegree, degree, capacity);

Map<String, Object> params = new LinkedHashMap<>();
params.put("source", source);
Expand All @@ -57,9 +59,29 @@ public Path get(Object sourceId, Object targetId,
params.put("label", label);
params.put("max_depth", maxDepth);
params.put("max_degree", degree);
params.put("skip_degree", skipDegree);
params.put("capacity", capacity);
RestResult result = this.client.get(this.path(), params);
List<Object> vertices = result.readList("path", Object.class);
return new Path(vertices);
}

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);
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/baidu/hugegraph/driver/HugeClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private void initManagers(RestClient client, String graph) {
private void checkServerApiVersion() {
VersionUtil.Version apiVersion = VersionUtil.Version.of(
this.version.getApiVersion());
VersionUtil.check(apiVersion, "0.36", "0.37",
VersionUtil.check(apiVersion, "0.37", "0.38",
"hugegraph-api in server");
}

Expand Down
33 changes: 23 additions & 10 deletions src/main/java/com/baidu/hugegraph/driver/TraverserManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@

import static com.baidu.hugegraph.structure.constant.Traverser.DEFAULT_PAGE_LIMIT;

import static com.baidu.hugegraph.structure.constant.Traverser.DEFAULT_CAPACITY;
import static com.baidu.hugegraph.structure.constant.Traverser.DEFAULT_DEGREE;
import static com.baidu.hugegraph.structure.constant.Traverser.DEFAULT_ELEMENTS_LIMIT;

public class TraverserManager {

private final GraphManager graphManager;
Expand Down Expand Up @@ -89,15 +93,22 @@ public Path shortestPath(Object sourceId, Object targetId,

public Path shortestPath(Object sourceId, Object targetId,
Direction direction, String label, int maxDepth) {
return this.shortestPath(sourceId, targetId, direction,
label, maxDepth, -1L, -1L);
return this.shortestPath(sourceId, targetId, direction, label, maxDepth,
DEFAULT_DEGREE, DEFAULT_CAPACITY);
}

public Path shortestPath(Object sourceId, Object targetId,
Direction direction, String label, int maxDepth,
long degree, long capacity) {
return this.shortestPathAPI.get(sourceId, targetId, direction,
label, maxDepth, degree, capacity);
return this.shortestPath(sourceId, targetId, direction, label,
maxDepth, degree, 0L, capacity);
}

public Path shortestPath(Object sourceId, Object targetId,
Direction direction, String label, int maxDepth,
long degree, long skipDegree, long capacity) {
return this.shortestPathAPI.get(sourceId, targetId, direction, label,
maxDepth, degree, skipDegree, capacity);
}

public List<Path> paths(Object sourceId, Object targetId,
Expand All @@ -109,8 +120,8 @@ public List<Path> paths(Object sourceId, Object targetId,
public List<Path> paths(Object sourceId, Object targetId,
Direction direction, String label,
int maxDepth, long limit) {
return this.paths(sourceId, targetId, direction,
label, maxDepth, -1L, -1L, limit);
return this.paths(sourceId, targetId, direction, label, maxDepth,
DEFAULT_DEGREE, DEFAULT_CAPACITY, limit);
}

public List<Path> paths(Object sourceId, Object targetId,
Expand All @@ -129,8 +140,8 @@ public List<Path> crosspoint(Object sourceId, Object targetId,
public List<Path> crosspoint(Object sourceId, Object targetId,
Direction direction, String label,
int maxDepth, int limit) {
return this.crosspoint(sourceId, targetId, direction,
label, maxDepth, -1L, -1L, limit);
return this.crosspoint(sourceId, targetId, direction, label, maxDepth,
DEFAULT_DEGREE, DEFAULT_CAPACITY, limit);
}

public List<Path> crosspoint(Object sourceId, Object targetId,
Expand All @@ -148,7 +159,8 @@ public List<Object> kout(Object sourceId, Direction direction, int depth) {
public List<Object> kout(Object sourceId, Direction direction,
String label, int depth, boolean nearest) {
return this.kout(sourceId, direction, label, depth, nearest,
-1L, -1L, -1L);
DEFAULT_DEGREE, DEFAULT_CAPACITY,
DEFAULT_ELEMENTS_LIMIT);
}

public List<Object> kout(Object sourceId, Direction direction,
Expand All @@ -165,7 +177,8 @@ public List<Object> kneighbor(Object sourceId, Direction direction,

public List<Object> kneighbor(Object sourceId, Direction direction,
String label, int depth) {
return this.kneighbor(sourceId, direction, label, depth, -1L, -1L);
return this.kneighbor(sourceId, direction, label, depth,
DEFAULT_DEGREE, DEFAULT_ELEMENTS_LIMIT);
}

public List<Object> kneighbor(Object sourceId, Direction direction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
public class Traverser {

public static final long DEFAULT_CAPACITY = 10_000_000L;
public static final long DEFAULT_PATHS_LIMIT = 10L;
public static final long DEFAULT_ELEMENTS_LIMIT = 10_000_000L;
public static final long DEFAULT_DEGREE = 10_000L;
public static final long DEFAULT_CROSSPOINT_LIMIT = 10_000L;
public static final long DEFAULT_PATHS_LIMIT = 10L;
public static final long DEFAULT_SAMPLE = 100L;
public static final double DEFAULT_WEIGHT = 0.0D;
public static final long DEFAULT_PAGE_LIMIT = 100_000L;
Expand Down
175 changes: 173 additions & 2 deletions src/test/java/com/baidu/hugegraph/api/TraverserApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.baidu.hugegraph.driver.SchemaManager;
import com.baidu.hugegraph.exception.ServerException;
import com.baidu.hugegraph.structure.constant.Direction;
import com.baidu.hugegraph.structure.constant.T;
import com.baidu.hugegraph.structure.graph.Edge;
import com.baidu.hugegraph.structure.graph.Edges;
import com.baidu.hugegraph.structure.graph.Path;
Expand Down Expand Up @@ -69,7 +70,7 @@ public void testShortestPath() {
Object rippleId = getVertexId("software", "name", "ripple");

Path path = shortestPathAPI.get(markoId, rippleId, Direction.BOTH,
null, 3, -1L, -1L);
null, 3, -1L, 0L, -1L);
Assert.assertEquals(3, path.size());
Assert.assertEquals(markoId, path.objects().get(0));
Assert.assertEquals(joshId, path.objects().get(1));
Expand All @@ -83,10 +84,180 @@ public void testShortestPathWithCapacity() {

Assert.assertThrows(ServerException.class, () -> {
shortestPathAPI.get(markoId, rippleId, Direction.BOTH,
null, 3, -1L, 1L);
null, 3, 1L, 0L, 2L);
});
}

@Test
public void testShortestPathWithIllegalArgs() {
// The max depth shouldn't be 0 or negative
Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, -1, 1L, 0L, 2L);
});

Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 0, 1L, 0L, 2L);
});

// The degree shouldn't be 0 or negative but NO_LIMIT(-1)
Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 5, 0L, 0L, 2L);
});

Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 5, -3L, 0L, 2L);
});

// The skipped degree shouldn't be negative
Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 5, 1L, -1L, 2L);
});

// The skipped degree shouldn't be >= capacity
Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 5, 1L, 2L, 2L);
});

// The skipped degree shouldn't be < degree
Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 5, 3L, 2L, 10L);
});

Assert.assertThrows(IllegalArgumentException.class, () -> {
shortestPathAPI.get("a", "b", Direction.BOTH,
null, 5, -1L, 2L, 10L);
});
}

@Test
public void testShortestPathWithSkipDegree() {
schema().vertexLabel("node")
.useCustomizeNumberId()
.ifNotExist()
.create();

schema().edgeLabel("link")
.sourceLabel("node").targetLabel("node")
.ifNotExist()
.create();

Vertex v1 = graph().addVertex(T.label, "node", T.id, 1);
Vertex v2 = graph().addVertex(T.label, "node", T.id, 2);
Vertex v3 = graph().addVertex(T.label, "node", T.id, 3);
Vertex v4 = graph().addVertex(T.label, "node", T.id, 4);
Vertex v5 = graph().addVertex(T.label, "node", T.id, 5);
Vertex v6 = graph().addVertex(T.label, "node", T.id, 6);
Vertex v7 = graph().addVertex(T.label, "node", T.id, 7);
Vertex v8 = graph().addVertex(T.label, "node", T.id, 8);
Vertex v9 = graph().addVertex(T.label, "node", T.id, 9);
Vertex v10 = graph().addVertex(T.label, "node", T.id, 10);
Vertex v11 = graph().addVertex(T.label, "node", T.id, 11);
Vertex v12 = graph().addVertex(T.label, "node", T.id, 12);
Vertex v13 = graph().addVertex(T.label, "node", T.id, 13);
Vertex v14 = graph().addVertex(T.label, "node", T.id, 14);
Vertex v15 = graph().addVertex(T.label, "node", T.id, 15);
Vertex v16 = graph().addVertex(T.label, "node", T.id, 16);
Vertex v17 = graph().addVertex(T.label, "node", T.id, 17);
Vertex v18 = graph().addVertex(T.label, "node", T.id, 18);

// Path length 5
v1.addEdge("link", v2);
v2.addEdge("link", v3);
v3.addEdge("link", v4);
v4.addEdge("link", v5);
v5.addEdge("link", v6);

List<Object> path1 = ImmutableList.of(v1.id(), v2.id(), v3.id(),
v4.id(), v5.id(), v6.id());

// Path length 4
v1.addEdge("link", v7);
v7.addEdge("link", v8);
v8.addEdge("link", v9);
v9.addEdge("link", v6);

List<Object> path2 = ImmutableList.of(v1.id(), v7.id(), v8.id(),
v9.id(), v6.id());

// Path length 3
v1.addEdge("link", v10);
v10.addEdge("link", v11);
v11.addEdge("link", v6);

List<Object> path3 = ImmutableList.of(v1.id(), v10.id(),
v11.id(), v6.id());

// Add other 3 neighbor for v7
v7.addEdge("link", v12);
v7.addEdge("link", v13);
v7.addEdge("link", v14);

// Add other 4 neighbor for v10
v10.addEdge("link", v15);
v10.addEdge("link", v16);
v10.addEdge("link", v17);
v10.addEdge("link", v18);

Path path = shortestPathAPI.get(v1.id(), v6.id(), Direction.OUT,
null, 5, 6L, 6L, -1L);
Assert.assertEquals(4, path.size());
Assert.assertEquals(v1.id(), path.objects().get(0));
Assert.assertEquals(v10.id(), path.objects().get(1));
Assert.assertEquals(v11.id(), path.objects().get(2));
Assert.assertEquals(v6.id(), path.objects().get(3));

path = shortestPathAPI.get(v1.id(), v6.id(), Direction.OUT,
null, 5, 5L, 5L, -1L);
Assert.assertEquals(5, path.size());
Assert.assertEquals(v1.id(), path.objects().get(0));
Assert.assertEquals(v7.id(), path.objects().get(1));
Assert.assertEquals(v8.id(), path.objects().get(2));
Assert.assertEquals(v9.id(), path.objects().get(3));
Assert.assertEquals(v6.id(), path.objects().get(4));

path = shortestPathAPI.get(v1.id(), v6.id(), Direction.OUT,
null, 5, 4L, 4L, -1L);
Assert.assertEquals(6, path.size());
Assert.assertEquals(v1.id(), path.objects().get(0));
Assert.assertEquals(v2.id(), path.objects().get(1));
Assert.assertEquals(v3.id(), path.objects().get(2));
Assert.assertEquals(v4.id(), path.objects().get(3));
Assert.assertEquals(v5.id(), path.objects().get(4));
Assert.assertEquals(v6.id(), path.objects().get(5));

path = shortestPathAPI.get(v1.id(), v6.id(), Direction.OUT,
null, 5, 3L, 6L, -1L);

List<List<Object>> paths = ImmutableList.of(path1, path2, path3);
Assert.assertTrue(path.size() == 4 ||
path.size() == 5 ||
path.size() == 6);
Assert.assertTrue(paths.contains(path.objects()));

path = shortestPathAPI.get(v1.id(), v6.id(), Direction.OUT,
null, 5, 4L, 6L, -1L);

Assert.assertTrue(path.size() == 4 || path.size() == 5);
Assert.assertTrue(path2.equals(path.objects()) ||
path3.equals(path.objects()));

path = shortestPathAPI.get(v1.id(), v6.id(), Direction.OUT,
null, 5, 5L, 6L, -1L);

Assert.assertEquals(4, path.size());
Assert.assertEquals(path3, path.objects());

waitUntilTaskCompleted(edgeLabelAPI.delete("link"));
waitUntilTaskCompleted(vertexLabelAPI.delete("node"));
}

@Test
public void testPaths() {
Object markoId = getVertexId("person", "name", "marko");
Expand Down

0 comments on commit 665f914

Please sign in to comment.