From b1a8c396d0fb3e185772584769a8e0b51a0d9aa5 Mon Sep 17 00:00:00 2001 From: zhangyi51 Date: Fri, 24 May 2019 16:03:38 +0800 Subject: [PATCH 1/4] Add sourceInRing args for rings fixed: #523 Change-Id: If8c5cc4d8678f847ce4a5f0388e56aae465d3ea6 --- hugegraph-api/pom.xml | 2 +- .../hugegraph/api/traversers/RaysAPI.java | 2 +- .../hugegraph/api/traversers/RingsAPI.java | 10 +- .../baidu/hugegraph/version/ApiVersion.java | 3 +- .../traversal/algorithm/HugeTraverser.java | 4 +- .../algorithm/SubGraphTraverser.java | 113 ++++++++++++++---- 6 files changed, 106 insertions(+), 28 deletions(-) diff --git a/hugegraph-api/pom.xml b/hugegraph-api/pom.xml index fc27f55e2c..ee328812d7 100644 --- a/hugegraph-api/pom.xml +++ b/hugegraph-api/pom.xml @@ -86,7 +86,7 @@ - 0.39.0.0 + 0.40.0.0 diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java index edeccbe34e..f5d9b55cc5 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java @@ -72,7 +72,7 @@ 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 '{}'", + "max degree '{}', capacity '{}' and limit '{}'", graph, sourceV, direction, edgeLabel, depth, degree, limit); Id source = VertexAPI.checkAndParseVertexId(sourceV); diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java index 3921f3b4e1..bfbbf3cf24 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java @@ -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,7 +74,8 @@ 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 '{}'", + "source in ring '{}', max degree '{}', capacity '{}' " + + "and limit '{}'", graph, sourceV, direction, edgeLabel, depth, degree, limit); Id source = VertexAPI.checkAndParseVertexId(sourceV); @@ -82,8 +85,9 @@ public String get(@Context GraphManager manager, SubGraphTraverser traverser = new SubGraphTraverser(g); List paths = traverser.rings(source, dir, edgeLabel, - depth, degree, - capacity, limit); + depth, sourceInRing, + degree, capacity, + limit); return manager.serializer(g).writePaths("rings", paths, false); } } diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java index 80656b1552..09b635dd79 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java @@ -87,10 +87,11 @@ public final class ApiVersion { * * version 0.10: * [0.39] Issue-522: Add profile RESTful API + * [0.40] Issue-523: Add sourceInRing 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 diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java index 279064fcaa..16b3603e98 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java @@ -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 this.id.equals(other.id) && + Objects.equals(this.parent, other.parent); } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java index 79d8e18a77..642b7b14d7 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java @@ -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 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 rings(Id sourceV, Directions dir, String label, - int depth, long degree, long capacity, long limit) { + public List 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 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,13 +68,13 @@ private List 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 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; } @@ -78,27 +82,47 @@ private List subGraphPaths(Id sourceV, Directions dir, String label, return paths; } + private static boolean multiEdges(List edges, Id target) { + int count = 0; + for (Edge edge : edges) { + if (((HugeEdge) edge).id().otherVertexId().equals(target)) { + if (++count >= 2) { + return true; + } + } + } + assert count == 1; + return false; + } + private class Traverser { + private final Id source; private MultivaluedMap sources = newMultivalueMap(); private Set 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,9 @@ public List forward(Directions direction) { // Traversal vertices of previous level for (Map.Entry> entry : this.sources.entrySet()) { Id vid = entry.getKey(); - edges = edgesOfVertex(vid, direction, this.label, this.degree); + List edgeList = IteratorUtils.list(edgesOfVertex( + vid, direction, this.label, this.degree)); + edges = edgeList.iterator(); if (!edges.hasNext()) { // Reach the end, rays found @@ -128,33 +154,78 @@ public List forward(Directions direction) { } } } + + int neighborCount = 0; + Set currentNeighbors = new HashSet<>(); while (edges.hasNext()) { + neighborCount++; HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + // Avoid dedup 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 prePath = n.path(); - prePath.add(target); - paths.add(new Path(null, prePath)); + + // Rays found if fake ring like: + // path is pattern: A->B<-A && A is only neighbor of B + if (!this.rings && target.equals(node.parent().id()) && + neighborCount == 1 && !edges.hasNext() && + direction == Directions.BOTH) { + 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 (multiEdges(edgeList, target)) { + ringsFound = true; + } + } + + if (ringsFound) { + List 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 list : newVertices.values()) { + for (Node n : list) { + paths.add(new Path(null, n.path())); + } + } + } + return paths; } From 112e831d609b5fde7a0e025cbed54065f6e7e553 Mon Sep 17 00:00:00 2001 From: zhangyi51 Date: Wed, 5 Jun 2019 12:12:32 +0800 Subject: [PATCH 2/4] improve Change-Id: Ie99226fbb53fb3827887b76cdc4949cf018c7440 --- .../baidu/hugegraph/api/traversers/RaysAPI.java | 3 ++- .../baidu/hugegraph/api/traversers/RingsAPI.java | 3 ++- .../com/baidu/hugegraph/version/ApiVersion.java | 2 +- .../traversal/algorithm/HugeTraverser.java | 2 +- .../traversal/algorithm/SubGraphTraverser.java | 15 +++++++++------ 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java index f5d9b55cc5..c4996a79dd 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RaysAPI.java @@ -73,7 +73,8 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get rays paths from '{}' with " + "direction '{}', edge label '{}', max depth '{}', " + "max degree '{}', capacity '{}' and limit '{}'", - graph, sourceV, direction, edgeLabel, depth, degree, limit); + graph, sourceV, direction, edgeLabel, depth, degree, + capacity, limit); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java index bfbbf3cf24..814cdbdd76 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/traversers/RingsAPI.java @@ -76,7 +76,8 @@ public String get(@Context GraphManager manager, "direction '{}', edge label '{}', max depth '{}', " + "source in ring '{}', max degree '{}', capacity '{}' " + "and limit '{}'", - graph, sourceV, direction, edgeLabel, depth, degree, limit); + graph, sourceV, direction, edgeLabel, depth, sourceInRing, + degree, capacity, limit); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java index 09b635dd79..427048464f 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java @@ -87,7 +87,7 @@ public final class ApiVersion { * * version 0.10: * [0.39] Issue-522: Add profile RESTful API - * [0.40] Issue-523: Add sourceInRing args for rings 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 diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java index 16b3603e98..912471d657 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/HugeTraverser.java @@ -380,7 +380,7 @@ 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); } } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java index 642b7b14d7..81d3d6c1a8 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java @@ -82,7 +82,7 @@ private List subGraphPaths(Id sourceV, Directions dir, String label, return paths; } - private static boolean multiEdges(List edges, Id target) { + private static boolean containsMultiEdges(List edges, Id target) { int count = 0; for (Edge edge : edges) { if (((HugeEdge) edge).id().otherVertexId().equals(target)) { @@ -175,11 +175,13 @@ public List forward(Directions direction) { continue; } - // Rays found if fake ring like: + // Rays found if it's fake ring like: // path is pattern: A->B<-A && A is only neighbor of B - if (!this.rings && target.equals(node.parent().id()) && - neighborCount == 1 && !edges.hasNext() && - direction == Directions.BOTH) { + 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()) { @@ -197,7 +199,8 @@ public List forward(Directions direction) { ringsFound = true; } else if (direction != Directions.BOTH) { ringsFound = true; - } else if (multiEdges(edgeList, target)) { + } else if (containsMultiEdges(edgeList, + target)) { ringsFound = true; } } From 0c79c1929c9461fb28c37095493b42651cba0461 Mon Sep 17 00:00:00 2001 From: zhangyi51 Date: Wed, 5 Jun 2019 14:33:47 +0800 Subject: [PATCH 3/4] tiny improve Change-Id: I9834c43a2c04c120844cf77029c8cc0e2af02076 --- .../hugegraph/traversal/algorithm/SubGraphTraverser.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java index 81d3d6c1a8..8cd4b55315 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java @@ -82,11 +82,11 @@ private List subGraphPaths(Id sourceV, Directions dir, String label, return paths; } - private static boolean containsMultiEdges(List edges, Id target) { + private static boolean hasMultiEdges(List edges, Id target) { int count = 0; for (Edge edge : edges) { if (((HugeEdge) edge).id().otherVertexId().equals(target)) { - if (++count >= 2) { + if (++count > 1) { return true; } } @@ -199,8 +199,7 @@ public List forward(Directions direction) { ringsFound = true; } else if (direction != Directions.BOTH) { ringsFound = true; - } else if (containsMultiEdges(edgeList, - target)) { + } else if (hasMultiEdges(edgeList, target)) { ringsFound = true; } } From c649e26f3ac15714ee10945d2e034dc2eba9ac29 Mon Sep 17 00:00:00 2001 From: zhangyi51 Date: Fri, 14 Jun 2019 12:11:12 +0800 Subject: [PATCH 4/4] improve Change-Id: I88fbcfa83ed5259f20997dbbf0b1c752eac494b4 --- .../baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java index 8cd4b55315..1a7d63911c 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/algorithm/SubGraphTraverser.java @@ -136,6 +136,7 @@ public List forward(Directions direction) { // Traversal vertices of previous level for (Map.Entry> entry : this.sources.entrySet()) { Id vid = entry.getKey(); + // Record edgeList to determine if multiple edges exist List edgeList = IteratorUtils.list(edgesOfVertex( vid, direction, this.label, this.degree)); edges = edgeList.iterator(); @@ -161,7 +162,7 @@ public List forward(Directions direction) { neighborCount++; HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); - // Avoid dedup path + // Avoid deduplicate path if (currentNeighbors.contains(target)) { continue; }