From 8a8f9c75ef70e2b9dcf2e2e696176e273f3a2f24 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 11:08:13 +0800 Subject: [PATCH 01/16] chore: improve gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 47bbf40170..7eca2cb39a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ upload-files/ demo* gen-java *.class +swagger-ui-* +hugegraph-dist/dist.sh ### STS ### .apt_generated From 8f3f9db59341dac19ea1cd67e5195ca4b6f3527d Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 11:30:17 +0800 Subject: [PATCH 02/16] feat: add ApiMeasure to collect runtime data ApiMeasure will count the number of vertices and edges traversed at runtime, and the time the api takes to execute --- .../java/org/apache/hugegraph/api/API.java | 58 ++++++++++++++++--- .../apache/hugegraph/core/GraphManager.java | 4 ++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java index afaba499b3..5f8b6e1682 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java @@ -18,28 +18,30 @@ package org.apache.hugegraph.api; import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.function.Consumer; -import jakarta.ws.rs.ForbiddenException; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.NotSupportedException; -import jakarta.ws.rs.core.MediaType; - +import org.apache.hugegraph.HugeException; +import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.define.Checkable; import org.apache.hugegraph.metrics.MetricsUtil; -import org.slf4j.Logger; - -import org.apache.hugegraph.HugeException; -import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.JsonUtil; import org.apache.hugegraph.util.Log; +import org.slf4j.Logger; + import com.codahale.metrics.Meter; import com.google.common.collect.ImmutableMap; +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.NotSupportedException; +import jakarta.ws.rs.core.MediaType; + public class API { protected static final Logger LOG = Log.logger(API.class); @@ -190,4 +192,42 @@ public static boolean checkAndParseAction(String action) { String.format("Not support action '%s'", action)); } } + + public static class ApiMeasure { + public static final String EDGE_ITER = "edge_iters"; + public static final String VERTICE_ITER = "vertice_iters"; + public static final String COST = "cost"; + protected long timeStart = System.currentTimeMillis(); + protected HashMap mapResult = new LinkedHashMap<>(); + + public Map getResult() { + mapResult.put(COST, System.currentTimeMillis() - timeStart); + return mapResult; + } + + public void put(String key, String value) { + this.mapResult.put(key, value); + } + + public void put(String key, long value) { + this.mapResult.put(key, value); + } + + public void put(String key, int value) { + this.mapResult.put(key, value); + } + + protected void addCount(String key, long value) { + long cur = 0; + if (this.mapResult.containsKey(key)) { + cur = (long) this.mapResult.get(key); + } + this.mapResult.put(key, cur + value); + } + + public void addIterCount(long verticeIters, long edgeIters) { + this.addCount(EDGE_ITER, edgeIters); + this.addCount(VERTICE_ITER, verticeIters); + } + } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java b/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java index b203c10470..2c73b5ee93 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java @@ -224,6 +224,10 @@ public Serializer serializer(Graph g) { return JsonSerializer.instance(); } + public Serializer serializer(Graph g, Map apiMeasure) { + return JsonSerializer.instance(apiMeasure); + } + public void rollbackAll() { for (Graph graph : this.graphs.values()) { if (graph.features().graph().supportsTransactions() && From eef9da4d312e2861df3f43a775ad9e01e5252959 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 11:41:42 +0800 Subject: [PATCH 03/16] feat: Add ApiMeasure to JsonSerializer and Modify the Serializer interface * JsonSerializer: return measure information in api response * Serializer: fit the feature that returns complete information about vertices and edges --- .../hugegraph/serializer/JsonSerializer.java | 153 +++++++++++++----- .../hugegraph/serializer/Serializer.java | 24 +-- 2 files changed, 123 insertions(+), 54 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/JsonSerializer.java b/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/JsonSerializer.java index 8103602234..035499c598 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/JsonSerializer.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/JsonSerializer.java @@ -24,11 +24,6 @@ import java.util.List; import java.util.Map; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator; - import org.apache.hugegraph.HugeException; import org.apache.hugegraph.api.API; import org.apache.hugegraph.auth.SchemaDefine.AuthElement; @@ -47,25 +42,44 @@ import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser.WeightedPaths; import org.apache.hugegraph.traversal.optimize.TraversalUtil; import org.apache.hugegraph.util.JsonUtil; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; public class JsonSerializer implements Serializer { private static final int LBUF_SIZE = 1024; - - private static JsonSerializer INSTANCE = new JsonSerializer(); + private static final String MEASURE_KEY = "measure"; + private static final JsonSerializer INSTANCE = new JsonSerializer(); + private Map apiMeasure = null; private JsonSerializer() { } + private JsonSerializer(Map apiMeasure) { + this.apiMeasure = apiMeasure; + } + public static JsonSerializer instance() { return INSTANCE; } + public static JsonSerializer instance(Map apiMeasure) { + return new JsonSerializer(apiMeasure); + } + @Override public String writeMap(Map map) { - return JsonUtil.toJson(map); + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.putAll(map); + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); + } + return JsonUtil.toJson(builder.build()); } @Override @@ -73,6 +87,10 @@ public String writeList(String label, Collection list) { try (ByteArrayOutputStream out = new ByteArrayOutputStream(LBUF_SIZE)) { out.write(String.format("{\"%s\": ", label).getBytes(API.CHARSET)); out.write(JsonUtil.toJson(list).getBytes(API.CHARSET)); + if (this.apiMeasure != null) { + out.write(String.format(",\"%s\": ", MEASURE_KEY).getBytes(API.CHARSET)); + out.write(JsonUtil.toJson(this.apiMeasure).getBytes(API.CHARSET)); + } out.write("}".getBytes(API.CHARSET)); return out.toString(API.CHARSET); } catch (Exception e) { @@ -122,6 +140,11 @@ private String writeIterator(String label, Iterator iter, out.write(page.getBytes(API.CHARSET)); } + if (this.apiMeasure != null) { + out.write(String.format(",\"%s\":[", MEASURE_KEY).getBytes(API.CHARSET)); + out.write(JsonUtil.toJson(this.apiMeasure).getBytes(API.CHARSET)); + } + out.write("}".getBytes(API.CHARSET)); return out.toString(API.CHARSET); } catch (HugeException e) { @@ -144,7 +167,7 @@ public String writePropertyKey(PropertyKey propertyKey) { @Override public String writeTaskWithSchema( - SchemaElement.TaskWithSchema taskWithSchema) { + SchemaElement.TaskWithSchema taskWithSchema) { StringBuilder builder = new StringBuilder(); long id = taskWithSchema.task() == null ? 0L : taskWithSchema.task().asLong(); @@ -162,10 +185,14 @@ public String writeTaskWithSchema( "TaskWithSchema, only support " + "[PropertyKey, IndexLabel]", schemaElement); } - return builder.append("{\"").append(type).append("\": ") - .append(schema) - .append(", \"task_id\": ").append(id).append("}") - .toString(); + builder.append("{\"").append(type).append("\": ") + .append(schema).append(", \"task_id\": ") + .append(id); + if (this.apiMeasure != null) { + builder.append(String.format(",\"%s\":[", MEASURE_KEY)); + builder.append(JsonUtil.toJson(this.apiMeasure)); + } + return builder.append("}").toString(); } @Override @@ -245,27 +272,36 @@ public String writeAuthElements(String label, @Override public String writePaths(String name, Collection paths, - boolean withCrossPoint, - Iterator vertices) { + boolean withCrossPoint, Iterator vertices, + Iterator edges) { List> pathList = new ArrayList<>(paths.size()); for (HugeTraverser.Path path : paths) { pathList.add(path.toMap(withCrossPoint)); } - Map results; - if (vertices == null) { - results = ImmutableMap.of(name, pathList); - } else { - results = ImmutableMap.of(name, pathList, "vertices", vertices); + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(name, pathList); + + if (vertices != null) { + builder.put("vertices", vertices); + } + + if (edges != null) { + builder.put("edges", edges); + } + + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); } - return JsonUtil.toJson(results); + + return JsonUtil.toJson(builder.build()); } @Override public String writeCrosspoints(CrosspointsPaths paths, - Iterator iterator, + Iterator vertices, + Iterator edges, boolean withPath) { - Map results; List> pathList; if (withPath) { pathList = new ArrayList<>(); @@ -275,50 +311,81 @@ public String writeCrosspoints(CrosspointsPaths paths, } else { pathList = ImmutableList.of(); } - results = ImmutableMap.of("crosspoints", paths.crosspoints(), - "paths", pathList, - "vertices", iterator); - return JsonUtil.toJson(results); + ImmutableMap.Builder builder = ImmutableMap.builder() + .put("crosspoints", + paths.crosspoints()) + .put("paths", pathList) + .put("vertices", vertices) + .put("edges", edges); + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); + } + return JsonUtil.toJson(builder.build()); } @Override public String writeSimilars(SimilarsMap similars, - Iterator vertices) { - return JsonUtil.toJson(ImmutableMap.of("similars", similars.toMap(), - "vertices", vertices)); + Iterator vertices) { + ImmutableMap.Builder builder = ImmutableMap.builder() + .put("similars", + similars.toMap()) + .put("vertices", vertices); + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); + } + return JsonUtil.toJson(builder.build()); } @Override - public String writeWeightedPath(NodeWithWeight path, - Iterator vertices) { + public String writeWeightedPath(NodeWithWeight path, Iterator vertices, + Iterator edges) { Map pathMap = path == null ? ImmutableMap.of() : path.toMap(); - return JsonUtil.toJson(ImmutableMap.of("path", pathMap, - "vertices", vertices)); + ImmutableMap.Builder builder = ImmutableMap.builder() + .put("path", pathMap) + .put("vertices", vertices) + .put("edges", edges); + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); + } + return JsonUtil.toJson(builder.build()); } @Override - public String writeWeightedPaths(WeightedPaths paths, - Iterator vertices) { + public String writeWeightedPaths(WeightedPaths paths, Iterator vertices, + Iterator edges) { Map> pathMap = paths == null ? ImmutableMap.of() : paths.toMap(); - return JsonUtil.toJson(ImmutableMap.of("paths", pathMap, - "vertices", vertices)); + ImmutableMap.Builder builder = ImmutableMap.builder() + .put("paths", pathMap) + .put("vertices", vertices) + .put("edges", edges); + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); + } + return JsonUtil.toJson(builder.build()); } @Override public String writeNodesWithPath(String name, List nodes, long size, Collection paths, - Iterator vertices) { + Iterator vertices, Iterator edges) { List> pathList = new ArrayList<>(); for (HugeTraverser.Path path : paths) { pathList.add(path.toMap(false)); } - Map results; - results = ImmutableMap.of(name, nodes, "size", size, - "paths", pathList, "vertices", vertices); - return JsonUtil.toJson(results); + ImmutableMap.Builder builder = ImmutableMap.builder() + .put(name, nodes) + .put("size", size) + .put("paths", pathList) + .put("vertices", vertices) + .put("edges", edges); + if (this.apiMeasure != null) { + builder.put(MEASURE_KEY, this.apiMeasure); + } + + return JsonUtil.toJson(builder.build()); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/Serializer.java b/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/Serializer.java index f3b0cdcace..96fa634202 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/Serializer.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/serializer/Serializer.java @@ -22,9 +22,6 @@ import java.util.List; import java.util.Map; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; - import org.apache.hugegraph.auth.SchemaDefine.AuthElement; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.schema.EdgeLabel; @@ -37,6 +34,8 @@ import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser.NodeWithWeight; import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser.WeightedPaths; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; public interface Serializer { @@ -77,23 +76,26 @@ public interface Serializer { String writeAuthElements(String label, List users); String writePaths(String name, Collection paths, - boolean withCrossPoint, Iterator vertices); + boolean withCrossPoint, Iterator vertices, + Iterator edges); default String writePaths(String name, Collection paths, boolean withCrossPoint) { - return this.writePaths(name, paths, withCrossPoint, null); + return this.writePaths(name, paths, withCrossPoint, null, null); } - String writeCrosspoints(CrosspointsPaths paths, Iterator iterator, - boolean withPath); + String writeCrosspoints(CrosspointsPaths paths, Iterator vertices, + Iterator edges, boolean withPath); - String writeSimilars(SimilarsMap similars, Iterator vertices); + String writeSimilars(SimilarsMap similars, Iterator vertices); - String writeWeightedPath(NodeWithWeight path, Iterator vertices); + String writeWeightedPath(NodeWithWeight path, Iterator vertices, + Iterator edges); - String writeWeightedPaths(WeightedPaths paths, Iterator vertices); + String writeWeightedPaths(WeightedPaths paths, Iterator vertices, + Iterator edges); String writeNodesWithPath(String name, List nodes, long size, Collection paths, - Iterator vertices); + Iterator vertices, Iterator edges); } From 023acf6fece38f525278992c6e412199e1adadae Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 11:45:12 +0800 Subject: [PATCH 04/16] refactor: format code based on hugegraph-style.xml --- .../hugegraph/api/traversers/EdgesAPI.java | 28 +++++----- .../hugegraph/api/traversers/VerticesAPI.java | 28 +++++----- .../hugegraph/config/ServerOptions.java | 54 +++++-------------- .../comm/TriangleCountAlgorithm.java | 38 ++++++------- .../records/ShortestPathRecords.java | 4 +- 5 files changed, 63 insertions(+), 89 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/EdgesAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/EdgesAPI.java index ca4909a552..da9dfe1779 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/EdgesAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/EdgesAPI.java @@ -22,32 +22,32 @@ import java.util.Iterator; import java.util.List; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.filter.CompressInterceptor.Compress; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.backend.query.ConditionQuery; import org.apache.hugegraph.backend.store.Shard; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.type.HugeType; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/edges") @Singleton @Tag(name = "EdgesAPI") diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/VerticesAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/VerticesAPI.java index 56c4889f81..86364a23bf 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/VerticesAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/VerticesAPI.java @@ -22,20 +22,6 @@ import java.util.Iterator; import java.util.List; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.filter.CompressInterceptor.Compress; @@ -43,11 +29,25 @@ import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.backend.query.ConditionQuery; import org.apache.hugegraph.backend.store.Shard; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.type.HugeType; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/vertices") @Singleton @Tag(name = "VerticesAPI") diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java b/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java index 95a53faa39..0ad77d6d9d 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java @@ -25,20 +25,6 @@ public class ServerOptions extends OptionHolder { - private ServerOptions() { - super(); - } - - private static volatile ServerOptions instance; - - public static synchronized ServerOptions instance() { - if (instance == null) { - instance = new ServerOptions(); - instance.registerOptions(); - } - return instance; - } - public static final ConfigOption REST_SERVER_URL = new ConfigOption<>( "restserver.url", @@ -46,7 +32,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "http://127.0.0.1:8080" ); - public static final ConfigOption SERVER_ID = new ConfigOption<>( "server.id", @@ -54,7 +39,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "server-1" ); - public static final ConfigOption SERVER_ROLE = new ConfigOption<>( "server.role", @@ -63,7 +47,6 @@ public static synchronized ServerOptions instance() { allowValues("master", "worker", "computer"), "master" ); - public static final ConfigOption MAX_WORKER_THREADS = new ConfigOption<>( "restserver.max_worker_threads", @@ -71,7 +54,6 @@ public static synchronized ServerOptions instance() { rangeInt(2, Integer.MAX_VALUE), 2 * CoreOptions.CPUS ); - public static final ConfigOption MIN_FREE_MEMORY = new ConfigOption<>( "restserver.min_free_memory", @@ -81,7 +63,6 @@ public static synchronized ServerOptions instance() { nonNegativeInt(), 64 ); - public static final ConfigOption REQUEST_TIMEOUT = new ConfigOption<>( "restserver.request_timeout", @@ -90,7 +71,6 @@ public static synchronized ServerOptions instance() { rangeInt(-1, Integer.MAX_VALUE), 30 ); - public static final ConfigOption CONN_IDLE_TIMEOUT = new ConfigOption<>( "restserver.connection_idle_timeout", @@ -99,7 +79,6 @@ public static synchronized ServerOptions instance() { rangeInt(-1, Integer.MAX_VALUE), 30 ); - public static final ConfigOption CONN_MAX_REQUESTS = new ConfigOption<>( "restserver.connection_max_requests", @@ -108,7 +87,6 @@ public static synchronized ServerOptions instance() { rangeInt(-1, Integer.MAX_VALUE), 256 ); - public static final ConfigOption GREMLIN_SERVER_URL = new ConfigOption<>( "gremlinserver.url", @@ -116,7 +94,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "http://127.0.0.1:8182" ); - public static final ConfigOption GREMLIN_SERVER_TIMEOUT = new ConfigOption<>( "gremlinserver.timeout", @@ -124,7 +101,6 @@ public static synchronized ServerOptions instance() { positiveInt(), 30 ); - public static final ConfigOption GREMLIN_SERVER_MAX_ROUTE = new ConfigOption<>( "gremlinserver.max_route", @@ -132,7 +108,6 @@ public static synchronized ServerOptions instance() { positiveInt(), 2 * CoreOptions.CPUS ); - public static final ConfigOption GRAPHS = new ConfigOption<>( "graphs", @@ -140,7 +115,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "./conf/graphs" ); - public static final ConfigOption MAX_VERTICES_PER_BATCH = new ConfigOption<>( "batch.max_vertices_per_batch", @@ -148,7 +122,6 @@ public static synchronized ServerOptions instance() { positiveInt(), 500 ); - public static final ConfigOption MAX_EDGES_PER_BATCH = new ConfigOption<>( "batch.max_edges_per_batch", @@ -156,7 +129,6 @@ public static synchronized ServerOptions instance() { positiveInt(), 500 ); - public static final ConfigOption MAX_WRITE_RATIO = new ConfigOption<>( "batch.max_write_ratio", @@ -165,7 +137,6 @@ public static synchronized ServerOptions instance() { rangeInt(0, 100), 50 ); - public static final ConfigOption MAX_WRITE_THREADS = new ConfigOption<>( "batch.max_write_threads", @@ -174,7 +145,6 @@ public static synchronized ServerOptions instance() { "batch.max_write_ratio * restserver.max_worker_threads.", nonNegativeInt(), 0); - public static final ConfigOption RAFT_GROUP_PEERS = new ConfigOption<>( "raft.group_peers", @@ -182,15 +152,13 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "127.0.0.1:8090" ); - public static final ConfigOption ALLOW_TRACE = new ConfigOption<>( "exception.allow_trace", "Whether to allow exception trace stack.", disallowEmpty(), - false + true ); - public static final ConfigOption AUTHENTICATOR = new ConfigOption<>( "auth.authenticator", @@ -200,7 +168,6 @@ public static synchronized ServerOptions instance() { null, "" ); - public static final ConfigOption AUTH_GRAPH_STORE = new ConfigOption<>( "auth.graph_store", @@ -209,7 +176,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "hugegraph" ); - public static final ConfigOption AUTH_ADMIN_TOKEN = new ConfigOption<>( "auth.admin_token", @@ -218,7 +184,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "162f7848-0b6d-4faf-b557-3a0797869c55" ); - public static final ConfigListOption AUTH_USER_TOKENS = new ConfigListOption<>( "auth.user_tokens", @@ -227,7 +192,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "hugegraph:9fd95c9c-711b-415b-b85f-d4df46ba5c31" ); - public static final ConfigOption AUTH_REMOTE_URL = new ConfigOption<>( "auth.remote_url", @@ -238,7 +202,6 @@ public static synchronized ServerOptions instance() { null, "" ); - public static final ConfigOption SSL_KEYSTORE_FILE = new ConfigOption<>( "ssl.keystore_file", @@ -247,7 +210,6 @@ public static synchronized ServerOptions instance() { disallowEmpty(), "conf/hugegraph-server.keystore" ); - public static final ConfigOption SSL_KEYSTORE_PASSWORD = new ConfigOption<>( "ssl.keystore_password", @@ -256,7 +218,6 @@ public static synchronized ServerOptions instance() { null, "hugegraph" ); - public static final ConfigOption ENABLE_DYNAMIC_CREATE_DROP = new ConfigOption<>( "graphs.enable_dynamic_create_drop", @@ -264,4 +225,17 @@ public static synchronized ServerOptions instance() { disallowEmpty(), true ); + private static volatile ServerOptions instance; + + private ServerOptions() { + super(); + } + + public static synchronized ServerOptions instance() { + if (instance == null) { + instance = new ServerOptions(); + instance.registerOptions(); + } + return instance; + } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/job/algorithm/comm/TriangleCountAlgorithm.java b/hugegraph-core/src/main/java/org/apache/hugegraph/job/algorithm/comm/TriangleCountAlgorithm.java index 2f512f7169..0fba245966 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/job/algorithm/comm/TriangleCountAlgorithm.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/job/algorithm/comm/TriangleCountAlgorithm.java @@ -26,19 +26,29 @@ import org.apache.commons.lang.mutable.MutableLong; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.backend.id.IdGenerator; -import org.apache.tinkerpop.gremlin.structure.Edge; - import org.apache.hugegraph.job.UserJob; import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.InsertionOrderUtil; +import org.apache.tinkerpop.gremlin.structure.Edge; + import com.google.common.collect.ImmutableMap; public class TriangleCountAlgorithm extends AbstractCommAlgorithm { public static final String ALGO_NAME = "triangle_count"; + protected static int workersWhenBoth(Map parameters) { + Directions direction = direction4Out(parameters); + int workers = workers(parameters); + E.checkArgument(direction == Directions.BOTH || workers <= 0, + "The workers must be not set when direction!=BOTH, " + + "but got workers=%s and direction=%s", + workers, direction); + return workers; + } + @Override public String name() { return ALGO_NAME; @@ -60,16 +70,6 @@ public Object call(UserJob job, Map parameters) { } } - protected static int workersWhenBoth(Map parameters) { - Directions direction = direction4Out(parameters); - int workers = workers(parameters); - E.checkArgument(direction == Directions.BOTH || workers <= 0, - "The workers must be not set when direction!=BOTH, " + - "but got workers=%s and direction=%s", - workers, direction); - return workers; - } - protected static class Traverser extends AlgoTraverser { protected static final String KEY_TRIANGLES = "triangles"; @@ -83,8 +83,12 @@ protected Traverser(UserJob job, String name, int workers) { super(job, name, workers); } + protected static Set newOrderedSet() { + return new TreeSet<>(); + } + public Object triangleCount(Directions direction, long degree) { - Map results = triangles( direction, degree); + Map results = triangles(direction, degree); results = InsertionOrderUtil.newMap(results); results.remove(KEY_TRIADS); return results; @@ -191,7 +195,7 @@ private Set adjacentVertices(Id source, long degree, MutableLong edgesCount) { Iterator adjVertices = this.adjacentVertices(source, Directions.BOTH, - null, degree); + (Id) null, degree); Set set = newOrderedSet(); while (adjVertices.hasNext()) { edgesCount.increment(); @@ -206,7 +210,7 @@ protected long intersect(long degree, Set adjVertices) { Id empty = IdGenerator.ZERO; Iterator vertices; for (Id v : adjVertices) { - vertices = this.adjacentVertices(v, dir, null, degree); + vertices = this.adjacentVertices(v, dir, (Id) null, degree); Id lastVertex = empty; while (vertices.hasNext()) { Id vertex = vertices.next(); @@ -231,9 +235,5 @@ protected long intersect(long degree, Set adjVertices) { protected long localTriads(int size) { return size * (size - 1L) / 2L; } - - protected static Set newOrderedSet() { - return new TreeSet<>(); - } } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/ShortestPathRecords.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/ShortestPathRecords.java index ce3647de2e..fe05d00824 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/ShortestPathRecords.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/ShortestPathRecords.java @@ -23,14 +23,14 @@ import java.util.function.Function; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser.Path; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser.PathSet; import org.apache.hugegraph.traversal.algorithm.records.record.Int2IntRecord; import org.apache.hugegraph.traversal.algorithm.records.record.Record; import org.apache.hugegraph.traversal.algorithm.records.record.RecordType; import org.apache.hugegraph.util.collection.CollectionFactory; import org.apache.hugegraph.util.collection.IntMap; import org.apache.hugegraph.util.collection.IntSet; -import org.apache.hugegraph.traversal.algorithm.HugeTraverser.Path; -import org.apache.hugegraph.traversal.algorithm.HugeTraverser.PathSet; public class ShortestPathRecords extends DoubleWayMultiPathsRecords { From fc94aa3d826d84f3dec863c6630a7fe506888266 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 12:03:50 +0800 Subject: [PATCH 05/16] feat: Add statistics information in all oltp restful apis response and Support full information about vertices and edges Statistics information: * add vertexIterCounter and edgeIterCounter in HugeTraverser.java to track traversed vertices and edges at run time * modify all oltp restful apis to add statistics information in response Full information about vertices and edges: * add 'with_vertex' and 'with_edge' parameter option in apis * modify oltp apis to support vertex and edge information in api response * add EdgeRecord in HugeTraverser.java to record edges at run time and generate the edge information returned in api response * modify Path and PathSet in HugeTraverser.java to support full edge information storage * modify all traversers to support track of edge information at run time --- .../api/traversers/AllShortestPathsAPI.java | 71 ++- .../api/traversers/CrosspointsAPI.java | 30 +- .../traversers/CustomizedCrosspointsAPI.java | 126 ++-- .../api/traversers/CustomizedPathsAPI.java | 103 ++-- .../api/traversers/FusiformSimilarityAPI.java | 65 ++- .../api/traversers/JaccardSimilarityAPI.java | 55 +- .../api/traversers/KneighborAPI.java | 78 ++- .../hugegraph/api/traversers/KoutAPI.java | 90 ++- .../traversers/MultiNodeShortestPathAPI.java | 82 +-- .../hugegraph/api/traversers/PathsAPI.java | 102 ++-- .../hugegraph/api/traversers/RaysAPI.java | 67 ++- .../hugegraph/api/traversers/RingsAPI.java | 74 ++- .../api/traversers/SameNeighborsAPI.java | 113 +++- .../api/traversers/ShortestPathAPI.java | 67 ++- .../SingleSourceShortestPathAPI.java | 79 ++- .../api/traversers/TemplatePathsAPI.java | 104 ++-- .../traversers/WeightedShortestPathAPI.java | 84 ++- .../algorithm/CollectionPathsTraverser.java | 62 +- .../algorithm/CustomizePathsTraverser.java | 81 +-- .../CustomizedCrosspointsTraverser.java | 133 +++-- .../FusiformSimilarityTraverser.java | 67 ++- .../traversal/algorithm/HugeTraverser.java | 541 +++++++++++------- .../algorithm/JaccardSimilarTraverser.java | 49 +- .../algorithm/KneighborTraverser.java | 16 +- .../traversal/algorithm/KoutTraverser.java | 24 +- .../MultiNodeShortestPathTraverser.java | 116 ++-- .../traversal/algorithm/PathTraverser.java | 24 +- .../traversal/algorithm/PathsTraverser.java | 23 +- .../algorithm/SameNeighborTraverser.java | 57 +- .../algorithm/ShortestPathTraverser.java | 45 +- .../SingleSourceShortestPathTraverser.java | 206 ++++--- .../algorithm/SubGraphTraverser.java | 175 +++--- .../algorithm/TemplatePathsTraverser.java | 62 +- .../records/SingleWayMultiPathsRecords.java | 18 +- 34 files changed, 2014 insertions(+), 1075 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java index 030c4e8cc1..a6b003ddab 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java @@ -20,19 +20,10 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; - -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.slf4j.Logger; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; @@ -44,9 +35,22 @@ import org.apache.hugegraph.traversal.algorithm.ShortestPathTraverser; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.google.common.collect.ImmutableList; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/allshortestpaths") @Singleton @Tag(name = "AllShortestPathsAPI") @@ -68,13 +72,20 @@ public String get(@Context GraphManager manager, @DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree, @QueryParam("skip_degree") @DefaultValue("0") long skipDegree, + @QueryParam("with_vertex") + @DefaultValue("false") boolean withVertex, + @QueryParam("with_edge") + @DefaultValue("false") boolean withEdge, @QueryParam("capacity") @DefaultValue(DEFAULT_CAPACITY) long capacity) { LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " + "direction {}, edge label {}, max depth '{}', " + - "max degree '{}', skipped degree '{}' and capacity '{}'", + "max degree '{}', skipped degree '{}', capacity '{}', " + + "with vertex '{}' and with edge '{}'", graph, source, target, direction, edgeLabel, depth, - maxDegree, skipDegree, capacity); + maxDegree, skipDegree, capacity, withVertex, withEdge); + + ApiMeasure measure = new ApiMeasure(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); @@ -86,8 +97,34 @@ public String get(@Context GraphManager manager, List edgeLabels = edgeLabel == null ? ImmutableList.of() : ImmutableList.of(edgeLabel); HugeTraverser.PathSet paths = traverser.allShortestPaths( - sourceId, targetId, dir, edgeLabels, - depth, maxDegree, skipDegree, capacity); - return manager.serializer(g).writePaths("paths", paths, false); + sourceId, targetId, dir, edgeLabels, + depth, maxDegree, skipDegree, capacity); + + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); + } + if (withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge; + Set edges = paths.getEdges(); + if (withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); + } + + return manager.serializer(g, measure.getResult()) + .writePaths("paths", paths, false, + iterVertex, iterEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java index 39de473b8f..e501dc3246 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java @@ -21,18 +21,6 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.graph.EdgeAPI; @@ -43,8 +31,20 @@ import org.apache.hugegraph.traversal.algorithm.PathsTraverser; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.Log; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/crosspoints") @Singleton @Tag(name = "CrosspointsAPI") @@ -74,6 +74,7 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, depth, maxDegree, capacity, limit); + ApiMeasure measure = new ApiMeasure(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -84,6 +85,9 @@ public String get(@Context GraphManager manager, dir, edgeLabel, depth, maxDegree, capacity, limit); - return manager.serializer(g).writePaths("crosspoints", paths, true); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + return manager.serializer(g, measure.getResult()) + .writePaths("crosspoints", paths, true); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java index da35f7325f..36783d3907 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java @@ -22,38 +22,39 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.CustomizedCrosspointsTraverser; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/customizedcrosspoints") @Singleton @Tag(name = "CustomizedCrosspointsAPI") @@ -61,6 +62,22 @@ public class CustomizedCrosspointsAPI extends API { private static final Logger LOG = Log.logger(CustomizedCrosspointsAPI.class); + private static List pathPatterns( + HugeGraph graph, CrosspointsRequest request) { + int stepSize = request.pathPatterns.size(); + List pathPatterns; + pathPatterns = new ArrayList<>(stepSize); + for (PathPattern pattern : request.pathPatterns) { + CustomizedCrosspointsTraverser.PathPattern pathPattern; + pathPattern = new CustomizedCrosspointsTraverser.PathPattern(); + for (Step step : pattern.steps) { + pathPattern.add(step.jsonToStep(graph)); + } + pathPatterns.add(pathPattern); + } + return pathPatterns; + } + @POST @Timed @Consumes(APPLICATION_JSON) @@ -78,55 +95,56 @@ public String post(@Context GraphManager manager, "The steps of crosspoints request can't be empty"); LOG.debug("Graph [{}] get customized crosspoints from source vertex " + - "'{}', with path_pattern '{}', with_path '{}', with_vertex " + - "'{}', capacity '{}' and limit '{}'", graph, request.sources, - request.pathPatterns, request.withPath, request.withVertex, - request.capacity, request.limit); + "'{}', with path_pattern '{}', with path '{}', with vertex " + + "'{}', capacity '{}', limit '{}' and with edge '{}'", + graph, request.sources, request.pathPatterns, request.withPath, + request.withVertex, request.capacity, request.limit, request.withEdge); + + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); - List patterns; - patterns = pathPatterns(g, request); CustomizedCrosspointsTraverser traverser = - new CustomizedCrosspointsTraverser(g); - CustomizedCrosspointsTraverser.CrosspointsPaths paths; - paths = traverser.crosspointsPaths(sources, patterns, request.capacity, - request.limit); - Iterator iter = QueryResults.emptyIterator(); - if (!request.withVertex) { - return manager.serializer(g).writeCrosspoints(paths, iter, - request.withPath); - } - Set ids = new HashSet<>(); + new CustomizedCrosspointsTraverser(g); + + List patterns = pathPatterns(g, request); + CustomizedCrosspointsTraverser.CrosspointsPaths paths = + traverser.crosspointsPaths(sources, patterns, request.capacity, request.limit); + + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + + Iterator iterVertex; + Set vertexIds = new HashSet<>(); if (request.withPath) { - for (HugeTraverser.Path p : paths.paths()) { - ids.addAll(p.vertices()); + for (HugeTraverser.Path path : paths.paths()) { + vertexIds.addAll(path.vertices()); } } else { - ids = paths.crosspoints(); + vertexIds = paths.crosspoints(); } - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); } - return manager.serializer(g).writeCrosspoints(paths, iter, - request.withPath); - } - private static List - pathPatterns(HugeGraph graph, CrosspointsRequest request) { - int stepSize = request.pathPatterns.size(); - List pathPatterns; - pathPatterns = new ArrayList<>(stepSize); - for (PathPattern pattern : request.pathPatterns) { - CustomizedCrosspointsTraverser.PathPattern pathPattern; - pathPattern = new CustomizedCrosspointsTraverser.PathPattern(); - for (Step step : pattern.steps) { - pathPattern.add(step.jsonToStep(graph)); + Iterator iterEdge = Collections.emptyIterator(); + if (request.withPath) { + Set edges = traverser.getEdgeRecord().getEdges(paths.paths()); + if (request.withEdge) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - pathPatterns.add(pathPattern); } - return pathPatterns; + + return manager.serializer(g, measure.getResult()) + .writeCrosspoints(paths, iterVertex, + iterEdge, request.withPath); } private static class CrosspointsRequest { @@ -143,14 +161,16 @@ private static class CrosspointsRequest { public boolean withPath = false; @JsonProperty("with_vertex") public boolean withVertex = false; + @JsonProperty("with_edge") + public boolean withEdge = false; @Override public String toString() { return String.format("CrosspointsRequest{sourceVertex=%s," + "pathPatterns=%s,withPath=%s,withVertex=%s," + - "capacity=%s,limit=%s}", this.sources, - this.pathPatterns, this.withPath, - this.withVertex, this.capacity, this.limit); + "capacity=%s,limit=%s,withEdge=%s}", this.sources, + this.pathPatterns, this.withPath, this.withVertex, + this.capacity, this.limit, this.withEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java index 272009ea24..65ef1a960c 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java @@ -30,33 +30,33 @@ import java.util.Map; import java.util.Set; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.CustomizePathsTraverser; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.steps.WeightedEdgeStep; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/customizedpaths") @Singleton @Tag(name = "CustomizedPathsAPI") @@ -64,6 +64,16 @@ public class CustomizedPathsAPI extends API { private static final Logger LOG = Log.logger(CustomizedPathsAPI.class); + private static List step(HugeGraph graph, + PathRequest req) { + int stepSize = req.steps.size(); + List steps = new ArrayList<>(stepSize); + for (Step step : req.steps) { + steps.add(step.jsonToStep(graph)); + } + return steps; + } + @POST @Timed @Consumes(APPLICATION_JSON) @@ -81,10 +91,12 @@ public String post(@Context GraphManager manager, } LOG.debug("Graph [{}] get customized paths from source vertex '{}', " + - "with steps '{}', sort by '{}', capacity '{}', limit '{}' " + - "and with_vertex '{}'", graph, request.sources, request.steps, + "with steps '{}', sort by '{}', capacity '{}', limit '{}', " + + "with vertex '{}' and with edge '{}'", graph, request.sources, request.steps, request.sortBy, request.capacity, request.limit, - request.withVertex); + request.withVertex, request.withEdge); + + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -95,6 +107,8 @@ public String post(@Context GraphManager manager, List paths; paths = traverser.customizedPaths(sources, steps, sorted, request.capacity, request.limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); if (sorted) { boolean incr = request.sortBy == SortBy.INCR; @@ -102,29 +116,35 @@ public String post(@Context GraphManager manager, request.limit); } - if (!request.withVertex) { - return manager.serializer(g).writePaths("paths", paths, false); + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); } - - Set ids = new HashSet<>(); - for (HugeTraverser.Path p : paths) { - ids.addAll(p.vertices()); + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); } - Iterator iter = QueryResults.emptyIterator(); - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + + Iterator iterEdge; + Set edges = traverser.getEdgeRecord().getEdges(paths); + if (request.withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g).writePaths("paths", paths, false, iter); + + return manager.serializer(g, measure.getResult()) + .writePaths("paths", paths, false, + iterVertex, iterEdge); } - private static List step(HugeGraph graph, - PathRequest req) { - int stepSize = req.steps.size(); - List steps = new ArrayList<>(stepSize); - for (Step step : req.steps) { - steps.add(step.jsonToStep(graph)); - } - return steps; + private enum SortBy { + INCR, + DECR, + NONE } private static class PathRequest { @@ -142,13 +162,16 @@ private static class PathRequest { @JsonProperty("with_vertex") public boolean withVertex = false; + @JsonProperty("with_edge") + public boolean withEdge = false; + @Override public String toString() { return String.format("PathRequest{sourceVertex=%s,steps=%s," + "sortBy=%s,capacity=%s,limit=%s," + - "withVertex=%s}", this.sources, this.steps, + "withVertex=%s,withEdge=%s}", this.sources, this.steps, this.sortBy, this.capacity, this.limit, - this.withVertex); + this.withVertex, this.withEdge); } } @@ -190,10 +213,4 @@ private WeightedEdgeStep jsonToStep(HugeGraph g) { this.defaultWeight, this.sample); } } - - private enum SortBy { - INCR, - DECR, - NONE - } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java index fbb330ae12..37c7276e8c 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java @@ -23,32 +23,33 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.NO_LIMIT; import java.util.Iterator; - -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; -import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.FusiformSimilarityTraverser; import org.apache.hugegraph.traversal.algorithm.FusiformSimilarityTraverser.SimilarsMap; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/fusiformsimilarity") @Singleton @Tag(name = "FusiformSimilarityAPI") @@ -64,7 +65,7 @@ public String post(@Context GraphManager manager, @PathParam("graph") String graph, FusiformSimilarityRequest request) { E.checkArgumentNotNull(request, "The fusiform similarity " + - "request body can't be null"); + "request body can't be null"); E.checkArgumentNotNull(request.sources, "The sources of fusiform similarity " + "request can't be null"); @@ -94,28 +95,38 @@ public String post(@Context GraphManager manager, request.minNeighbors, request.alpha, request.minSimilars, request.groupProperty, request.minGroups); + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); E.checkArgument(sources != null && sources.hasNext(), "The source vertices can't be empty"); FusiformSimilarityTraverser traverser = - new FusiformSimilarityTraverser(g); + new FusiformSimilarityTraverser(g); SimilarsMap result = traverser.fusiformSimilarity( - sources, request.direction, request.label, - request.minNeighbors, request.alpha, - request.minSimilars, request.top, - request.groupProperty, request.minGroups, - request.maxDegree, request.capacity, - request.limit, request.withIntermediary); + sources, request.direction, request.label, + request.minNeighbors, request.alpha, + request.minSimilars, request.top, + request.groupProperty, request.minGroups, + request.maxDegree, request.capacity, + request.limit, request.withIntermediary); CloseableIterator.closeIterator(sources); - Iterator iterator = QueryResults.emptyIterator(); - if (request.withVertex && !result.isEmpty()) { - iterator = g.vertices(result.vertices().toArray()); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set vertexIds = result.vertices(); + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0); + } else { + iterVertex = vertexIds.iterator(); } - return manager.serializer(g).writeSimilars(result, iterator); + + return manager.serializer(g, measure.getResult()) + .writeSimilars(result, iterVertex); } private static class FusiformSimilarityRequest { diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java index ff187a5918..5f13367d39 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java @@ -18,41 +18,40 @@ package org.apache.hugegraph.api.traversers; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY; -import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_LIMIT; +import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import java.util.Map; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.structure.HugeVertex; -import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.traversal.algorithm.JaccardSimilarTraverser; +import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; -import org.apache.hugegraph.util.JsonUtil; import org.apache.hugegraph.util.Log; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableMap; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/jaccardsimilarity") @Singleton @Tag(name = "JaccardSimilarityAPI") @@ -75,6 +74,8 @@ public String get(@Context GraphManager manager, "with direction {}, edge label {} and max degree '{}'", graph, vertex, other, direction, edgeLabel, maxDegree); + ApiMeasure measure = new ApiMeasure(); + Id sourceId = VertexAPI.checkAndParseVertexId(vertex); Id targetId = VertexAPI.checkAndParseVertexId(other); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -82,12 +83,15 @@ public String get(@Context GraphManager manager, HugeGraph g = graph(manager, graph); double similarity; try (JaccardSimilarTraverser traverser = - new JaccardSimilarTraverser(g)) { + new JaccardSimilarTraverser(g)) { similarity = traverser.jaccardSimilarity(sourceId, targetId, dir, edgeLabel, maxDegree); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); } - return JsonUtil.toJson(ImmutableMap.of("jaccard_similarity", - similarity)); + + return manager.serializer(g, measure.getResult()) + .writeMap(ImmutableMap.of("jaccard_similarity", similarity)); } @POST @@ -110,6 +114,8 @@ public String post(@Context GraphManager manager, graph, request.vertex, request.step, request.top, request.capacity); + ApiMeasure measure = new ApiMeasure(); + HugeGraph g = graph(manager, graph); Id sourceId = HugeVertex.getIdValue(request.vertex); @@ -117,11 +123,14 @@ public String post(@Context GraphManager manager, Map results; try (JaccardSimilarTraverser traverser = - new JaccardSimilarTraverser(g)) { + new JaccardSimilarTraverser(g)) { results = traverser.jaccardSimilars(sourceId, step, request.top, request.capacity); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); } - return manager.serializer(g).writeMap(results); + return manager.serializer(g, measure.getResult()) + .writeMap(ImmutableMap.of("jaccard_similarity", results)); } private static class Request { diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java index 4a7c0a9515..ea55ab383e 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java @@ -21,6 +21,7 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.NO_LIMIT; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -40,12 +41,13 @@ import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; -import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.Edge; import org.slf4j.Logger; import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Singleton; @@ -75,6 +77,8 @@ public String get(@Context GraphManager manager, @QueryParam("direction") String direction, @QueryParam("label") String edgeLabel, @QueryParam("max_depth") int depth, + @QueryParam("count_only") + @DefaultValue("false") boolean countOnly, @QueryParam("max_degree") @DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree, @QueryParam("limit") @@ -85,6 +89,8 @@ public String get(@Context GraphManager manager, graph, sourceV, direction, edgeLabel, depth, maxDegree, limit); + ApiMeasure measure = new ApiMeasure(); + Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -94,8 +100,14 @@ public String get(@Context GraphManager manager, try (KneighborTraverser traverser = new KneighborTraverser(g)) { ids = traverser.kneighbor(source, dir, edgeLabel, depth, maxDegree, limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + } + if (countOnly) { + return manager.serializer(g, measure.getResult()).writeMap( + ImmutableMap.of("vertices_size", ids.size())); } - return manager.serializer(g).writeList("vertices", ids); + return manager.serializer(g, measure.getResult()).writeList("vertices", ids); } @POST @@ -111,15 +123,18 @@ public String post(@Context GraphManager manager, E.checkArgument(request.step != null, "The steps of request can't be null"); if (request.countOnly) { - E.checkArgument(!request.withVertex && !request.withPath, - "Can't return vertex or path when count only"); + E.checkArgument(!request.withVertex && !request.withPath && !request.withEdge, + "Can't return vertex or path or edge when count only"); } LOG.debug("Graph [{}] get customized kneighbor from source vertex " + "'{}', with step '{}', limit '{}', count_only '{}', " + - "with_vertex '{}' and with_path '{}'", + "with_vertex '{}', with_path '{}' and with_edge '{}'", graph, request.source, request.step, request.limit, - request.countOnly, request.withVertex, request.withPath); + request.countOnly, request.withVertex, request.withPath, + request.withEdge); + + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Id sourceId = HugeVertex.getIdValue(request.source); @@ -131,6 +146,8 @@ public String post(@Context GraphManager manager, results = traverser.customizedKneighbor(sourceId, step, request.maxDepth, request.limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); } long size = results.size(); @@ -144,20 +161,41 @@ public String post(@Context GraphManager manager, if (request.withPath) { paths.addAll(results.paths(request.limit)); } - Iterator iter = QueryResults.emptyIterator(); - if (request.withVertex && !request.countOnly) { - Set ids = new HashSet<>(neighbors); - if (request.withPath) { - for (HugeTraverser.Path p : paths) { - ids.addAll(p.vertices()); - } + + if (request.countOnly) { + return manager.serializer(g, measure.getResult()) + .writeNodesWithPath("kneighbor", neighbors, size, paths, + QueryResults.emptyIterator(), + QueryResults.emptyIterator()); + } + + Iterator iterVertex; + Set vertexIds = new HashSet<>(neighbors); + if (request.withPath) { + for (HugeTraverser.Path p : paths) { + vertexIds.addAll(p.vertices()); } - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + } + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge = Collections.emptyIterator(); + if (request.withPath) { + Set edges = results.getEdgeIdRecord().getEdges(paths); + if (request.withEdge) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } } - return manager.serializer(g).writeNodesWithPath("kneighbor", neighbors, - size, paths, iter); + + return manager.serializer(g, measure.getResult()) + .writeNodesWithPath("kneighbor", neighbors, + size, paths, iterVertex, iterEdge); } private static class Request { @@ -176,14 +214,16 @@ private static class Request { public boolean withVertex = false; @JsonProperty("with_path") public boolean withPath = false; + @JsonProperty("with_edge") + public boolean withEdge = false; @Override public String toString() { return String.format("PathRequest{source=%s,step=%s,maxDepth=%s" + "limit=%s,countOnly=%s,withVertex=%s," + - "withPath=%s}", this.source, this.step, + "withPath=%s,withEdge=%s}", this.source, this.step, this.maxDepth, this.limit, this.countOnly, - this.withVertex, this.withPath); + this.withVertex, this.withPath, this.withEdge); } } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java index 30282be9d6..8dd947dae0 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java @@ -22,6 +22,7 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.NO_LIMIT; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -41,12 +42,13 @@ import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; -import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.Edge; import org.slf4j.Logger; import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Singleton; @@ -78,6 +80,8 @@ public String get(@Context GraphManager manager, @QueryParam("max_depth") int depth, @QueryParam("nearest") @DefaultValue("true") boolean nearest, + @QueryParam("count_only") + @DefaultValue("false") boolean count_only, @QueryParam("max_degree") @DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree, @QueryParam("capacity") @@ -87,8 +91,10 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get k-out from '{}' with " + "direction '{}', edge label '{}', max depth '{}', nearest " + "'{}', max degree '{}', capacity '{}' and limit '{}'", - graph, source, direction, edgeLabel, depth, nearest, - maxDegree, capacity, limit); + graph, source, direction, edgeLabel, depth, + nearest, maxDegree, capacity, limit); + + ApiMeasure measure = new ApiMeasure(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -99,8 +105,15 @@ public String get(@Context GraphManager manager, try (KoutTraverser traverser = new KoutTraverser(g)) { ids = traverser.kout(sourceId, dir, edgeLabel, depth, nearest, maxDegree, capacity, limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + } + + if (count_only) { + return manager.serializer(g, measure.getResult()).writeMap(ImmutableMap.of( + "vertices_size", ids.size())); } - return manager.serializer(g).writeList("vertices", ids); + return manager.serializer(g, measure.getResult()).writeList("vertices", ids); } @POST @@ -116,23 +129,25 @@ public String post(@Context GraphManager manager, E.checkArgument(request.step != null, "The steps of request can't be null"); if (request.countOnly) { - E.checkArgument(!request.withVertex && !request.withPath, - "Can't return vertex or path when count only"); + E.checkArgument(!request.withVertex && !request.withPath && !request.withEdge, + "Can't return vertex or path or edge when count only"); } LOG.debug("Graph [{}] get customized kout from source vertex '{}', " + "with step '{}', max_depth '{}', nearest '{}', " + "count_only '{}', capacity '{}', limit '{}', " + - "with_vertex '{}' and with_path '{}'", + "with_vertex '{}', with_path '{}' and with_edge '{}'", graph, request.source, request.step, request.maxDepth, request.nearest, request.countOnly, request.capacity, - request.limit, request.withVertex, request.withPath); + request.limit, request.withVertex, request.withPath, + request.withEdge); + + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Id sourceId = HugeVertex.getIdValue(request.source); EdgeStep step = step(g, request.step); - KoutRecords results; try (KoutTraverser traverser = new KoutTraverser(g)) { results = traverser.customizedKout(sourceId, step, @@ -140,8 +155,9 @@ public String post(@Context GraphManager manager, request.nearest, request.capacity, request.limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); } - long size = results.size(); if (request.limit != NO_LIMIT && size > request.limit) { size = request.limit; @@ -154,20 +170,40 @@ public String post(@Context GraphManager manager, paths.addAll(results.paths(request.limit)); } - Iterator iter = QueryResults.emptyIterator(); - if (request.withVertex && !request.countOnly) { - Set ids = new HashSet<>(neighbors); - if (request.withPath) { - for (HugeTraverser.Path p : paths) { - ids.addAll(p.vertices()); - } + if (request.countOnly) { + return manager.serializer(g, measure.getResult()) + .writeNodesWithPath("kneighbor", neighbors, size, paths, + QueryResults.emptyIterator(), + QueryResults.emptyIterator()); + } + + Iterator iterVertex; + Set vertexIds = new HashSet<>(neighbors); + if (request.withPath) { + for (HugeTraverser.Path p : results.paths(request.limit)) { + vertexIds.addAll(p.vertices()); } - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + } + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge = Collections.emptyIterator(); + if (request.withPath) { + Set edges = results.getEdgeIdRecord().getEdges(paths); + if (request.withEdge) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } } - return manager.serializer(g).writeNodesWithPath("kout", neighbors, - size, paths, iter); + + return manager.serializer(g, measure.getResult()) + .writeNodesWithPath("kout", neighbors, size, paths, + iterVertex, iterEdge); } private static class Request { @@ -191,14 +227,18 @@ private static class Request { @JsonProperty("with_path") public boolean withPath = false; + @JsonProperty("with_edge") + public boolean withEdge = false; + @Override public String toString() { return String.format("KoutRequest{source=%s,step=%s,maxDepth=%s" + "nearest=%s,countOnly=%s,capacity=%s," + - "limit=%s,withVertex=%s,withPath=%s}", - this.source, this.step, this.maxDepth, - this.nearest, this.countOnly, this.capacity, - this.limit, this.withVertex, this.withPath); + "limit=%s,withVertex=%s,withPath=%s," + + "withEdge=%s}", this.source, this.step, + this.maxDepth, this.nearest, this.countOnly, + this.capacity, this.limit, this.withVertex, + this.withPath, this.withEdge); } } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java index 81c38e65c9..ad569e01b0 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java @@ -24,30 +24,30 @@ import java.util.List; import java.util.Set; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.backend.query.QueryResults; -import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.MultiNodeShortestPathTraverser; +import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/multinodeshortestpath") @Singleton @Tag(name = "MultiNodeShortestPathAPI") @@ -74,32 +74,48 @@ public String post(@Context GraphManager manager, graph, request.vertices, request.step, request.maxDepth, request.capacity, request.withVertex); + ApiMeasure measure = new ApiMeasure(); + HugeGraph g = graph(manager, graph); Iterator vertices = request.vertices.vertices(g); EdgeStep step = step(g, request.step); - List paths; + MultiNodeShortestPathTraverser.WrappedListPath wrappedListPath; try (MultiNodeShortestPathTraverser traverser = - new MultiNodeShortestPathTraverser(g)) { - paths = traverser.multiNodeShortestPath(vertices, step, - request.maxDepth, - request.capacity); + new MultiNodeShortestPathTraverser(g)) { + wrappedListPath = traverser.multiNodeShortestPath(vertices, step, + request.maxDepth, + request.capacity); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); } - if (!request.withVertex) { - return manager.serializer(g).writePaths("paths", paths, false); - } + List paths = wrappedListPath.getPaths(); - Set ids = new HashSet<>(); - for (HugeTraverser.Path p : paths) { - ids.addAll(p.vertices()); + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); + } + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); } - Iterator iter = QueryResults.emptyIterator(); - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + + Iterator iterEdge; + Set edges = wrappedListPath.getEdges(); + if (request.withEdge && !edges.isEmpty()) { + iterEdge = wrappedListPath.getEdges().iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g).writePaths("paths", paths, false, iter); + + return manager.serializer(g, measure.getResult()) + .writePaths("paths", paths, + false, iterVertex, iterEdge); } private static class Request { @@ -114,13 +130,15 @@ private static class Request { public long capacity = Long.parseLong(DEFAULT_CAPACITY); @JsonProperty("with_vertex") public boolean withVertex = false; + @JsonProperty("with_edge") + public boolean withEdge = false; @Override public String toString() { return String.format("Request{vertices=%s,step=%s,maxDepth=%s" + - "capacity=%s,withVertex=%s}", + "capacity=%s,withVertex=%s,withEdge=%s}", this.vertices, this.step, this.maxDepth, - this.capacity, this.withVertex); + this.capacity, this.withVertex, this.withEdge); } } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java index 6e18c9a1c2..980f829116 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java @@ -27,27 +27,11 @@ import java.util.Iterator; import java.util.Set; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.CollectionPathsTraverser; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.PathsTraverser; @@ -55,9 +39,25 @@ import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/paths") @Singleton @Tag(name = "PathsAPI") @@ -87,6 +87,8 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, depth, maxDegree, capacity, limit); + ApiMeasure measure = new ApiMeasure(); + Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -97,7 +99,10 @@ public String get(@Context GraphManager manager, dir.opposite(), edgeLabel, depth, maxDegree, capacity, limit); - return manager.serializer(g).writePaths("paths", paths, false); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + return manager.serializer(g, measure.getResult()) + .writePaths("paths", paths, false); } @POST @@ -120,10 +125,12 @@ public String post(@Context GraphManager manager, LOG.debug("Graph [{}] get paths from source vertices '{}', target " + "vertices '{}', with step '{}', max depth '{}', " + - "capacity '{}', limit '{}' and with_vertex '{}'", + "capacity '{}', limit '{}', with vertex '{}' and with edge '{}'", graph, request.sources, request.targets, request.step, request.depth, request.capacity, request.limit, - request.withVertex); + request.withVertex, request.withEdge); + + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -131,24 +138,38 @@ public String post(@Context GraphManager manager, EdgeStep step = step(g, request.step); CollectionPathsTraverser traverser = new CollectionPathsTraverser(g); - Collection paths; - paths = traverser.paths(sources, targets, step, request.depth, - request.nearest, request.capacity, - request.limit); - - if (!request.withVertex) { - return manager.serializer(g).writePaths("paths", paths, false); + CollectionPathsTraverser.WrappedPathCollection + wrappedPathCollection = traverser.paths(sources, targets, + step, request.depth, + request.nearest, request.capacity, + request.limit); + Collection paths = wrappedPathCollection.getPaths(); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); } - - Set ids = new HashSet<>(); - for (HugeTraverser.Path p : paths) { - ids.addAll(p.vertices()); + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); } - Iterator iter = QueryResults.emptyIterator(); - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + + Iterator iterEdge; + Set edges = wrappedPathCollection.getEdges(); + if (request.withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g).writePaths("paths", paths, false, iter); + + return manager.serializer(g, measure.getResult()) + .writePaths("paths", paths, false, + iterVertex, iterEdge); } private static class Request { @@ -170,14 +191,17 @@ private static class Request { @JsonProperty("with_vertex") public boolean withVertex = false; + @JsonProperty("with_edge") + public boolean withEdge = false; + @Override public String toString() { return String.format("PathRequest{sources=%s,targets=%s,step=%s," + "maxDepth=%s,nearest=%s,capacity=%s," + - "limit=%s,withVertex=%s}", this.sources, - this.targets, this.step, this.depth, - this.nearest, this.capacity, - this.limit, this.withVertex); + "limit=%s,withVertex=%s,withEdge=%s}", + this.sources, this.targets, this.step, + this.depth, this.nearest, this.capacity, + this.limit, this.withVertex, this.withEdge); } } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java index c841412cae..abbccb804a 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java @@ -21,30 +21,35 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.SubGraphTraverser; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/rays") @Singleton @Tag(name = "RaysAPI") @@ -66,12 +71,17 @@ public String get(@Context GraphManager manager, @QueryParam("capacity") @DefaultValue(DEFAULT_CAPACITY) long capacity, @QueryParam("limit") - @DefaultValue(DEFAULT_PATHS_LIMIT) int limit) { + @DefaultValue(DEFAULT_PATHS_LIMIT) int limit, + @QueryParam("with_vertex") + @DefaultValue("false") boolean withVertex, + @QueryParam("with_edge") + @DefaultValue("false") boolean withEdge) { LOG.debug("Graph [{}] get rays paths from '{}' with " + "direction '{}', edge label '{}', max depth '{}', " + "max degree '{}', capacity '{}' and limit '{}'", graph, sourceV, direction, edgeLabel, depth, maxDegree, capacity, limit); + ApiMeasure measure = new ApiMeasure(); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -80,8 +90,33 @@ public String get(@Context GraphManager manager, SubGraphTraverser traverser = new SubGraphTraverser(g); HugeTraverser.PathSet paths = traverser.rays(source, dir, edgeLabel, - depth, maxDegree, - capacity, limit); - return manager.serializer(g).writePaths("rays", paths, false); + depth, maxDegree, capacity, + limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); + } + if (withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge; + Set edges = paths.getEdges(); + if (withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); + } + + return manager.serializer(g, measure.getResult()) + .writePaths("rays", paths, false, + iterVertex, iterEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java index 67dfe7ab72..764e2f7a91 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java @@ -21,30 +21,35 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.SubGraphTraverser; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/rings") @Singleton @Tag(name = "RingsAPI") @@ -68,14 +73,19 @@ public String get(@Context GraphManager manager, @QueryParam("capacity") @DefaultValue(DEFAULT_CAPACITY) long capacity, @QueryParam("limit") - @DefaultValue(DEFAULT_PATHS_LIMIT) int limit) { + @DefaultValue(DEFAULT_PATHS_LIMIT) int limit, + @QueryParam("with_vertex") + @DefaultValue("false") boolean withVertex, + @QueryParam("with_edge") + @DefaultValue("false") boolean withEdge) { LOG.debug("Graph [{}] get rings paths reachable from '{}' with " + "direction '{}', edge label '{}', max depth '{}', " + - "source in ring '{}', max degree '{}', capacity '{}' " + - "and limit '{}'", + "source in ring '{}', max degree '{}', capacity '{}', " + + "limit '{}', with vertex '{}' and with edge '{}'", graph, sourceV, direction, edgeLabel, depth, sourceInRing, - maxDegree, capacity, limit); + maxDegree, capacity, limit, withVertex, withEdge); + ApiMeasure measure = new ApiMeasure(); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -83,8 +93,34 @@ public String get(@Context GraphManager manager, SubGraphTraverser traverser = new SubGraphTraverser(g); HugeTraverser.PathSet paths = traverser.rings(source, dir, edgeLabel, - depth, sourceInRing, - maxDegree, capacity, limit); - return manager.serializer(g).writePaths("rings", paths, false); + depth, sourceInRing, maxDegree, + capacity, limit); + + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); + } + if (withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge; + Set edges = paths.getEdges(); + if (withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); + } + + return manager.serializer(g, measure.getResult()) + .writePaths("rings", paths, false, + iterVertex, iterEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java index a7a1770fd0..7553295c78 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java @@ -20,30 +20,40 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_ELEMENTS_LIMIT; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; import java.util.Set; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.core.GraphManager; +import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.traversal.algorithm.SameNeighborTraverser; import org.apache.hugegraph.type.define.Directions; +import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; @Path("graphs/{graph}/traversers/sameneighbors") @Singleton @@ -69,6 +79,8 @@ public String get(@Context GraphManager manager, "direction {}, edge label {}, max degree '{}' and limit '{}'", graph, vertex, other, direction, edgeLabel, maxDegree, limit); + ApiMeasure measure = new ApiMeasure(); + Id sourceId = VertexAPI.checkAndParseVertexId(vertex); Id targetId = VertexAPI.checkAndParseVertexId(other); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -77,6 +89,81 @@ public String get(@Context GraphManager manager, SameNeighborTraverser traverser = new SameNeighborTraverser(g); Set neighbors = traverser.sameNeighbors(sourceId, targetId, dir, edgeLabel, maxDegree, limit); - return manager.serializer(g).writeList("same_neighbors", neighbors); + + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + return manager.serializer(g, measure.getResult()) + .writeList("same_neighbors", neighbors); + } + + @POST + @Timed + @Produces(APPLICATION_JSON_WITH_CHARSET) + public String sameNeighbors(@Context GraphManager manager, + @PathParam("graph") String graph, + Request request) { + LOG.debug("Graph [{}] get same neighbors among batch, '{}'", graph, request.toString()); + + ApiMeasure measure = new ApiMeasure(); + + Directions dir = Directions.convert(EdgeAPI.parseDirection(request.direction)); + HugeGraph g = graph(manager, graph); + SameNeighborTraverser traverser = new SameNeighborTraverser(g); + + List vertexList = request.vertexList; + E.checkArgument(vertexList.size() >= 2, "vertex_list size can't " + + "be less than 2"); + + List vertexIds = new ArrayList<>(); + for (Object obj : vertexList) { + vertexIds.add(HugeVertex.getIdValue(obj)); + } + + Set neighbors = traverser.sameNeighbors(vertexIds, dir, request.labels, + request.maxDegree, request.limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set ids = new HashSet<>(neighbors); + ids.addAll(vertexIds); + if (request.withVertex && !ids.isEmpty()) { + iterVertex = g.vertices(ids.toArray()); + } else { + iterVertex = ids.iterator(); + } + return manager.serializer(g, measure.getResult()) + .writeMap(ImmutableMap.of("same_neighbors", neighbors, + "vertices", iterVertex)); + } + + private static class Request { + @JsonProperty("max_degree") + public long maxDegree = Long.parseLong(DEFAULT_MAX_DEGREE); + @JsonProperty("limit") + public long limit = Long.parseLong(DEFAULT_ELEMENTS_LIMIT); + @JsonProperty("vertex_list") + private List vertexList; + @JsonProperty("direction") + private String direction; + @JsonProperty("labels") + private List labels; + @JsonProperty("with_vertex") + private boolean withVertex = false; + + @Override + public String toString() { + ObjectMapper om = new ObjectMapper(); + String vertexStr; + try { + vertexStr = om.writeValueAsString(this.vertexList); + } catch (Exception e) { + throw new RuntimeException(e); + } + return String.format("SameNeighborsBatchRequest{vertex=%s,direction=%s,label=%s," + + "max_degree=%d,limit=%d,with_vertex=%s", vertexStr, this.direction, + this.labels, this.maxDegree, this.limit, this.withVertex); + } } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java index 08cbdf74cb..b74e7eb8ce 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java @@ -20,32 +20,36 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_CAPACITY; import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; +import java.util.Iterator; import java.util.List; - -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.ShortestPathTraverser; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; @Path("graphs/{graph}/traversers/shortestpath") @Singleton @@ -68,13 +72,21 @@ public String get(@Context GraphManager manager, @DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree, @QueryParam("skip_degree") @DefaultValue("0") long skipDegree, + @QueryParam("with_vertex") + @DefaultValue("false") boolean withVertex, + @QueryParam("with_edge") + @DefaultValue("false") boolean withEdge, @QueryParam("capacity") @DefaultValue(DEFAULT_CAPACITY) long capacity) { LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " + "direction {}, edge label {}, max depth '{}', " + - "max degree '{}', skipped maxDegree '{}' and capacity '{}'", + "max degree '{}', skipped maxDegree '{}', capacity '{}', " + + "with vertex '{}' and with edge '{}'", graph, source, target, direction, edgeLabel, depth, - maxDegree, skipDegree, capacity); + maxDegree, skipDegree, capacity, withVertex, withEdge); + + ApiMeasure measure = new ApiMeasure(); + Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -89,6 +101,29 @@ public String get(@Context GraphManager manager, dir, edgeLabels, depth, maxDegree, skipDegree, capacity); - return manager.serializer(g).writeList("path", path.vertices()); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + List vertexIds = path.vertices(); + if (withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(path.vertices().size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge; + Set edges = path.getEdges(); + if (withEdge) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); + } + + return manager.serializer(g, measure.getResult()) + .writeMap(ImmutableMap.of("path", path.vertices(), + "vertices", iterVertex, + "edges", iterEdge)); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java index 8813399ca7..71d195944a 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java @@ -22,33 +22,33 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_PATHS_LIMIT; import java.util.Iterator; - -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; import org.apache.hugegraph.api.graph.EdgeAPI; import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.core.GraphManager; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser; -import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser.WeightedPaths; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/singlesourceshortestpath") @Singleton @Tag(name = "SingleSourceShortestPathAPI") @@ -69,16 +69,22 @@ public String get(@Context GraphManager manager, @DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree, @QueryParam("skip_degree") @DefaultValue("0") long skipDegree, + @QueryParam("with_vertex") + @DefaultValue("false") boolean withVertex, + @QueryParam("with_edge") + @DefaultValue("false") boolean withEdge, @QueryParam("capacity") @DefaultValue(DEFAULT_CAPACITY) long capacity, @QueryParam("limit") - @DefaultValue(DEFAULT_PATHS_LIMIT) int limit, - @QueryParam("with_vertex") boolean withVertex) { + @DefaultValue(DEFAULT_PATHS_LIMIT) int limit) { LOG.debug("Graph [{}] get single source shortest path from '{}' " + "with direction {}, edge label {}, weight property {}, " + - "max degree '{}', limit '{}' and with vertex '{}'", + "max degree '{}', capacity '{}', limit '{}', " + + "with vertex '{}' and with edge '{}'", graph, source, direction, edgeLabel, - weight, maxDegree, withVertex); + weight, maxDegree, capacity, limit, withVertex, withEdge); + + ApiMeasure measure = new ApiMeasure(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -86,14 +92,31 @@ public String get(@Context GraphManager manager, HugeGraph g = graph(manager, graph); SingleSourceShortestPathTraverser traverser = new SingleSourceShortestPathTraverser(g); - WeightedPaths paths = traverser.singleSourceShortestPaths( - sourceId, dir, edgeLabel, weight, - maxDegree, skipDegree, capacity, limit); - Iterator iterator = QueryResults.emptyIterator(); - assert paths != null; - if (!paths.isEmpty() && withVertex) { - iterator = g.vertices(paths.vertices().toArray()); + SingleSourceShortestPathTraverser.WeightedPaths paths = + traverser.singleSourceShortestPaths( + sourceId, dir, edgeLabel, weight, + maxDegree, skipDegree, capacity, limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + Iterator iterVertex; + Set vertexIds = paths.vertices(); + if (withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); } - return manager.serializer(g).writeWeightedPaths(paths, iterator); + + Iterator iterEdge; + Set edges = paths.getEdges(); + if (withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); + } + + return manager.serializer(g, measure.getResult()) + .writeWeightedPaths(paths, iterVertex, iterEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java index d566fae90d..12a6088ade 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java @@ -26,30 +26,30 @@ import java.util.List; import java.util.Set; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.TemplatePathsTraverser; import org.apache.hugegraph.traversal.algorithm.steps.RepeatEdgeStep; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/templatepaths") @Singleton @Tag(name = "TemplatePathsAPI") @@ -57,6 +57,22 @@ public class TemplatePathsAPI extends TraverserAPI { private static final Logger LOG = Log.logger(TemplatePathsAPI.class); + private static List steps(HugeGraph g, + List steps) { + List edgeSteps = new ArrayList<>(steps.size()); + for (TemplatePathStep step : steps) { + edgeSteps.add(repeatEdgeStep(g, step)); + } + return edgeSteps; + } + + private static RepeatEdgeStep repeatEdgeStep(HugeGraph graph, + TemplatePathStep step) { + return new RepeatEdgeStep(graph, step.direction, step.labels, + step.properties, step.maxDegree, + step.skipDegree, step.maxTimes); + } + @POST @Timed @Consumes(APPLICATION_JSON) @@ -74,9 +90,11 @@ public String post(@Context GraphManager manager, LOG.debug("Graph [{}] get template paths from source vertices '{}', " + "target vertices '{}', with steps '{}', " + - "capacity '{}', limit '{}' and with_vertex '{}'", + "capacity '{}', limit '{}', with vertex '{}' and with edge '{}'", graph, request.sources, request.targets, request.steps, - request.capacity, request.limit, request.withVertex); + request.capacity, request.limit, request.withVertex, request.withEdge); + + ApiMeasure measure = new ApiMeasure(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -84,40 +102,38 @@ public String post(@Context GraphManager manager, List steps = steps(g, request.steps); TemplatePathsTraverser traverser = new TemplatePathsTraverser(g); - Set paths; - paths = traverser.templatePaths(sources, targets, steps, + TemplatePathsTraverser.WrappedPathSet wrappedPathSet = + traverser.templatePaths(sources, targets, steps, request.withRing, request.capacity, request.limit); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); - if (!request.withVertex) { - return manager.serializer(g).writePaths("paths", paths, false); - } + Set paths = wrappedPathSet.getPaths(); - Set ids = new HashSet<>(); - for (HugeTraverser.Path p : paths) { - ids.addAll(p.vertices()); + Iterator iterVertex; + Set vertexIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + vertexIds.addAll(path.vertices()); } - Iterator iter = QueryResults.emptyIterator(); - if (!ids.isEmpty()) { - iter = g.vertices(ids.toArray()); + if (request.withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); } - return manager.serializer(g).writePaths("paths", paths, false, iter); - } - private static List steps(HugeGraph g, - List steps) { - List edgeSteps = new ArrayList<>(steps.size()); - for (TemplatePathStep step : steps) { - edgeSteps.add(repeatEdgeStep(g, step)); + Iterator iterEdge; + Set edges = wrappedPathSet.getEdges(); + if (request.withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return edgeSteps; - } - private static RepeatEdgeStep repeatEdgeStep(HugeGraph graph, - TemplatePathStep step) { - return new RepeatEdgeStep(graph, step.direction, step.labels, - step.properties, step.maxDegree, - step.skipDegree, step.maxTimes); + return manager.serializer(g, measure.getResult()) + .writePaths("paths", paths, false, + iterVertex, iterEdge); } private static class Request { @@ -136,15 +152,17 @@ private static class Request { public int limit = Integer.parseInt(DEFAULT_PATHS_LIMIT); @JsonProperty("with_vertex") public boolean withVertex = false; + @JsonProperty("with_edge") + public boolean withEdge = false; @Override public String toString() { return String.format("TemplatePathsRequest{sources=%s,targets=%s," + "steps=%s,withRing=%s,capacity=%s,limit=%s," + - "withVertex=%s}", + "withVertex=%s,withEdge=%s}", this.sources, this.targets, this.steps, this.withRing, this.capacity, this.limit, - this.withVertex); + this.withVertex, this.withEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java index b675f618bc..9bee43d221 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java @@ -21,20 +21,8 @@ import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE; import java.util.Iterator; - -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.inject.Singleton; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; - -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.core.GraphManager; -import org.slf4j.Logger; +import java.util.List; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.api.API; @@ -42,13 +30,27 @@ import org.apache.hugegraph.api.graph.VertexAPI; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.backend.query.QueryResults; +import org.apache.hugegraph.core.GraphManager; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser; -import org.apache.hugegraph.traversal.algorithm.SingleSourceShortestPathTraverser.NodeWithWeight; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.Log; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.codahale.metrics.annotation.Timed; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.inject.Singleton; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; + @Path("graphs/{graph}/traversers/weightedshortestpath") @Singleton @Tag(name = "WeightedShortestPathAPI") @@ -70,16 +72,20 @@ public String get(@Context GraphManager manager, @DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree, @QueryParam("skip_degree") @DefaultValue("0") long skipDegree, + @QueryParam("with_vertex") + @DefaultValue("false") boolean withVertex, + @QueryParam("with_edge") + @DefaultValue("false") boolean withEdge, @QueryParam("capacity") - @DefaultValue(DEFAULT_CAPACITY) long capacity, - @QueryParam("with_vertex") boolean withVertex) { + @DefaultValue(DEFAULT_CAPACITY) long capacity) { LOG.debug("Graph [{}] get weighted shortest path between '{}' and " + "'{}' with direction {}, edge label {}, weight property {}, " + "max degree '{}', skip degree '{}', capacity '{}', " + - "and with vertex '{}'", + "with vertex '{}' and with edge '{}'", graph, source, target, direction, edgeLabel, weight, - maxDegree, skipDegree, capacity, withVertex); + maxDegree, skipDegree, capacity, withVertex, withEdge); + ApiMeasure measure = new ApiMeasure(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -89,14 +95,38 @@ public String get(@Context GraphManager manager, SingleSourceShortestPathTraverser traverser = new SingleSourceShortestPathTraverser(g); - NodeWithWeight path = traverser.weightedShortestPath( - sourceId, targetId, dir, edgeLabel, weight, - maxDegree, skipDegree, capacity); - Iterator iterator = QueryResults.emptyIterator(); - if (path != null && withVertex) { - assert !path.node().path().isEmpty(); - iterator = g.vertices(path.node().path().toArray()); + SingleSourceShortestPathTraverser.NodeWithWeight node = + traverser.weightedShortestPath(sourceId, targetId, + dir, edgeLabel, weight, + maxDegree, skipDegree, capacity); + measure.addIterCount(traverser.vertexIterCounter.get(), + traverser.edgeIterCounter.get()); + + if (node == null) { + return manager.serializer(g, measure.getResult()) + .writeWeightedPath(null, + QueryResults.emptyIterator(), + QueryResults.emptyIterator()); + } + + Iterator iterVertex; + List vertexIds = node.node().path(); + if (withVertex && !vertexIds.isEmpty()) { + iterVertex = g.vertices(vertexIds.toArray()); + measure.addIterCount(vertexIds.size(), 0L); + } else { + iterVertex = vertexIds.iterator(); + } + + Iterator iterEdge; + Set edges = node.getEdges(); + if (withEdge && !edges.isEmpty()) { + iterEdge = edges.iterator(); + } else { + iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g).writeWeightedPath(path, iterator); + + return manager.serializer(g, measure.getResult()) + .writeWeightedPath(node, iterVertex, iterEdge); } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java index 76db199498..0301037de9 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java @@ -18,18 +18,21 @@ package org.apache.hugegraph.traversal.algorithm; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.traversal.algorithm.strategy.TraverseStrategy; +import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.structure.HugeVertex; -import org.apache.hugegraph.util.E; import com.google.common.collect.ImmutableList; public class CollectionPathsTraverser extends HugeTraverser { @@ -38,10 +41,10 @@ public CollectionPathsTraverser(HugeGraph graph) { super(graph); } - public Collection paths(Iterator sources, - Iterator targets, - EdgeStep step, int depth, boolean nearest, - long capacity, long limit) { + public WrappedPathCollection paths(Iterator sources, + Iterator targets, + EdgeStep step, int depth, boolean nearest, + long capacity, long limit) { checkCapacity(capacity); checkLimit(limit); @@ -63,31 +66,33 @@ public Collection paths(Iterator sources, "but got: %s", MAX_VERTICES, sourceList.size()); checkPositive(depth, "max depth"); + boolean concurrent = depth >= this.concurrentDepth(); TraverseStrategy strategy = TraverseStrategy.create( - depth >= this.concurrentDepth(), - this.graph()); + concurrent, this.graph()); Traverser traverser; if (nearest) { traverser = new NearestTraverser(this, strategy, sourceList, targetList, step, - depth, capacity, limit); + depth, capacity, limit, concurrent); } else { traverser = new Traverser(this, strategy, sourceList, targetList, step, - depth, capacity, limit); + depth, capacity, limit, concurrent); } do { // Forward traverser.forward(); if (traverser.finished()) { - return traverser.paths(); + Collection paths = traverser.paths(); + return new WrappedPathCollection(paths, traverser.edgeRecord.getEdges(paths)); } // Backward traverser.backward(); if (traverser.finished()) { - return traverser.paths(); + Collection paths = traverser.paths(); + return new WrappedPathCollection(paths, traverser.edgeRecord.getEdges(paths)); } } while (true); } @@ -98,8 +103,9 @@ private static class Traverser extends PathTraverser { public Traverser(HugeTraverser traverser, TraverseStrategy strategy, Collection sources, Collection targets, - EdgeStep step, int depth, long capacity, long limit) { - super(traverser, strategy, sources, targets, capacity, limit); + EdgeStep step, int depth, long capacity, long limit, + boolean concurrent) { + super(traverser, strategy, sources, targets, capacity, limit, concurrent); this.step = step; this.totalSteps = depth; } @@ -180,15 +186,15 @@ protected void reInitCurrentStepIfNeeded(EdgeStep step, } } - private class NearestTraverser extends Traverser { + private static class NearestTraverser extends Traverser { public NearestTraverser(HugeTraverser traverser, TraverseStrategy strategy, Collection sources, Collection targets, EdgeStep step, int depth, long capacity, - long limit) { + long limit, boolean concurrent) { super(traverser, strategy, sources, targets, step, - depth, capacity, limit); + depth, capacity, limit, concurrent); } @Override @@ -274,4 +280,26 @@ protected int accessedNodes() { return this.sourcesAll.size() + this.targetsAll.size(); } } + + public static class WrappedPathCollection { + private final Collection paths; + private Set edges = Collections.emptySet(); + + public WrappedPathCollection(Collection paths) { + this.paths = paths; + } + + public WrappedPathCollection(Collection paths, Set edges) { + this.paths = paths; + this.edges = edges; + } + + public Collection getPaths() { + return paths; + } + + public Set getEdges() { + return edges; + } + } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java index 3d3559b05a..87f4702cb0 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java @@ -22,25 +22,54 @@ import java.util.List; import java.util.Map; -import jakarta.ws.rs.core.MultivaluedMap; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; - import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.traversal.algorithm.steps.WeightedEdgeStep; import org.apache.hugegraph.util.CollectionUtil; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import jakarta.ws.rs.core.MultivaluedMap; + public class CustomizePathsTraverser extends HugeTraverser { + private final EdgeRecord edgeRecord; public CustomizePathsTraverser(HugeGraph graph) { super(graph); + this.edgeRecord = new EdgeRecord(false); + } + + public static List topNPath(List paths, + boolean incr, long limit) { + paths.sort((p1, p2) -> { + WeightPath wp1 = (WeightPath) p1; + WeightPath wp2 = (WeightPath) p2; + int result = Double.compare(wp1.totalWeight(), wp2.totalWeight()); + return incr ? result : -result; + }); + + if (limit == NO_LIMIT || paths.size() <= limit) { + return paths; + } + return paths.subList(0, (int) limit); + } + + private static List sample(List nodes, long sample) { + if (nodes.size() <= sample) { + return nodes; + } + List result = newList((int) sample); + int size = nodes.size(); + for (int random : CollectionUtil.randomSet(0, size, (int) sample)) { + result.add(nodes.get(random)); + } + return result; } public List customizedPaths(Iterator vertices, @@ -64,7 +93,8 @@ public List customizedPaths(Iterator vertices, int pathCount = 0; long access = 0; MultivaluedMap newVertices = null; - root : for (WeightedEdgeStep step : steps) { + root: + for (WeightedEdgeStep step : steps) { stepNum--; newVertices = newMultivalueMap(); Iterator edges; @@ -75,7 +105,11 @@ public List customizedPaths(Iterator vertices, edges = this.edgesOfVertex(entry.getKey(), step.step()); while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); + this.edgeIterCounter.addAndGet(1L); Id target = edge.id().otherVertexId(); + + this.edgeRecord.addEdge(entry.getKey(), target, edge); + for (Node n : entry.getValue()) { // If have loop, skip target if (n.contains(target)) { @@ -113,6 +147,7 @@ public List customizedPaths(Iterator vertices, } } } + this.vertexIterCounter.addAndGet(sources.size()); // Re-init sources sources = newVertices; } @@ -120,6 +155,9 @@ public List customizedPaths(Iterator vertices, return ImmutableList.of(); } List paths = newList(); + if (newVertices == null) { + return ImmutableList.of(); + } for (List nodes : newVertices.values()) { for (Node n : nodes) { if (sorted) { @@ -133,36 +171,13 @@ public List customizedPaths(Iterator vertices, return paths; } - public static List topNPath(List paths, - boolean incr, long limit) { - paths.sort((p1, p2) -> { - WeightPath wp1 = (WeightPath) p1; - WeightPath wp2 = (WeightPath) p2; - int result = Double.compare(wp1.totalWeight(), wp2.totalWeight()); - return incr ? result : -result; - }); - - if (limit == NO_LIMIT || paths.size() <= limit) { - return paths; - } - return paths.subList(0, (int) limit); - } - - private static List sample(List nodes, long sample) { - if (nodes.size() <= sample) { - return nodes; - } - List result = newList((int) sample); - int size = nodes.size(); - for (int random : CollectionUtil.randomSet(0, size, (int) sample)) { - result.add(nodes.get(random)); - } - return result; + public EdgeRecord getEdgeRecord() { + return edgeRecord; } public static class WeightNode extends Node { - private double weight; + private final double weight; public WeightNode(Id id, Node parent, double weight) { super(id, parent); @@ -183,7 +198,7 @@ public List weights() { public static class WeightPath extends Path { - private List weights; + private final List weights; private double totalWeight; public WeightPath(List vertices, diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java index f097711e04..a6df06f88e 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java @@ -24,26 +24,82 @@ import java.util.Set; import java.util.stream.Collectors; -import jakarta.ws.rs.core.MultivaluedMap; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeEdge; +import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.type.define.Directions; +import org.apache.hugegraph.util.CollectionUtil; +import org.apache.hugegraph.util.E; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.hugegraph.structure.HugeEdge; -import org.apache.hugegraph.structure.HugeVertex; -import org.apache.hugegraph.util.CollectionUtil; -import org.apache.hugegraph.util.E; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import jakarta.ws.rs.core.MultivaluedMap; + public class CustomizedCrosspointsTraverser extends HugeTraverser { + private final EdgeRecord edgeRecord; + public CustomizedCrosspointsTraverser(HugeGraph graph) { super(graph); + this.edgeRecord = new EdgeRecord(false); + } + + private static CrosspointsPaths intersectionPaths(List sources, + List paths, + long limit) { + // Split paths by end vertices + MultivaluedMap endVertices = newMultivalueMap(); + for (Path path : paths) { + List vertices = path.vertices(); + int length = vertices.size(); + endVertices.add(vertices.get(0), vertices.get(length - 1)); + } + + Set sourceIds = sources.stream().map(HugeVertex::id) + .collect(Collectors.toSet()); + Set ids = endVertices.keySet(); + if (sourceIds.size() != ids.size() || !sourceIds.containsAll(ids)) { + return CrosspointsPaths.EMPTY; + } + + // Get intersection of end vertices + Collection intersection = null; + for (List ends : endVertices.values()) { + if (intersection == null) { + intersection = ends; + } else { + intersection = CollectionUtil.intersect(intersection, ends); + } + if (intersection == null || intersection.isEmpty()) { + return CrosspointsPaths.EMPTY; + } + } + assert intersection != null; + // Limit intersection number to limit crosspoints vertices in result + int size = intersection.size(); + if (limit != NO_LIMIT && size > limit) { + intersection = newList(intersection).subList(0, size - 1); + } + + // Filter intersection paths + List results = newList(); + for (Path path : paths) { + List vertices = path.vertices(); + int length = vertices.size(); + if (intersection.contains(vertices.get(length - 1))) { + results.add(path); + } + } + return new CrosspointsPaths(newSet(intersection), results); + } + + public EdgeRecord getEdgeRecord() { + return edgeRecord; } public CrosspointsPaths crosspointsPaths(Iterator vertices, @@ -64,6 +120,8 @@ public CrosspointsPaths crosspointsPaths(Iterator vertices, initialSources.add(vertex.id(), node); } List paths = newList(); + long edgeCount = 0L; + long vertexCount = 0L; for (PathPattern pathPattern : pathPatterns) { MultivaluedMap sources = initialSources; @@ -79,9 +137,14 @@ public CrosspointsPaths crosspointsPaths(Iterator vertices, for (Map.Entry> entry : sources.entrySet()) { List adjacency = newList(); edges = this.edgesOfVertex(entry.getKey(), step.edgeStep); + vertexCount += 1; while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); + edgeCount += 1; Id target = edge.id().otherVertexId(); + + this.edgeRecord.addEdge(entry.getKey(), target, edge); + for (Node n : entry.getValue()) { // If have loop, skip target if (n.contains(target)) { @@ -104,67 +167,21 @@ public CrosspointsPaths crosspointsPaths(Iterator vertices, sources = newVertices; } assert stepNum == 0; + assert newVertices != null; for (List nodes : newVertices.values()) { for (Node n : nodes) { paths.add(new Path(n.path())); } } } + this.vertexIterCounter.addAndGet(vertexCount); + this.edgeIterCounter.addAndGet(edgeCount); return intersectionPaths(verticesList, paths, limit); } - private static CrosspointsPaths intersectionPaths(List sources, - List paths, - long limit) { - // Split paths by end vertices - MultivaluedMap endVertices = newMultivalueMap(); - for (Path path : paths) { - List vertices = path.vertices(); - int length = vertices.size(); - endVertices.add(vertices.get(0), vertices.get(length - 1)); - } - - Set sourceIds = sources.stream().map(HugeVertex::id) - .collect(Collectors.toSet()); - Set ids = endVertices.keySet(); - if (sourceIds.size() != ids.size() || !sourceIds.containsAll(ids)) { - return CrosspointsPaths.EMPTY; - } - - // Get intersection of end vertices - Collection intersection = null; - for (List ends : endVertices.values()) { - if (intersection == null) { - intersection = ends; - } else { - intersection = CollectionUtil.intersect(intersection, ends); - } - if (intersection == null || intersection.isEmpty()) { - return CrosspointsPaths.EMPTY; - } - } - assert intersection != null; - // Limit intersection number to limit crosspoints vertices in result - int size = intersection.size(); - if (limit != NO_LIMIT && size > limit) { - intersection = newList(intersection).subList(0, size - 1); - } - - // Filter intersection paths - List results = newList(); - for (Path path : paths) { - List vertices = path.vertices(); - int length = vertices.size(); - if (intersection.contains(vertices.get(length - 1))) { - results.add(path); - } - } - return new CrosspointsPaths(newSet(intersection), results); - } - public static class PathPattern { - private List steps; + private final List steps; public PathPattern() { this.steps = newList(); @@ -201,8 +218,8 @@ public static class CrosspointsPaths { ImmutableSet.of(), ImmutableList.of() ); - private Set crosspoints; - private List paths; + private final Set crosspoints; + private final List paths; public CrosspointsPaths(Set crosspoints, List paths) { this.crosspoints = crosspoints; diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/FusiformSimilarityTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/FusiformSimilarityTraverser.java index b39ea009ff..b322167c28 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/FusiformSimilarityTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/FusiformSimilarityTraverser.java @@ -22,27 +22,27 @@ import java.util.Map; import java.util.Set; -import jakarta.ws.rs.core.MultivaluedHashMap; -import jakarta.ws.rs.core.MultivaluedMap; - import org.apache.commons.lang3.mutable.MutableInt; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.schema.EdgeLabel; +import org.apache.hugegraph.structure.HugeEdge; +import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.type.define.Frequency; +import org.apache.hugegraph.util.E; +import org.apache.hugegraph.util.InsertionOrderUtil; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import org.apache.hugegraph.structure.HugeEdge; -import org.apache.hugegraph.structure.HugeVertex; -import org.apache.hugegraph.util.E; -import org.apache.hugegraph.util.InsertionOrderUtil; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; + public class FusiformSimilarityTraverser extends HugeTraverser { private long accessed = 0L; @@ -51,6 +51,20 @@ public FusiformSimilarityTraverser(HugeGraph graph) { super(graph); } + private static void checkGroupArgs(String groupProperty, int minGroups) { + if (groupProperty == null) { + E.checkArgument(minGroups == 0, + "Can't set min group count when " + + "group property not set"); + } else { + E.checkArgument(!groupProperty.isEmpty(), + "The group property can't be empty"); + E.checkArgument(minGroups > 0, + "Must set min group count when " + + "group property set"); + } + } + public SimilarsMap fusiformSimilarity(Iterator vertices, Directions direction, String label, int minNeighbors, double alpha, @@ -69,10 +83,10 @@ public SimilarsMap fusiformSimilarity(Iterator vertices, HugeVertex vertex = (HugeVertex) vertices.next(); // Find fusiform similarity for current vertex Set result = this.fusiformSimilarityForVertex( - vertex, direction, label, - minNeighbors, alpha, minSimilars, top, - groupProperty, minGroups, degree, capacity, - withIntermediary); + vertex, direction, label, + minNeighbors, alpha, minSimilars, top, + groupProperty, minGroups, degree, capacity, + withIntermediary); if (result.isEmpty()) { continue; } @@ -87,11 +101,11 @@ public SimilarsMap fusiformSimilarity(Iterator vertices, } private Set fusiformSimilarityForVertex( - HugeVertex vertex, Directions direction, - String label, int minNeighbors, double alpha, - int minSimilars, int top, String groupProperty, - int minGroups, long degree, long capacity, - boolean withIntermediary) { + HugeVertex vertex, Directions direction, + String label, int minNeighbors, double alpha, + int minSimilars, int top, String groupProperty, + int minGroups, long degree, long capacity, + boolean withIntermediary) { boolean matched = this.matchMinNeighborCount(vertex, direction, label, minNeighbors, degree); if (!matched) { @@ -105,6 +119,7 @@ private Set fusiformSimilarityForVertex( Map similars = newMap(); MultivaluedMap intermediaries = new MultivaluedHashMap<>(); Set neighbors = newIdSet(); + long vertexCount = 1L; while (edges.hasNext()) { Id target = ((HugeEdge) edges.next()).id().otherVertexId(); if (neighbors.contains(target)) { @@ -116,6 +131,7 @@ private Set fusiformSimilarityForVertex( Directions backDir = direction.opposite(); Iterator backEdges = this.edgesOfVertex(target, backDir, labelId, degree); + vertexCount += 1L; Set currentSimilars = newIdSet(); while (backEdges.hasNext()) { Id node = ((HugeEdge) backEdges.next()).id().otherVertexId(); @@ -137,6 +153,9 @@ private Set fusiformSimilarityForVertex( count.increment(); } } + this.edgeIterCounter.addAndGet(this.accessed); + this.vertexIterCounter.addAndGet(vertexCount); + // Delete source vertex assert similars.containsKey(vertex.id()); similars.remove(vertex.id()); @@ -189,20 +208,6 @@ private Set fusiformSimilarityForVertex( return result; } - private static void checkGroupArgs(String groupProperty, int minGroups) { - if (groupProperty == null) { - E.checkArgument(minGroups == 0, - "Can't set min group count when " + - "group property not set"); - } else { - E.checkArgument(!groupProperty.isEmpty(), - "The group property can't be empty"); - E.checkArgument(minGroups > 0, - "Must set min group count when " + - "group property set"); - } - } - private boolean matchMinNeighborCount(HugeVertex vertex, Directions direction, String label, @@ -249,7 +254,7 @@ public Similar(Id id, double score, List intermediaries) { this.id = id; this.score = score; assert newSet(intermediaries).size() == intermediaries.size() : - "Invalid intermediaries"; + "Invalid intermediaries"; this.intermediaries = intermediaries; } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java index 21344e6b2a..c0d36f31bd 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java @@ -19,15 +19,16 @@ import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - -import jakarta.ws.rs.core.MultivaluedHashMap; -import jakarta.ws.rs.core.MultivaluedMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.hugegraph.HugeException; @@ -39,39 +40,38 @@ import org.apache.hugegraph.backend.query.QueryResults; import org.apache.hugegraph.backend.tx.GraphTransaction; import org.apache.hugegraph.config.CoreOptions; -import org.apache.hugegraph.schema.SchemaLabel; -import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; -import org.apache.hugegraph.type.HugeType; -import org.apache.hugegraph.type.define.CollectionType; -import org.apache.hugegraph.type.define.Directions; -import org.apache.hugegraph.type.define.HugeKeys; -import org.apache.hugegraph.util.collection.CollectionFactory; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.slf4j.Logger; - import org.apache.hugegraph.exception.NotFoundException; import org.apache.hugegraph.iterator.ExtendableIterator; import org.apache.hugegraph.iterator.FilterIterator; import org.apache.hugegraph.iterator.LimitIterator; import org.apache.hugegraph.iterator.MapperIterator; import org.apache.hugegraph.perf.PerfUtil.Watched; +import org.apache.hugegraph.schema.SchemaLabel; import org.apache.hugegraph.structure.HugeEdge; +import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.traversal.optimize.TraversalUtil; +import org.apache.hugegraph.type.HugeType; +import org.apache.hugegraph.type.define.CollectionType; +import org.apache.hugegraph.type.define.Directions; +import org.apache.hugegraph.type.define.HugeKeys; import org.apache.hugegraph.util.CollectionUtil; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.InsertionOrderUtil; import org.apache.hugegraph.util.Log; +import org.apache.hugegraph.util.collection.CollectionFactory; +import org.apache.hugegraph.util.collection.ObjectIntMapping; +import org.apache.hugegraph.util.collection.ObjectIntMappingFactory; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.slf4j.Logger; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -public class HugeTraverser { - - protected static final Logger LOG = Log.logger(HugeTraverser.class); - - private HugeGraph graph; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.MultivaluedMap; - private static CollectionFactory collectionFactory; +public class HugeTraverser { public static final String DEFAULT_CAPACITY = "10000000"; public static final String DEFAULT_ELEMENTS_LIMIT = "10000000"; @@ -82,13 +82,16 @@ public class HugeTraverser { public static final String DEFAULT_SAMPLE = "100"; public static final String DEFAULT_WEIGHT = "0"; public static final int DEFAULT_MAX_DEPTH = 5000; - - protected static final int MAX_VERTICES = 10; - // Empirical value of scan limit, with which results can be returned in 3s public static final String DEFAULT_PAGE_LIMIT = "100000"; - public static final long NO_LIMIT = -1L; + protected static final Logger LOG = Log.logger(HugeTraverser.class); + protected static final int MAX_VERTICES = 10; + private static CollectionFactory collectionFactory; + private final HugeGraph graph; + // for apimeasure + public AtomicLong edgeIterCounter = new AtomicLong(0); + public AtomicLong vertexIterCounter = new AtomicLong(0); public HugeTraverser(HugeGraph graph) { this.graph = graph; @@ -97,6 +100,178 @@ public HugeTraverser(HugeGraph graph) { } } + public static void checkDegree(long degree) { + checkPositiveOrNoLimit(degree, "max degree"); + } + + public static void checkCapacity(long capacity) { + checkPositiveOrNoLimit(capacity, "capacity"); + } + + public static void checkLimit(long limit) { + checkPositiveOrNoLimit(limit, "limit"); + } + + public static void checkPositive(long value, String name) { + E.checkArgument(value > 0, + "The %s parameter must be > 0, but got %s", + name, value); + } + + public static void checkPositiveOrNoLimit(long value, String name) { + E.checkArgument(value > 0L || value == NO_LIMIT, + "The %s parameter must be > 0 or == %s, but got: %s", + name, NO_LIMIT, value); + } + + public static void checkNonNegative(long value, String name) { + E.checkArgument(value >= 0L, + "The %s parameter must be >= 0, but got: %s", + name, value); + } + + public static void checkNonNegativeOrNoLimit(long value, String name) { + E.checkArgument(value >= 0L || value == NO_LIMIT, + "The %s parameter must be >= 0 or == %s, but got: %s", + name, NO_LIMIT, value); + } + + public static void checkCapacity(long capacity, long access, + String traverse) { + if (capacity != NO_LIMIT && access > capacity) { + throw new HugeException("Exceed capacity '%s' while finding %s", + capacity, traverse); + } + } + + public static void checkSkipDegree(long skipDegree, long degree, + long capacity) { + E.checkArgument(skipDegree >= 0L && + skipDegree <= Query.DEFAULT_CAPACITY, + "The skipped degree must be in [0, %s], but got '%s'", + Query.DEFAULT_CAPACITY, skipDegree); + if (capacity != NO_LIMIT) { + E.checkArgument(degree != NO_LIMIT && degree < capacity, + "The max 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 >= max degree, " + + "but got skipped degree '%s' and max degree '%s'", + skipDegree, degree); + } + } + + public static > Map topN( + Map map, + boolean sorted, + long limit) { + if (sorted) { + map = CollectionUtil.sortByValue(map, false); + } + if (limit == NO_LIMIT || map.size() <= limit) { + return map; + } + Map results = InsertionOrderUtil.newMap(); + long count = 0L; + for (Map.Entry entry : map.entrySet()) { + results.put(entry.getKey(), entry.getValue()); + if (++count >= limit) { + break; + } + } + return results; + } + + public static Iterator skipSuperNodeIfNeeded(Iterator edges, + long degree, + long skipDegree) { + if (skipDegree <= 0L) { + return edges; + } + List edgeList = newList(); + for (int i = 1; edges.hasNext(); i++) { + Edge edge = edges.next(); + if (i <= degree) { + edgeList.add(edge); + } + if (i >= skipDegree) { + return QueryResults.emptyIterator(); + } + } + return edgeList.iterator(); + } + + protected static Set newIdSet() { + return collectionFactory.newIdSet(); + } + + protected static Set newSet() { + return newSet(false); + } + + protected static Set newSet(boolean concurrent) { + if (concurrent) { + return ConcurrentHashMap.newKeySet(); + } else { + return collectionFactory.newSet(); + } + } + + protected static Set newSet(int initialCapacity) { + return collectionFactory.newSet(initialCapacity); + } + + protected static Set newSet(Collection collection) { + return collectionFactory.newSet(collection); + } + + protected static List newList() { + return collectionFactory.newList(); + } + + protected static List newList(int initialCapacity) { + return collectionFactory.newList(initialCapacity); + } + + protected static List newList(Collection collection) { + return collectionFactory.newList(collection); + } + + protected static Map newMap() { + return collectionFactory.newMap(); + } + + protected static Map newMap(int initialCapacity) { + return collectionFactory.newMap(initialCapacity); + } + + protected static MultivaluedMap newMultivalueMap() { + return new MultivaluedHashMap<>(); + } + + protected static List joinPath(Node prev, Node back, boolean ring) { + // Get self path + List path = prev.path(); + + // Get reversed other path + List backPath = back.path(); + Collections.reverse(backPath); + + if (!ring) { + // Avoid loop in path + if (CollectionUtils.containsAny(path, backPath)) { + return ImmutableList.of(); + } + } + + // Append other path behind self path + path.addAll(backPath); + return path; + } + public HugeGraph graph() { return this.graph; } @@ -157,6 +332,15 @@ protected Set adjacentVertices(Id source, EdgeStep step) { return neighbors; } + protected Iterator adjacentVertices(Id source, Directions dir, + List labels, long limit) { + Iterator edges = this.edgesOfVertex(source, dir, labels, limit); + return new MapperIterator<>(edges, e -> { + HugeEdge edge = (HugeEdge) e; + return edge.id().otherVertexId(); + }); + } + @Watched protected Iterator edgesOfVertex(Id source, Directions dir, Id label, long limit) { @@ -189,9 +373,26 @@ protected Iterator edgesOfVertex(Id source, Directions dir, } long[] count = new long[1]; - return new LimitIterator<>(results, e -> { - return count[0]++ >= limit; - }); + return new LimitIterator<>(results, e -> count[0]++ >= limit); + } + + protected Iterator edgesOfVertex(Id source, Directions dir, + List labels, long limit) { + if (labels == null || labels.isEmpty()) { + return this.edgesOfVertex(source, dir, (Id) null, limit); + } + ExtendableIterator results = new ExtendableIterator<>(); + for (Id label : labels) { + E.checkNotNull(label, "edge label"); + results.extend(this.edgesOfVertex(source, dir, label, limit)); + } + + if (limit == NO_LIMIT) { + return results; + } + + long[] count = new long[1]; + return new LimitIterator<>(results, e -> count[0]++ >= limit); } protected Iterator edgesOfVertex(Id source, EdgeStep edgeStep) { @@ -253,7 +454,7 @@ private void fillFilterBySortKeys(Query query, Id[] edgeLabels, if (!GraphTransaction.matchFullEdgeSortKeys(condQuery, this.graph())) { Id label = condQuery.condition(HugeKeys.LABEL); E.checkArgument(false, "The properties %s does not match " + - "sort keys of edge label '%s'", + "sort keys of edge label '%s'", this.graph().mapPkId2Name(properties.keySet()), this.graph().edgeLabel(label).name()); } @@ -308,182 +509,10 @@ protected void checkVertexExist(Id vertexId, String name) { this.graph.vertex(vertexId); } catch (NotFoundException e) { throw new IllegalArgumentException(String.format( - "The %s with id '%s' does not exist", name, vertexId), e); - } - } - - public static void checkDegree(long degree) { - checkPositiveOrNoLimit(degree, "max degree"); - } - - public static void checkCapacity(long capacity) { - checkPositiveOrNoLimit(capacity, "capacity"); - } - - public static void checkLimit(long limit) { - checkPositiveOrNoLimit(limit, "limit"); - } - - public static void checkPositive(long value, String name) { - E.checkArgument(value > 0, - "The %s parameter must be > 0, but got %s", - name, value); - } - - public static void checkPositiveOrNoLimit(long value, String name) { - E.checkArgument(value > 0L || value == NO_LIMIT, - "The %s parameter must be > 0 or == %s, but got: %s", - name, NO_LIMIT, value); - } - - public static void checkNonNegative(long value, String name) { - E.checkArgument(value >= 0L, - "The %s parameter must be >= 0, but got: %s", - name, value); - } - - public static void checkNonNegativeOrNoLimit(long value, String name) { - E.checkArgument(value >= 0L || value == NO_LIMIT, - "The %s parameter must be >= 0 or == %s, but got: %s", - name, NO_LIMIT, value); - } - - public static void checkCapacity(long capacity, long access, - String traverse) { - if (capacity != NO_LIMIT && access > capacity) { - throw new HugeException("Exceed capacity '%s' while finding %s", - capacity, traverse); - } - } - - public static void checkSkipDegree(long skipDegree, long degree, - long capacity) { - E.checkArgument(skipDegree >= 0L && - skipDegree <= Query.DEFAULT_CAPACITY, - "The skipped degree must be in [0, %s], but got '%s'", - Query.DEFAULT_CAPACITY, skipDegree); - if (capacity != NO_LIMIT) { - E.checkArgument(degree != NO_LIMIT && degree < capacity, - "The max 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 >= max degree, " + - "but got skipped degree '%s' and max degree '%s'", - skipDegree, degree); - } - } - - public static > Map topN( - Map map, - boolean sorted, - long limit) { - if (sorted) { - map = CollectionUtil.sortByValue(map, false); - } - if (limit == NO_LIMIT || map.size() <= limit) { - return map; - } - Map results = InsertionOrderUtil.newMap(); - long count = 0L; - for (Map.Entry entry : map.entrySet()) { - results.put(entry.getKey(), entry.getValue()); - if (++count >= limit) { - break; - } - } - return results; - } - - public static Iterator skipSuperNodeIfNeeded(Iterator edges, - long degree, - long skipDegree) { - if (skipDegree <= 0L) { - return edges; - } - List edgeList = newList(); - for (int i = 1; edges.hasNext(); i++) { - Edge edge = edges.next(); - if (i <= degree) { - edgeList.add(edge); - } - if (i >= skipDegree) { - return QueryResults.emptyIterator(); - } - } - return edgeList.iterator(); - } - - protected static Set newIdSet() { - return collectionFactory.newIdSet(); - } - - protected static Set newSet() { - return newSet(false); - } - - protected static Set newSet(boolean concurrent) { - if (concurrent) { - return ConcurrentHashMap.newKeySet(); - } else { - return collectionFactory.newSet(); + "The %s with id '%s' does not exist", name, vertexId), e); } } - protected static Set newSet(int initialCapacity) { - return collectionFactory.newSet(initialCapacity); - } - - protected static Set newSet(Collection collection) { - return collectionFactory.newSet(collection); - } - - protected static List newList() { - return collectionFactory.newList(); - } - - protected static List newList(int initialCapacity) { - return collectionFactory.newList(initialCapacity); - } - - protected static List newList(Collection collection) { - return collectionFactory.newList(collection); - } - - protected static Map newMap() { - return collectionFactory.newMap(); - } - - protected static Map newMap(int initialCapacity) { - return collectionFactory.newMap(initialCapacity); - } - - protected static MultivaluedMap newMultivalueMap() { - return new MultivaluedHashMap<>(); - } - - protected static List joinPath(Node prev, Node back, boolean ring) { - // Get self path - List path = prev.path(); - - // Get reversed other path - List backPath = back.path(); - Collections.reverse(backPath); - - if (!ring) { - // Avoid loop in path - if (CollectionUtils.containsAny(path, backPath)) { - return ImmutableList.of(); - } - } - - // Append other path behind self path - path.addAll(backPath); - return path; - } - public static class Node { private final Id id; @@ -560,6 +589,7 @@ public static class Path { private final Id crosspoint; private final List vertices; + private Set edges = Collections.emptySet(); public Path(List vertices) { this(null, vertices); @@ -570,6 +600,19 @@ public Path(Id crosspoint, List vertices) { this.vertices = vertices; } + public Path(List vertices, Set edges) { + this(null, vertices); + this.edges = edges; + } + + public Set getEdges() { + return edges; + } + + public void setEdges(Set edges) { + this.edges = edges; + } + public Id crosspoint() { return this.crosspoint; } @@ -615,6 +658,7 @@ public int hashCode() { * Compares the specified object with this path for equality. * Returns true if and only if both have same vertices list * without regard of crosspoint. + * * @param other the object to be compared for equality with this path * @return true if the specified object is equal to this path */ @@ -638,6 +682,13 @@ public static class PathSet implements Set { private final Set paths; + private Set edges = Collections.emptySet(); + + public PathSet(Set paths, Set edges) { + this(paths); + this.edges = edges; + } + public PathSet() { this(newSet()); } @@ -646,6 +697,18 @@ private PathSet(Set paths) { this.paths = paths; } + public Set getPaths() { + return this.paths; + } + + public Set getEdges() { + return edges; + } + + public void setEdges(Set edges) { + this.edges = edges; + } + @Override public boolean add(Path path) { return this.paths.add(path); @@ -729,7 +792,7 @@ public String toString() { } public void append(Id current) { - for (Iterator iter = paths.iterator(); iter.hasNext();) { + for (Iterator iter = paths.iterator(); iter.hasNext(); ) { Path path = iter.next(); if (path.vertices().contains(current)) { iter.remove(); @@ -739,4 +802,80 @@ public void append(Id current) { } } } + + public static class EdgeRecord { + private final Map edgeMap; + private final ObjectIntMapping idMapping; + + public EdgeRecord(boolean concurrent) { + this.edgeMap = new HashMap<>(); + this.idMapping = ObjectIntMappingFactory.newObjectIntMapping(concurrent); + } + + private static Long makeVertexPairIndex(int source, int target) { + return ((long) source & 0xFFFFFFFFL) | + (((long) target << 32) & 0xFFFFFFFF00000000L); + } + + public static Set getEdgeIds(Set edges) { + return edges.stream().map(edge -> ((HugeEdge) edge).id()).collect(Collectors.toSet()); + } + + private int code(Id id) { + if (id.number()) { + long l = id.asLong(); + if (0 <= l && l <= Integer.MAX_VALUE) { + return (int) l; + } + } + int code = this.idMapping.object2Code(id); + assert code > 0; + return -code; + } + + public void addEdge(Id source, Id target, Edge edge) { + Long index = makeVertexPairIndex(this.code(source), this.code(target)); + this.edgeMap.put(index, edge); + } + + private Edge getEdge(Id source, Id target) { + Long index = makeVertexPairIndex(this.code(source), this.code(target)); + return this.edgeMap.get(index); + } + + public Set getEdges(HugeTraverser.Path path) { + if (path == null || path.vertices().isEmpty()) { + return new HashSet<>(); + } + Iterator vertexIter = path.vertices().iterator(); + return getEdges(vertexIter); + } + + public Set getEdges(Collection paths) { + Set edgeIds = new HashSet<>(); + for (HugeTraverser.Path path : paths) { + edgeIds.addAll(getEdges(path)); + } + return edgeIds; + } + + public Set getEdges(Iterator vertexIter) { + Set edges = new HashSet<>(); + Id first = vertexIter.next(); + Id second; + while (vertexIter.hasNext()) { + second = vertexIter.next(); + Edge edge = getEdge(first, second); + if (edge == null) { + edge = getEdge(second, first); + } + if (edge != null) { + edges.add(edge); + } + first = second; + } + return edges; + } + + } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/JaccardSimilarTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/JaccardSimilarTraverser.java index 240792abe2..a5539cd0f6 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/JaccardSimilarTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/JaccardSimilarTraverser.java @@ -27,10 +27,10 @@ import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.type.define.Directions; -import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; - import org.apache.hugegraph.util.CollectionUtil; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; + import com.google.common.collect.ImmutableMap; public class JaccardSimilarTraverser extends OltpTraverser { @@ -39,6 +39,12 @@ public JaccardSimilarTraverser(HugeGraph graph) { super(graph); } + private static void reachCapacity(long count, long capacity) { + if (capacity != NO_LIMIT && count > capacity) { + throw new HugeException("Reach capacity '%s'", capacity); + } + } + public double jaccardSimilarity(Id vertex, Id other, Directions dir, String label, long degree) { E.checkNotNull(vertex, "vertex id"); @@ -51,9 +57,14 @@ public double jaccardSimilarity(Id vertex, Id other, Directions dir, Id labelId = this.getEdgeLabelId(label); Set sourceNeighbors = IteratorUtils.set(this.adjacentVertices( - vertex, dir, labelId, degree)); + vertex, dir, labelId, degree)); Set targetNeighbors = IteratorUtils.set(this.adjacentVertices( - other, dir, labelId, degree)); + other, dir, labelId, degree)); + + this.vertexIterCounter.addAndGet(2L); + this.edgeIterCounter.addAndGet(sourceNeighbors.size()); + this.edgeIterCounter.addAndGet(targetNeighbors.size()); + return jaccardSimilarity(sourceNeighbors, targetNeighbors); } @@ -96,6 +107,10 @@ public Map jaccardSimilarsConcurrent(Id source, EdgeStep step, // Query neighbors Set layer1s = this.adjacentVertices(source, step); + + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(layer1s.size()); + reachCapacity(count.get() + layer1s.size(), capacity); count.addAndGet(layer1s.size()); if (layer1s.isEmpty()) { @@ -111,6 +126,10 @@ public Map jaccardSimilarsConcurrent(Id source, EdgeStep step, return; } Set layer2s = this.adjacentVertices(id, step); + + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(layer2s.size()); + if (layer2s.isEmpty()) { results.put(id, 0.0D); } @@ -130,6 +149,10 @@ public Map jaccardSimilarsConcurrent(Id source, EdgeStep step, return; } Set layer3s = this.adjacentVertices(id, step); + + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(layer3s.size()); + reachCapacity(count.get() + layer3s.size(), capacity); if (layer3s.isEmpty()) { results.put(id, 0.0D); @@ -152,6 +175,10 @@ public Map jaccardSimilarsSingle(Id source, EdgeStep step, // Query neighbors Set layer1s = this.adjacentVertices(source, step); + + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(layer1s.size()); + reachCapacity(count + layer1s.size(), capacity); count += layer1s.size(); if (layer1s.isEmpty()) { @@ -168,6 +195,10 @@ public Map jaccardSimilarsSingle(Id source, EdgeStep step, continue; } layer2s = this.adjacentVertices(neighbor, step); + + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(layer2s.size()); + if (layer2s.isEmpty()) { results.put(neighbor, 0.0D); continue; @@ -188,6 +219,10 @@ public Map jaccardSimilarsSingle(Id source, EdgeStep step, continue; } layer3s = this.adjacentVertices(neighbor, step); + + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(layer3s.size()); + reachCapacity(count + layer3s.size(), capacity); if (layer3s.isEmpty()) { results.put(neighbor, 0.0D); @@ -201,10 +236,4 @@ public Map jaccardSimilarsSingle(Id source, EdgeStep step, return results; } - - private static void reachCapacity(long count, long capacity) { - if (capacity != NO_LIMIT && count > capacity) { - throw new HugeException("Reach capacity '%s'", capacity); - } - } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java index c9381cd423..ac8aa579c9 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java @@ -23,13 +23,12 @@ import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.traversal.algorithm.records.KneighborRecords; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.type.define.Directions; -import org.apache.tinkerpop.gremlin.structure.Edge; - -import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; public class KneighborTraverser extends OltpTraverser { @@ -53,12 +52,15 @@ public Set kneighbor(Id sourceV, Directions dir, Set all = newSet(); latest.add(sourceV); + this.vertexIterCounter.addAndGet(1L); while (depth-- > 0) { long remaining = limit == NO_LIMIT ? NO_LIMIT : limit - all.size(); latest = this.adjacentVertices(sourceV, latest, dir, labelId, all, degree, remaining); all.addAll(latest); + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(latest.size()); if (reachLimit(limit, all.size())) { break; } @@ -84,9 +86,15 @@ public KneighborRecords customizedKneighbor(Id source, EdgeStep step, return; } Iterator edges = edgesOfVertex(v, step); + this.vertexIterCounter.addAndGet(1L); while (!this.reachLimit(limit, records.size()) && edges.hasNext()) { - Id target = ((HugeEdge) edges.next()).id().otherVertexId(); + HugeEdge edge = (HugeEdge) edges.next(); + Id target = edge.id().otherVertexId(); records.addPath(v, target); + + records.getEdgeIdRecord().addEdge(v, target, edge); + + this.edgeIterCounter.addAndGet(1L); } }; diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java index 2c268c94b4..bb97be0aa3 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java @@ -24,13 +24,12 @@ import org.apache.hugegraph.HugeException; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.traversal.algorithm.records.KoutRecords; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.type.define.Directions; -import org.apache.tinkerpop.gremlin.structure.Edge; - -import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; public class KoutTraverser extends OltpTraverser { @@ -66,6 +65,7 @@ public Set kout(Id sourceV, Directions dir, String label, long remaining = capacity == NO_LIMIT ? NO_LIMIT : capacity - latest.size(); + this.vertexIterCounter.addAndGet(1L); while (depth-- > 0) { // Just get limit nodes in last layer if limit < remaining capacity if (depth == 0 && limit != NO_LIMIT && @@ -80,14 +80,16 @@ public Set kout(Id sourceV, Directions dir, String label, latest = this.adjacentVertices(sourceV, latest, dir, labelId, null, degree, remaining); } + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(latest.size()); if (capacity != NO_LIMIT) { // Update 'remaining' value to record remaining capacity remaining -= latest.size(); if (remaining <= 0 && depth > 0) { throw new HugeException( - "Reach capacity '%s' while remaining depth '%s'", - capacity, depth); + "Reach capacity '%s' while remaining depth '%s'", + capacity, depth); } } } @@ -114,11 +116,17 @@ public KoutRecords customizedKout(Id source, EdgeStep step, return; } Iterator edges = edgesOfVertex(v, step); + this.vertexIterCounter.addAndGet(1L); while (!this.reachLimit(limit, depth[0], records.size()) && edges.hasNext()) { - Id target = ((HugeEdge) edges.next()).id().otherVertexId(); + HugeEdge edge = (HugeEdge) edges.next(); + Id target = edge.id().otherVertexId(); records.addPath(v, target); this.checkCapacity(capacity, records.accessed(), depth[0]); + + records.getEdgeIdRecord().addEdge(v, target, edge); + + this.edgeIterCounter.addAndGet(1L); } }; @@ -136,8 +144,8 @@ private void checkCapacity(long capacity, long accessed, long depth) { } if (accessed >= capacity && depth > 0) { throw new HugeException( - "Reach capacity '%s' while remaining depth '%s'", - capacity, depth); + "Reach capacity '%s' while remaining depth '%s'", + capacity, depth); } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java index 493b97286d..f579d352e9 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java @@ -19,28 +19,55 @@ import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Consumer; import org.apache.commons.lang3.tuple.Pair; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; +import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import org.apache.hugegraph.structure.HugeVertex; -import org.apache.hugegraph.util.E; - public class MultiNodeShortestPathTraverser extends OltpTraverser { public MultiNodeShortestPathTraverser(HugeGraph graph) { super(graph); } - public List multiNodeShortestPath(Iterator vertices, - EdgeStep step, int maxDepth, - long capacity) { + private static void cmn(List all, int m, int n, int current, + List result, Consumer> consumer) { + assert m <= all.size(); + assert current <= all.size(); + if (result == null) { + result = newList(n); + } + if (n == 0) { + // All n items are selected + consumer.accept(result); + return; + } + if (m < n || current >= all.size()) { + return; + } + + // Select current item, continue to select C(m-1, n-1) + int index = result.size(); + result.add(all.get(current)); + cmn(all, m - 1, n - 1, ++current, result, consumer); + // Not select current item, continue to select C(m-1, n) + result.remove(index); + cmn(all, m - 1, n, current, result, consumer); + } + + public WrappedListPath multiNodeShortestPath(Iterator vertices, + EdgeStep step, int maxDepth, + long capacity) { List vertexList = IteratorUtils.list(vertices); int vertexCount = vertexList.size(); E.checkState(vertexCount >= 2 && vertexCount <= MAX_VERTICES, @@ -56,70 +83,69 @@ public List multiNodeShortestPath(Iterator vertices, }); if (maxDepth >= this.concurrentDepth() && vertexCount > 10) { - return this.multiNodeShortestPathConcurrent(pairs, step, - maxDepth, capacity); + return this.multiNodeShortestPathConcurrent(pairs, step, maxDepth, capacity); } else { - return this.multiNodeShortestPathSingle(pairs, step, - maxDepth, capacity); + return this.multiNodeShortestPathSingle(pairs, step, maxDepth, capacity); } } - public List multiNodeShortestPathConcurrent(List> pairs, - EdgeStep step, - int maxDepth, - long capacity) { - List results = new CopyOnWriteArrayList<>(); + public WrappedListPath multiNodeShortestPathConcurrent(List> pairs, + EdgeStep step, int maxDepth, + long capacity) { + List paths = new CopyOnWriteArrayList<>(); + Set edges = new CopyOnWriteArraySet<>(); ShortestPathTraverser traverser = - new ShortestPathTraverser(this.graph()); + new ShortestPathTraverser(this.graph()); this.traversePairs(pairs.iterator(), pair -> { Path path = traverser.shortestPath(pair.getLeft(), pair.getRight(), step, maxDepth, capacity); if (!Path.EMPTY.equals(path)) { - results.add(path); + paths.add(path); } + edges.addAll(path.getEdges()); }); + this.vertexIterCounter.addAndGet(traverser.vertexIterCounter.get()); + this.edgeIterCounter.addAndGet(traverser.edgeIterCounter.get()); - return results; + return new WrappedListPath(paths, edges); } - public List multiNodeShortestPathSingle(List> pairs, - EdgeStep step, int maxDepth, - long capacity) { - List results = newList(); + public WrappedListPath multiNodeShortestPathSingle(List> pairs, + EdgeStep step, int maxDepth, + long capacity) { + List paths = newList(); + Set edges = newSet(); ShortestPathTraverser traverser = - new ShortestPathTraverser(this.graph()); + new ShortestPathTraverser(this.graph()); for (Pair pair : pairs) { Path path = traverser.shortestPath(pair.getLeft(), pair.getRight(), step, maxDepth, capacity); if (!Path.EMPTY.equals(path)) { - results.add(path); + paths.add(path); } + edges.addAll(path.getEdges()); } - return results; + this.vertexIterCounter.addAndGet(traverser.vertexIterCounter.get()); + this.edgeIterCounter.addAndGet(traverser.edgeIterCounter.get()); + + return new WrappedListPath(paths, edges); } - private static void cmn(List all, int m, int n, int current, - List result, Consumer> consumer) { - assert m <= all.size(); - assert current <= all.size(); - if (result == null) { - result = newList(n); - } - if (n == 0) { - // All n items are selected - consumer.accept(result); - return; + public static class WrappedListPath { + private final List paths; + private final Set edges; + + public WrappedListPath(List paths, Set edges) { + this.paths = paths; + this.edges = edges; } - if (m < n || current >= all.size()) { - return; + + public List getPaths() { + return paths; } - // Select current item, continue to select C(m-1, n-1) - int index = result.size(); - result.add(all.get(current)); - cmn(all, m - 1, n - 1, ++current, result, consumer); - // Not select current item, continue to select C(m-1, n) - result.remove(index); - cmn(all, m - 1, n, current, result, consumer); + public Set getEdges() { + return edges; + } } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java index 7ae281640d..6ba7eb68d5 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java @@ -17,6 +17,8 @@ package org.apache.hugegraph.traversal.algorithm; +import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.NO_LIMIT; + import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -25,21 +27,17 @@ import java.util.function.BiConsumer; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.traversal.algorithm.strategy.TraverseStrategy; import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.hugegraph.structure.HugeEdge; - -import static org.apache.hugegraph.traversal.algorithm.HugeTraverser.NO_LIMIT; - public abstract class PathTraverser { protected final HugeTraverser traverser; - - protected int stepCount; protected final long capacity; protected final long limit; + protected int stepCount; protected int totalSteps; // TODO: delete or implement abstract method protected Map> sources; @@ -52,10 +50,11 @@ public abstract class PathTraverser { protected Set paths; protected TraverseStrategy traverseStrategy; + protected HugeTraverser.EdgeRecord edgeRecord; public PathTraverser(HugeTraverser traverser, TraverseStrategy strategy, Collection sources, Collection targets, - long capacity, long limit) { + long capacity, long limit, boolean concurrent) { this.traverser = traverser; this.traverseStrategy = strategy; @@ -79,6 +78,8 @@ public PathTraverser(HugeTraverser traverser, TraverseStrategy strategy, this.targetsAll.putAll(this.targets); this.paths = this.newPathSet(); + + this.edgeRecord = new HugeTraverser.EdgeRecord(concurrent); } public void forward() { @@ -145,9 +146,13 @@ private void traverseOne(Id v, EdgeStep step, boolean forward) { while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + this.traverser.edgeIterCounter.addAndGet(1L); + + this.edgeRecord.addEdge(v, target, edge); this.processOne(v, target, forward); } + this.traverser.vertexIterCounter.addAndGet(1L); } private void processOne(Id source, Id target, boolean forward) { @@ -205,10 +210,7 @@ protected boolean finished() { protected boolean reachLimit() { HugeTraverser.checkCapacity(this.capacity, this.accessedNodes(), "template paths"); - if (this.limit == NO_LIMIT || this.pathCount() < this.limit) { - return false; - } - return true; + return this.limit != NO_LIMIT && this.pathCount() >= this.limit; } protected int accessedNodes() { diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathsTraverser.java index bdc9712c53..d8b256082d 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathsTraverser.java @@ -21,13 +21,12 @@ import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.traversal.algorithm.records.PathsRecords; -import org.apache.hugegraph.type.define.Directions; -import org.apache.tinkerpop.gremlin.structure.Edge; - import org.apache.hugegraph.perf.PerfUtil.Watched; import org.apache.hugegraph.structure.HugeEdge; +import org.apache.hugegraph.traversal.algorithm.records.PathsRecords; +import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; public class PathsTraverser extends HugeTraverser { @@ -75,6 +74,8 @@ public PathSet paths(Id sourceV, Directions sourceDir, } traverser.backward(sourceV, targetDir); } + vertexIterCounter.addAndGet(traverser.vertexCounter); + edgeIterCounter.addAndGet(traverser.edgeCounter); return traverser.paths(); } @@ -88,6 +89,8 @@ private class Traverser { private final long limit; private final PathSet paths; + private long vertexCounter; + private long edgeCounter; public Traverser(Id sourceV, Id targetV, Id label, long degree, long capacity, long limit) { @@ -96,6 +99,8 @@ public Traverser(Id sourceV, Id targetV, Id label, this.degree = degree; this.capacity = capacity; this.limit = limit; + this.vertexCounter = 0L; + this.edgeCounter = 0L; this.paths = new PathSet(); } @@ -115,10 +120,11 @@ public void forward(Id targetV, Directions direction) { } edges = edgesOfVertex(vid, direction, this.label, this.degree); - + this.vertexCounter += 1L; while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + this.edgeCounter += 1L; PathSet results = this.record.findPath(target, null, true, false); @@ -148,10 +154,11 @@ public void backward(Id sourceV, Directions direction) { } edges = edgesOfVertex(vid, direction, this.label, this.degree); - + this.vertexCounter += 1L; while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + this.edgeCounter += 1L; PathSet results = this.record.findPath(target, null, true, false); @@ -175,5 +182,9 @@ private boolean reachLimit() { checkCapacity(this.capacity, this.record.accessed(), "paths"); return this.limit != NO_LIMIT && this.paths.size() >= this.limit; } + + public long accessed() { + return this.record.accessed(); + } } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java index a551eb7cc2..47fe883544 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java @@ -17,15 +17,17 @@ package org.apache.hugegraph.traversal.algorithm; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.type.define.Directions; -import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; - import org.apache.hugegraph.util.CollectionUtil; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; public class SameNeighborTraverser extends HugeTraverser { @@ -46,15 +48,60 @@ public Set sameNeighbors(Id vertex, Id other, Directions direction, Id labelId = this.getEdgeLabelId(label); Set sourceNeighbors = IteratorUtils.set(this.adjacentVertices( - vertex, direction, labelId, degree)); + vertex, direction, labelId, degree)); Set targetNeighbors = IteratorUtils.set(this.adjacentVertices( - other, direction, labelId, degree)); + other, direction, labelId, degree)); Set sameNeighbors = (Set) CollectionUtil.intersect( - sourceNeighbors, targetNeighbors); + sourceNeighbors, targetNeighbors); + + this.vertexIterCounter.addAndGet(2L); + this.edgeIterCounter.addAndGet(sourceNeighbors.size()); + this.edgeIterCounter.addAndGet(targetNeighbors.size()); + if (limit != NO_LIMIT) { int end = Math.min(sameNeighbors.size(), limit); sameNeighbors = CollectionUtil.subSet(sameNeighbors, 0, end); } return sameNeighbors; } + + public Set sameNeighbors(List vertexIds, Directions direction, + List labels, long degree, long limit) { + E.checkNotNull(vertexIds, "vertex ids"); + E.checkArgument(vertexIds.size() >= 2, "vertex_list size can't " + + "be less than 2"); + for (Id id : vertexIds) { + this.checkVertexExist(id, "vertex"); + } + E.checkNotNull(direction, "direction"); + checkDegree(degree); + checkLimit(limit); + + List labelsId = new ArrayList<>(); + if (labels != null) { + for (String label : labels) { + labelsId.add(this.getEdgeLabelId(label)); + } + } + + Set sameNeighbors = new HashSet<>(); + for (int i = 0; i < vertexIds.size(); i++) { + Set vertexNeighbors = IteratorUtils.set(this.adjacentVertices( + vertexIds.get(i), direction, labelsId, degree)); + if (i == 0) { + sameNeighbors = vertexNeighbors; + } else { + sameNeighbors = (Set) CollectionUtil.intersect( + sameNeighbors, vertexNeighbors); + } + this.vertexIterCounter.addAndGet(1L); + this.edgeIterCounter.addAndGet(vertexNeighbors.size()); + } + + if (limit != NO_LIMIT) { + int end = Math.min(sameNeighbors.size(), (int) limit); + sameNeighbors = CollectionUtil.subSet(sameNeighbors, 0, end); + } + return sameNeighbors; + } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java index e9584191f0..1783ab21fd 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java @@ -20,18 +20,19 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.perf.PerfUtil.Watched; +import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.traversal.algorithm.records.ShortestPathRecords; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.type.define.Directions; +import org.apache.hugegraph.util.E; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import org.apache.hugegraph.perf.PerfUtil.Watched; -import org.apache.hugegraph.structure.HugeEdge; -import org.apache.hugegraph.util.E; import com.google.common.collect.ImmutableList; public class ShortestPathTraverser extends HugeTraverser { @@ -81,7 +82,15 @@ public Path shortestPath(Id sourceV, Id targetV, Directions dir, checkCapacity(traverser.capacity, traverser.accessed(), "shortest path"); } - return paths.isEmpty() ? Path.EMPTY : paths.iterator().next(); + + this.vertexIterCounter.addAndGet(traverser.vertexCount); + this.edgeIterCounter.addAndGet(traverser.record.accessed()); + + Path path = paths.isEmpty() ? Path.EMPTY : paths.iterator().next(); + + Set edges = traverser.edgeRecord.getEdges(path); + path.setEdges(edges); + return path; } public Path shortestPath(Id sourceV, Id targetV, EdgeStep step, @@ -126,27 +135,36 @@ public PathSet allShortestPaths(Id sourceV, Id targetV, Directions dir, checkCapacity(traverser.capacity, traverser.accessed(), "shortest path"); } + + this.vertexIterCounter.addAndGet(traverser.vertexCount); + this.edgeIterCounter.addAndGet(traverser.record.accessed()); + + paths.setEdges(traverser.edgeRecord.getEdges(paths)); return paths; } private class Traverser { private final ShortestPathRecords record; + private final EdgeRecord edgeRecord; private final Directions direction; private final Map labels; private final long degree; private final long skipDegree; private final long capacity; + private long vertexCount; public Traverser(Id sourceV, Id targetV, Directions dir, Map labels, long degree, long skipDegree, long capacity) { this.record = new ShortestPathRecords(sourceV, targetV); + this.edgeRecord = new EdgeRecord(false); this.direction = dir; this.labels = labels; this.degree = degree; this.skipDegree = skipDegree; this.capacity = capacity; + this.vertexCount = 0L; } public PathSet traverse(boolean all) { @@ -170,13 +188,18 @@ public PathSet forward(boolean all) { this.labels, degree); edges = skipSuperNodeIfNeeded(edges, this.degree, this.skipDegree); + + this.vertexCount += 1L; + while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + this.edgeRecord.addEdge(source, target, edge); + PathSet paths = this.record.findPath(target, - t -> !this.superNode(t, this.direction), - all, false); + t -> !this.superNode(t, this.direction), + all, false); if (paths.isEmpty()) { continue; @@ -186,6 +209,7 @@ public PathSet forward(boolean all) { return paths; } } + } this.record.finishOneLayer(); @@ -210,13 +234,18 @@ public PathSet backward(boolean all) { this.labels, degree); edges = skipSuperNodeIfNeeded(edges, this.degree, this.skipDegree); + + this.vertexCount += 1L; + while (edges.hasNext()) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + this.edgeRecord.addEdge(source, target, edge); + PathSet paths = this.record.findPath(target, - t -> !this.superNode(t, opposite), - all, false); + t -> !this.superNode(t, opposite), + all, false); if (paths.isEmpty()) { continue; diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SingleSourceShortestPathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SingleSourceShortestPathTraverser.java index 0929711402..12d90600ec 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SingleSourceShortestPathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SingleSourceShortestPathTraverser.java @@ -17,6 +17,9 @@ package org.apache.hugegraph.traversal.algorithm; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -26,14 +29,14 @@ import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.backend.query.QueryResults; -import org.apache.hugegraph.type.define.Directions; -import org.apache.tinkerpop.gremlin.structure.Edge; - import org.apache.hugegraph.structure.HugeEdge; +import org.apache.hugegraph.type.define.Directions; import org.apache.hugegraph.util.CollectionUtil; import org.apache.hugegraph.util.E; import org.apache.hugegraph.util.InsertionOrderUtil; import org.apache.hugegraph.util.NumericUtil; +import org.apache.tinkerpop.gremlin.structure.Edge; + import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -57,13 +60,21 @@ public WeightedPaths singleSourceShortestPaths(Id sourceV, Directions dir, Id labelId = this.getEdgeLabelId(label); Traverser traverser = new Traverser(sourceV, dir, labelId, weight, - degree, skipDegree, capacity, - limit); + degree, skipDegree, capacity, limit); while (true) { // Found, reach max depth or reach capacity, stop searching traverser.forward(); if (traverser.done()) { - return traverser.shortestPaths(); + this.vertexIterCounter.addAndGet(traverser.vertexCount); + this.edgeIterCounter.addAndGet(traverser.edgeCount); + WeightedPaths paths = traverser.shortestPaths(); + List> pathList = paths.pathList(); + Set edges = new HashSet<>(); + for (List path : pathList) { + edges.addAll(traverser.edgeRecord.getEdges(path.iterator())); + } + paths.setEdges(edges); + return paths; } checkCapacity(traverser.capacity, traverser.size, "shortest path"); } @@ -91,18 +102,107 @@ public NodeWithWeight weightedShortestPath(Id sourceV, Id targetV, traverser.forward(); Map results = traverser.shortestPaths(); if (results.containsKey(targetV) || traverser.done()) { - return results.get(targetV); + this.vertexIterCounter.addAndGet(traverser.vertexCount); + this.edgeIterCounter.addAndGet(traverser.edgeCount); + NodeWithWeight nodeWithWeight = results.get(targetV); + if (nodeWithWeight != null) { + Iterator vertexIter = nodeWithWeight.node.path().iterator(); + Set edges = traverser.edgeRecord.getEdges(vertexIter); + nodeWithWeight.setEdges(edges); + } + return nodeWithWeight; } checkCapacity(traverser.capacity, traverser.size, "shortest path"); } } + public static class NodeWithWeight implements Comparable { + + private final double weight; + private final Node node; + + private Set edges = Collections.emptySet(); + + public NodeWithWeight(double weight, Node node) { + this.weight = weight; + this.node = node; + } + + public NodeWithWeight(double weight, Id id, NodeWithWeight prio) { + this(weight, new Node(id, prio.node())); + } + + public Set getEdges() { + return edges; + } + + public void setEdges(Set edges) { + this.edges = edges; + } + + public double weight() { + return weight; + } + + public Node node() { + return this.node; + } + + public Map toMap() { + return ImmutableMap.of("weight", this.weight, + "vertices", this.node().path()); + } + + @Override + public int compareTo(NodeWithWeight other) { + return Double.compare(this.weight, other.weight); + } + } + + public static class WeightedPaths extends LinkedHashMap { + + private static final long serialVersionUID = -313873642177730993L; + private Set edges = Collections.emptySet(); + + public Set getEdges() { + return edges; + } + + public void setEdges(Set edges) { + this.edges = edges; + } + + public Set vertices() { + Set vertices = newIdSet(); + vertices.addAll(this.keySet()); + for (NodeWithWeight nw : this.values()) { + vertices.addAll(nw.node().path()); + } + return vertices; + } + + public List> pathList() { + List> pathList = new ArrayList<>(); + for (NodeWithWeight nw : this.values()) { + pathList.add(nw.node.path()); + } + return pathList; + } + + public Map> toMap() { + Map> results = newMap(); + for (Map.Entry entry : this.entrySet()) { + Id source = entry.getKey(); + NodeWithWeight nw = entry.getValue(); + Map result = nw.toMap(); + results.put(source, result); + } + return results; + } + } + private class Traverser { - private WeightedPaths findingNodes = new WeightedPaths(); - private WeightedPaths foundNodes = new WeightedPaths(); - private Set sources; - private Id source; private final Directions direction; private final Id label; private final String weight; @@ -110,15 +210,21 @@ private class Traverser { private final long skipDegree; private final long capacity; private final long limit; - private long size; + private final WeightedPaths findingNodes = new WeightedPaths(); + private final WeightedPaths foundNodes = new WeightedPaths(); + private final EdgeRecord edgeRecord; + private final Id source; + private final long size; + private Set sources; + private long vertexCount; + private long edgeCount; private boolean done = false; public Traverser(Id sourceV, Directions dir, Id label, String weight, - long degree, long skipDegree, long capacity, - long limit) { + long degree, long skipDegree, long capacity, long limit) { this.source = sourceV; this.sources = ImmutableSet.of(new NodeWithWeight( - 0D, new Node(sourceV, null))); + 0D, new Node(sourceV, null))); this.direction = dir; this.label = label; this.weight = weight; @@ -127,6 +233,9 @@ public Traverser(Id sourceV, Directions dir, Id label, String weight, this.capacity = capacity; this.limit = limit; this.size = 0L; + this.vertexCount = 0L; + this.edgeCount = 0L; + this.edgeRecord = new EdgeRecord(false); } /** @@ -143,12 +252,16 @@ public void forward() { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); + this.edgeCount += 1L; + if (this.foundNodes.containsKey(target) || this.source.equals(target)) { // Already find shortest path for target, skip continue; } + this.edgeRecord.addEdge(node.node().id(), target, edge); + double currentWeight = this.edgeWeight(edge); double weight = currentWeight + node.weight(); NodeWithWeight nw = new NodeWithWeight(weight, target, node); @@ -164,9 +277,10 @@ public void forward() { } } } + this.vertexCount += sources.size(); Map sorted = CollectionUtil.sortByValue( - this.findingNodes, true); + this.findingNodes, true); double minWeight = 0; Set newSources = InsertionOrderUtil.newSet(); for (Map.Entry entry : sorted.entrySet()) { @@ -209,7 +323,7 @@ private double edgeWeight(HugeEdge edge) { edgeWeight = 1.0; } else { edgeWeight = NumericUtil.convertToNumber( - edge.value(this.weight)).doubleValue(); + edge.value(this.weight)).doubleValue(); } return edgeWeight; } @@ -232,62 +346,4 @@ private Iterator skipSuperNodeIfNeeded(Iterator edges) { return edgeList.iterator(); } } - - public static class NodeWithWeight implements Comparable { - - private final double weight; - private final Node node; - - public NodeWithWeight(double weight, Node node) { - this.weight = weight; - this.node = node; - } - - public NodeWithWeight(double weight, Id id, NodeWithWeight prio) { - this(weight, new Node(id, prio.node())); - } - - public double weight() { - return weight; - } - - public Node node() { - return this.node; - } - - public Map toMap() { - return ImmutableMap.of("weight", this.weight, - "vertices", this.node().path()); - } - - @Override - public int compareTo(NodeWithWeight other) { - return Double.compare(this.weight, other.weight); - } - } - - public static class WeightedPaths extends LinkedHashMap { - - private static final long serialVersionUID = -313873642177730993L; - - public Set vertices() { - Set vertices = newIdSet(); - vertices.addAll(this.keySet()); - for (NodeWithWeight nw : this.values()) { - vertices.addAll(nw.node().path()); - } - return vertices; - } - - public Map> toMap() { - Map> results = newMap(); - for (Map.Entry entry : this.entrySet()) { - Id source = entry.getKey(); - NodeWithWeight nw = entry.getValue(); - Map result = nw.toMap(); - results.put(source, result); - } - return results; - } - } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SubGraphTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SubGraphTraverser.java index b1e2405c28..25e03996eb 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SubGraphTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SubGraphTraverser.java @@ -22,16 +22,15 @@ import java.util.Map; import java.util.Set; -import jakarta.ws.rs.core.MultivaluedMap; - import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeEdge; import org.apache.hugegraph.type.define.Directions; +import org.apache.hugegraph.util.E; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import org.apache.hugegraph.structure.HugeEdge; -import org.apache.hugegraph.util.E; +import jakarta.ws.rs.core.MultivaluedMap; public class SubGraphTraverser extends HugeTraverser { @@ -39,17 +38,35 @@ public SubGraphTraverser(HugeGraph graph) { super(graph); } - public PathSet 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, false); + private static boolean hasMultiEdges(List edges, Id target) { + boolean hasOutEdge = false; + boolean hasInEdge = false; + for (Edge edge : edges) { + if (((HugeEdge) edge).id().otherVertexId().equals(target)) { + if (((HugeEdge) edge).direction() == Directions.OUT) { + hasOutEdge = true; + } else { + hasInEdge = true; + } + if (hasOutEdge && hasInEdge) { + return true; + } + } + } + return false; + } + + public PathSet 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, false); } public PathSet 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, sourceInRing); + return this.subGraphPaths(sourceV, dir, label, depth, degree, capacity, + limit, true, sourceInRing); } private PathSet subGraphPaths(Id sourceV, Directions dir, String label, @@ -69,48 +86,79 @@ private PathSet subGraphPaths(Id sourceV, Directions dir, String label, capacity, limit, rings, sourceInRing); PathSet paths = new PathSet(); - while (true) { + do { paths.addAll(traverser.forward(dir)); - if (--depth <= 0 || traverser.reachLimit() || - traverser.finished()) { - break; - } - } + } while (--depth > 0 && !traverser.reachLimit() && + !traverser.finished()); + this.vertexIterCounter.addAndGet(traverser.accessedVertices.size()); + this.edgeIterCounter.addAndGet(traverser.edgeCount); + paths.setEdges(traverser.edgeRecord.getEdges(paths)); return paths; } - private static boolean hasMultiEdges(List edges, Id target) { - boolean hasOutEdge = false; - boolean hasInEdge = false; - for (Edge edge : edges) { - if (((HugeEdge) edge).id().otherVertexId().equals(target)) { - if (((HugeEdge) edge).direction() == Directions.OUT) { - hasOutEdge = true; - } else { - hasInEdge = true; - } - if (hasOutEdge && hasInEdge) { - return true; + private static class RingPath extends Path { + + public RingPath(Id crosspoint, List vertices) { + super(crosspoint, vertices); + } + + @Override + public int hashCode() { + int hashCode = 0; + for (Id id : this.vertices()) { + hashCode ^= id.hashCode(); + } + return hashCode; + } + + /** + * Compares the specified object with this path for equality. + * Returns true if other path is equal to or + * reversed of this path. + * + * @param other the object to be compared + * @return true if the specified object is equal to or + * reversed of this path + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof RingPath)) { + return false; + } + List vertices = this.vertices(); + List otherVertices = ((Path) other).vertices(); + + if (vertices.equals(otherVertices)) { + return true; + } + if (vertices.size() != otherVertices.size()) { + return false; + } + for (int i = 0, size = vertices.size(); i < size; i++) { + int j = size - i - 1; + if (!vertices.get(i).equals(otherVertices.get(j))) { + return false; } } + return true; } - return false; } private class Traverser { private final Id source; - private MultivaluedMap sources = newMultivalueMap(); - private Set accessedVertices = newIdSet(); - 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 final Set accessedVertices = newIdSet(); + private final EdgeRecord edgeRecord; + private MultivaluedMap sources = newMultivalueMap(); + private int depth; private long pathCount; + private long edgeCount; public Traverser(Id sourceV, Id label, int depth, long degree, long capacity, long limit, boolean rings, @@ -126,6 +174,8 @@ public Traverser(Id sourceV, Id label, int depth, long degree, this.rings = rings; this.sourceInRing = sourceInRing; this.pathCount = 0L; + this.edgeCount = 0L; + this.edgeRecord = new EdgeRecord(false); } /** @@ -140,7 +190,7 @@ public PathSet forward(Directions direction) { Id vid = entry.getKey(); // Record edgeList to determine if multiple edges exist List edgeList = IteratorUtils.list(edgesOfVertex( - vid, direction, this.label, this.degree)); + vid, direction, this.label, this.degree)); edges = edgeList.iterator(); if (!edges.hasNext()) { @@ -163,7 +213,11 @@ public PathSet forward(Directions direction) { while (edges.hasNext()) { neighborCount++; HugeEdge edge = (HugeEdge) edges.next(); + this.edgeCount += 1L; Id target = edge.id().otherVertexId(); + + this.edgeRecord.addEdge(vid, target, edge); + // Avoid deduplicate path if (currentNeighbors.contains(target)) { continue; @@ -241,62 +295,11 @@ public PathSet forward(Directions direction) { private boolean reachLimit() { checkCapacity(this.capacity, this.accessedVertices.size(), this.rings ? "rings" : "rays"); - if (this.limit == NO_LIMIT || this.pathCount < this.limit) { - return false; - } - return true; + return this.limit != NO_LIMIT && this.pathCount >= this.limit; } private boolean finished() { return this.sources.isEmpty(); } } - - private static class RingPath extends Path { - - public RingPath(Id crosspoint, List vertices) { - super(crosspoint, vertices); - } - - @Override - public int hashCode() { - int hashCode = 0; - for (Id id : this.vertices()) { - hashCode ^= id.hashCode(); - } - return hashCode; - } - - /** - * Compares the specified object with this path for equality. - * Returns true if other path is equal to or - * reversed of this path. - * @param other the object to be compared - * @return true if the specified object is equal to or - * reversed of this path - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof RingPath)) { - return false; - } - List vertices = this.vertices(); - List otherVertices = ((Path) other).vertices(); - - if (vertices.equals(otherVertices)) { - return true; - } - if (vertices.size() != otherVertices.size()) { - return false; - } - assert vertices.size() == otherVertices.size(); - for (int i = 0, size = vertices.size(); i < size; i++) { - int j = size - i - 1; - if (!vertices.get(i).equals(otherVertices.get(j))) { - return false; - } - } - return true; - } - } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java index 85ce74651d..d5b3c63c5c 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java @@ -18,6 +18,7 @@ package org.apache.hugegraph.traversal.algorithm; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -25,13 +26,13 @@ import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.backend.id.Id; +import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.traversal.algorithm.steps.RepeatEdgeStep; import org.apache.hugegraph.traversal.algorithm.strategy.TraverseStrategy; -import org.apache.tinkerpop.gremlin.structure.Vertex; - -import org.apache.hugegraph.structure.HugeVertex; import org.apache.hugegraph.util.E; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; public class TemplatePathsTraverser extends HugeTraverser { @@ -39,11 +40,11 @@ public TemplatePathsTraverser(HugeGraph graph) { super(graph); } - public Set templatePaths(Iterator sources, - Iterator targets, - List steps, - boolean withRing, - long capacity, long limit) { + public WrappedPathSet templatePaths(Iterator sources, + Iterator targets, + List steps, + boolean withRing, long capacity, + long limit) { checkCapacity(capacity); checkLimit(limit); @@ -68,23 +69,26 @@ public Set templatePaths(Iterator sources, for (RepeatEdgeStep step : steps) { totalSteps += step.maxTimes(); } + + boolean concurrent = totalSteps >= this.concurrentDepth(); TraverseStrategy strategy = TraverseStrategy.create( - totalSteps >= this.concurrentDepth(), - this.graph()); + concurrent, this.graph()); Traverser traverser = new Traverser(this, strategy, sourceList, targetList, steps, - withRing, capacity, limit); + withRing, capacity, limit, concurrent); do { // Forward traverser.forward(); if (traverser.finished()) { - return traverser.paths(); + Set paths = traverser.paths(); + return new WrappedPathSet(paths, traverser.edgeRecord.getEdges(paths)); } // Backward traverser.backward(); if (traverser.finished()) { - return traverser.paths(); + Set paths = traverser.paths(); + return new WrappedPathSet(paths, traverser.edgeRecord.getEdges(paths)); } } while (true); } @@ -98,14 +102,14 @@ private static class Traverser extends PathTraverser { protected int sourceIndex; protected int targetIndex; - protected boolean sourceFinishOneStep = false; - protected boolean targetFinishOneStep = false; + protected boolean sourceFinishOneStep; + protected boolean targetFinishOneStep; public Traverser(HugeTraverser traverser, TraverseStrategy strategy, Collection sources, Collection targets, List steps, boolean withRing, - long capacity, long limit) { - super(traverser, strategy, sources, targets, capacity, limit); + long capacity, long limit, boolean concurrent) { + super(traverser, strategy, sources, targets, capacity, limit, concurrent); this.steps = steps; this.withRing = withRing; @@ -135,7 +139,7 @@ public void beforeTraverse(boolean forward) { public void afterTraverse(EdgeStep step, boolean forward) { Map> all = forward ? this.sourcesAll : - this.targetsAll; + this.targetsAll; this.addNewVerticesToAll(all); this.reInitCurrentStepIfNeeded(step, forward); this.stepCount++; @@ -276,4 +280,26 @@ public boolean lastSuperStep() { this.targetIndex == this.sourceIndex + 1; } } + + public static class WrappedPathSet { + private final Set paths; + private Set edges = Collections.emptySet(); + + public WrappedPathSet(Set paths) { + this.paths = paths; + } + + public WrappedPathSet(Set paths, Set edges) { + this.paths = paths; + this.edges = edges; + } + + public Set getPaths() { + return paths; + } + + public Set getEdges() { + return edges; + } + } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java index 4e53ecc16b..31de69c2ec 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java @@ -25,17 +25,18 @@ import org.apache.hugegraph.HugeException; import org.apache.hugegraph.backend.id.Id; -import org.apache.hugegraph.type.define.CollectionType; -import org.apache.hugegraph.util.collection.CollectionFactory; -import org.apache.hugegraph.util.collection.IntIterator; -import org.apache.hugegraph.util.collection.IntMap; -import org.apache.hugegraph.util.collection.IntSet; import org.apache.hugegraph.perf.PerfUtil.Watched; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser; import org.apache.hugegraph.traversal.algorithm.HugeTraverser.Path; import org.apache.hugegraph.traversal.algorithm.HugeTraverser.PathSet; import org.apache.hugegraph.traversal.algorithm.records.record.Int2IntRecord; import org.apache.hugegraph.traversal.algorithm.records.record.Record; import org.apache.hugegraph.traversal.algorithm.records.record.RecordType; +import org.apache.hugegraph.type.define.CollectionType; +import org.apache.hugegraph.util.collection.CollectionFactory; +import org.apache.hugegraph.util.collection.IntIterator; +import org.apache.hugegraph.util.collection.IntMap; +import org.apache.hugegraph.util.collection.IntSet; public abstract class SingleWayMultiPathsRecords extends AbstractRecords { @@ -44,7 +45,7 @@ public abstract class SingleWayMultiPathsRecords extends AbstractRecords { private final int sourceCode; private final boolean nearest; private final IntSet accessedVertices; - + private final HugeTraverser.EdgeRecord edgeRecord; private IntIterator parentRecordKeys; public SingleWayMultiPathsRecords(RecordType type, boolean concurrent, @@ -58,6 +59,7 @@ public SingleWayMultiPathsRecords(RecordType type, boolean concurrent, firstRecord.addPath(this.sourceCode, 0); this.records = new Stack<>(); this.records.push(firstRecord); + this.edgeRecord = new HugeTraverser.EdgeRecord(concurrent); this.accessedVertices = CollectionFactory.newIntSet(); } @@ -176,6 +178,10 @@ protected final Stack records() { return this.records; } + public HugeTraverser.EdgeRecord getEdgeIdRecord() { + return edgeRecord; + } + public abstract int size(); public abstract List ids(long limit); From c6ab9f4c2f530426c51cd65801b04849557385c6 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:30:33 +0800 Subject: [PATCH 06/16] fix: numeric cast --- .../org/apache/hugegraph/api/traversers/SameNeighborsAPI.java | 2 +- .../hugegraph/traversal/algorithm/SameNeighborTraverser.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java index 7553295c78..a7b1a87cc6 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java @@ -142,7 +142,7 @@ private static class Request { @JsonProperty("max_degree") public long maxDegree = Long.parseLong(DEFAULT_MAX_DEGREE); @JsonProperty("limit") - public long limit = Long.parseLong(DEFAULT_ELEMENTS_LIMIT); + public int limit = Integer.parseInt(DEFAULT_ELEMENTS_LIMIT); @JsonProperty("vertex_list") private List vertexList; @JsonProperty("direction") diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java index 47fe883544..06c5bec275 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/SameNeighborTraverser.java @@ -66,7 +66,7 @@ public Set sameNeighbors(Id vertex, Id other, Directions direction, } public Set sameNeighbors(List vertexIds, Directions direction, - List labels, long degree, long limit) { + List labels, long degree, int limit) { E.checkNotNull(vertexIds, "vertex ids"); E.checkArgument(vertexIds.size() >= 2, "vertex_list size can't " + "be less than 2"); @@ -99,7 +99,7 @@ public Set sameNeighbors(List vertexIds, Directions direction, } if (limit != NO_LIMIT) { - int end = Math.min(sameNeighbors.size(), (int) limit); + int end = Math.min(sameNeighbors.size(), limit); sameNeighbors = CollectionUtil.subSet(sameNeighbors, 0, end); } return sameNeighbors; From c7825a60d7007cb077293ec8ef8c259d03b3c4f3 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 28 Jul 2023 16:24:11 +0800 Subject: [PATCH 07/16] fix: Jaccard Similarity api test --- .../api/traversers/JaccardSimilarityApiTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hugegraph-test/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityApiTest.java b/hugegraph-test/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityApiTest.java index 1ce5f6d705..6fba538d54 100644 --- a/hugegraph-test/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityApiTest.java +++ b/hugegraph-test/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityApiTest.java @@ -19,14 +19,15 @@ import java.util.Map; -import jakarta.ws.rs.core.Response; +import org.apache.hugegraph.api.BaseApiTest; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.apache.hugegraph.api.BaseApiTest; import com.google.common.collect.ImmutableMap; +import jakarta.ws.rs.core.Response; + public class JaccardSimilarityApiTest extends BaseApiTest { static final String PATH = TRAVERSERS_API + "/jaccardsimilarity"; @@ -72,9 +73,10 @@ public void testPost() { "\"top\": 3}", markoId); Response r = client().post(PATH, reqBody); String content = assertResponseStatus(200, r); - Double rippleJaccardSimilarity = assertJsonContains(content, rippleId); - Double peterJaccardSimilarity = assertJsonContains(content, peterId); - Double jsonJaccardSimilarity = assertJsonContains(content, jsonId); + Map jaccardSimilarity = assertJsonContains(content, "jaccard_similarity"); + Double rippleJaccardSimilarity = assertMapContains(jaccardSimilarity, rippleId); + Double peterJaccardSimilarity = assertMapContains(jaccardSimilarity, peterId); + Double jsonJaccardSimilarity = assertMapContains(jaccardSimilarity, jsonId); Assert.assertEquals(0.3333, rippleJaccardSimilarity.doubleValue(), 0.0001); Assert.assertEquals(0.25, peterJaccardSimilarity.doubleValue(), 0.0001); From e67196379ca003fae5845668292a3ae0138a04ad Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:24:54 +0800 Subject: [PATCH 08/16] fix: adjust the code style and naming convention --- .../java/org/apache/hugegraph/api/API.java | 57 +++++++++++-------- .../api/traversers/AllShortestPathsAPI.java | 10 ++-- .../api/traversers/CrosspointsAPI.java | 4 +- .../traversers/CustomizedCrosspointsAPI.java | 11 ++-- .../api/traversers/CustomizedPathsAPI.java | 4 +- .../api/traversers/FusiformSimilarityAPI.java | 4 +- .../api/traversers/JaccardSimilarityAPI.java | 8 +-- .../api/traversers/KneighborAPI.java | 14 ++--- .../hugegraph/api/traversers/KoutAPI.java | 12 ++-- .../traversers/MultiNodeShortestPathAPI.java | 10 ++-- .../hugegraph/api/traversers/PathsAPI.java | 12 ++-- .../hugegraph/api/traversers/RaysAPI.java | 6 +- .../hugegraph/api/traversers/RingsAPI.java | 4 +- .../api/traversers/SameNeighborsAPI.java | 8 +-- .../api/traversers/ShortestPathAPI.java | 4 +- .../SingleSourceShortestPathAPI.java | 4 +- .../api/traversers/TemplatePathsAPI.java | 8 +-- .../traversers/WeightedShortestPathAPI.java | 6 +- .../algorithm/CollectionPathsTraverser.java | 12 ++-- .../MultiNodeShortestPathTraverser.java | 5 +- .../algorithm/TemplatePathsTraverser.java | 12 ++-- 21 files changed, 107 insertions(+), 108 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java index 5f8b6e1682..226f908034 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java @@ -18,18 +18,18 @@ package org.apache.hugegraph.api; import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.function.Consumer; +import org.apache.commons.lang.mutable.MutableLong; import org.apache.hugegraph.HugeException; import org.apache.hugegraph.HugeGraph; import org.apache.hugegraph.core.GraphManager; import org.apache.hugegraph.define.Checkable; import org.apache.hugegraph.metrics.MetricsUtil; import org.apache.hugegraph.util.E; +import org.apache.hugegraph.util.InsertionOrderUtil; import org.apache.hugegraph.util.JsonUtil; import org.apache.hugegraph.util.Log; import org.slf4j.Logger; @@ -71,8 +71,7 @@ public class API { public static HugeGraph graph(GraphManager manager, String graph) { HugeGraph g = manager.graph(graph); if (g == null) { - throw new NotFoundException(String.format( - "Graph '%s' does not exist", graph)); + throw new NotFoundException(String.format("Graph '%s' does not exist", graph)); } return g; } @@ -142,8 +141,7 @@ protected static void checkUpdatingBody(Checkable body) { body.checkUpdate(); } - protected static void checkCreatingBody( - Collection bodies) { + protected static void checkCreatingBody(Collection bodies) { E.checkArgumentNotNull(bodies, "The request body can't be empty"); for (Checkable body : bodies) { E.checkArgument(body != null, @@ -152,8 +150,7 @@ protected static void checkCreatingBody( } } - protected static void checkUpdatingBody( - Collection bodies) { + protected static void checkUpdatingBody(Collection bodies) { E.checkArgumentNotNull(bodies, "The request body can't be empty"); for (Checkable body : bodies) { E.checkArgumentNotNull(body, @@ -188,41 +185,51 @@ public static boolean checkAndParseAction(String action) { } else if (action.equals(ACTION_ELIMINATE)) { return false; } else { - throw new NotSupportedException( - String.format("Not support action '%s'", action)); + throw new NotSupportedException(String.format("Not support action '%s'", action)); } } - public static class ApiMeasure { - public static final String EDGE_ITER = "edge_iters"; - public static final String VERTICE_ITER = "vertice_iters"; + public static class ApiMeasurer { + + public static final String EDGE_ITER = "edge_iterations"; + public static final String VERTICE_ITER = "vertice_iterations"; public static final String COST = "cost"; - protected long timeStart = System.currentTimeMillis(); - protected HashMap mapResult = new LinkedHashMap<>(); + private final long timeStart; + private final Map measures; + + public ApiMeasurer() { + this.timeStart = System.currentTimeMillis(); + this.measures = InsertionOrderUtil.newMap(); + } - public Map getResult() { - mapResult.put(COST, System.currentTimeMillis() - timeStart); - return mapResult; + public Map measures() { + measures.put(COST, System.currentTimeMillis() - timeStart); + return measures; } public void put(String key, String value) { - this.mapResult.put(key, value); + this.measures.put(key, value); } public void put(String key, long value) { - this.mapResult.put(key, value); + this.measures.put(key, value); } public void put(String key, int value) { - this.mapResult.put(key, value); + this.measures.put(key, value); } protected void addCount(String key, long value) { - long cur = 0; - if (this.mapResult.containsKey(key)) { - cur = (long) this.mapResult.get(key); + Object current = measures.get(key); + if (current == null) { + measures.put(key, new MutableLong(value)); + } else if (current instanceof MutableLong) { + MutableLong currentMutableLong = (MutableLong) current; + currentMutableLong.add(value); + } else if (current instanceof Long) { + Long currentLong = (Long) current; + measures.put(key, new MutableLong(currentLong + value)); } - this.mapResult.put(key, cur + value); } public void addIterCount(long verticeIters, long edgeIters) { diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java index a6b003ddab..387e7531be 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java @@ -85,7 +85,7 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, depth, maxDegree, skipDegree, capacity, withVertex, withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); @@ -96,9 +96,9 @@ public String get(@Context GraphManager manager, ShortestPathTraverser traverser = new ShortestPathTraverser(g); List edgeLabels = edgeLabel == null ? ImmutableList.of() : ImmutableList.of(edgeLabel); - HugeTraverser.PathSet paths = traverser.allShortestPaths( - sourceId, targetId, dir, edgeLabels, - depth, maxDegree, skipDegree, capacity); + HugeTraverser.PathSet paths = traverser.allShortestPaths(sourceId, targetId, dir, + edgeLabels, depth, maxDegree, + skipDegree, capacity); measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); @@ -123,7 +123,7 @@ public String get(@Context GraphManager manager, iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("paths", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java index e501dc3246..eda042511c 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CrosspointsAPI.java @@ -74,7 +74,7 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, depth, maxDegree, capacity, limit); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -87,7 +87,7 @@ public String get(@Context GraphManager manager, limit); measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("crosspoints", paths, true); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java index 36783d3907..ca06c3ed5f 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java @@ -65,11 +65,10 @@ public class CustomizedCrosspointsAPI extends API { private static List pathPatterns( HugeGraph graph, CrosspointsRequest request) { int stepSize = request.pathPatterns.size(); - List pathPatterns; - pathPatterns = new ArrayList<>(stepSize); + List pathPatterns = new ArrayList<>(stepSize); for (PathPattern pattern : request.pathPatterns) { - CustomizedCrosspointsTraverser.PathPattern pathPattern; - pathPattern = new CustomizedCrosspointsTraverser.PathPattern(); + CustomizedCrosspointsTraverser.PathPattern pathPattern = + new CustomizedCrosspointsTraverser.PathPattern(); for (Step step : pattern.steps) { pathPattern.add(step.jsonToStep(graph)); } @@ -100,7 +99,7 @@ public String post(@Context GraphManager manager, graph, request.sources, request.pathPatterns, request.withPath, request.withVertex, request.capacity, request.limit, request.withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -142,7 +141,7 @@ public String post(@Context GraphManager manager, } } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeCrosspoints(paths, iterVertex, iterEdge, request.withPath); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java index 65ef1a960c..e8613c1b17 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java @@ -96,7 +96,7 @@ public String post(@Context GraphManager manager, request.sortBy, request.capacity, request.limit, request.withVertex, request.withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -136,7 +136,7 @@ public String post(@Context GraphManager manager, iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("paths", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java index 37c7276e8c..e22962d840 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java @@ -95,7 +95,7 @@ public String post(@Context GraphManager manager, request.minNeighbors, request.alpha, request.minSimilars, request.groupProperty, request.minGroups); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); E.checkArgument(sources != null && sources.hasNext(), @@ -125,7 +125,7 @@ public String post(@Context GraphManager manager, iterVertex = vertexIds.iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeSimilars(result, iterVertex); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java index 5f13367d39..d5de80351f 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/JaccardSimilarityAPI.java @@ -74,7 +74,7 @@ public String get(@Context GraphManager manager, "with direction {}, edge label {} and max degree '{}'", graph, vertex, other, direction, edgeLabel, maxDegree); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(vertex); Id targetId = VertexAPI.checkAndParseVertexId(other); @@ -90,7 +90,7 @@ public String get(@Context GraphManager manager, traverser.edgeIterCounter.get()); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeMap(ImmutableMap.of("jaccard_similarity", similarity)); } @@ -114,7 +114,7 @@ public String post(@Context GraphManager manager, graph, request.vertex, request.step, request.top, request.capacity); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Id sourceId = HugeVertex.getIdValue(request.vertex); @@ -129,7 +129,7 @@ public String post(@Context GraphManager manager, measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeMap(ImmutableMap.of("jaccard_similarity", results)); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java index ea55ab383e..9981dbe592 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java @@ -89,7 +89,7 @@ public String get(@Context GraphManager manager, graph, sourceV, direction, edgeLabel, depth, maxDegree, limit); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -104,10 +104,10 @@ public String get(@Context GraphManager manager, traverser.edgeIterCounter.get()); } if (countOnly) { - return manager.serializer(g, measure.getResult()).writeMap( - ImmutableMap.of("vertices_size", ids.size())); + return manager.serializer(g, measure.measures()) + .writeMap(ImmutableMap.of("vertices_size", ids.size())); } - return manager.serializer(g, measure.getResult()).writeList("vertices", ids); + return manager.serializer(g, measure.measures()).writeList("vertices", ids); } @POST @@ -134,7 +134,7 @@ public String post(@Context GraphManager manager, request.countOnly, request.withVertex, request.withPath, request.withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Id sourceId = HugeVertex.getIdValue(request.source); @@ -163,7 +163,7 @@ public String post(@Context GraphManager manager, } if (request.countOnly) { - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeNodesWithPath("kneighbor", neighbors, size, paths, QueryResults.emptyIterator(), QueryResults.emptyIterator()); @@ -193,7 +193,7 @@ public String post(@Context GraphManager manager, } } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeNodesWithPath("kneighbor", neighbors, size, paths, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java index 8dd947dae0..9d75fd4a3d 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java @@ -94,7 +94,7 @@ public String get(@Context GraphManager manager, graph, source, direction, edgeLabel, depth, nearest, maxDegree, capacity, limit); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -110,10 +110,10 @@ public String get(@Context GraphManager manager, } if (count_only) { - return manager.serializer(g, measure.getResult()).writeMap(ImmutableMap.of( + return manager.serializer(g, measure.measures()).writeMap(ImmutableMap.of( "vertices_size", ids.size())); } - return manager.serializer(g, measure.getResult()).writeList("vertices", ids); + return manager.serializer(g, measure.measures()).writeList("vertices", ids); } @POST @@ -142,7 +142,7 @@ public String post(@Context GraphManager manager, request.limit, request.withVertex, request.withPath, request.withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Id sourceId = HugeVertex.getIdValue(request.source); @@ -171,7 +171,7 @@ public String post(@Context GraphManager manager, } if (request.countOnly) { - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeNodesWithPath("kneighbor", neighbors, size, paths, QueryResults.emptyIterator(), QueryResults.emptyIterator()); @@ -201,7 +201,7 @@ public String post(@Context GraphManager manager, } } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeNodesWithPath("kout", neighbors, size, paths, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java index ad569e01b0..588940abb7 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/MultiNodeShortestPathAPI.java @@ -74,7 +74,7 @@ public String post(@Context GraphManager manager, graph, request.vertices, request.step, request.maxDepth, request.capacity, request.withVertex); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Iterator vertices = request.vertices.vertices(g); @@ -91,7 +91,7 @@ public String post(@Context GraphManager manager, traverser.edgeIterCounter.get()); } - List paths = wrappedListPath.getPaths(); + List paths = wrappedListPath.paths(); Iterator iterVertex; Set vertexIds = new HashSet<>(); @@ -106,14 +106,14 @@ public String post(@Context GraphManager manager, } Iterator iterEdge; - Set edges = wrappedListPath.getEdges(); + Set edges = wrappedListPath.edges(); if (request.withEdge && !edges.isEmpty()) { - iterEdge = wrappedListPath.getEdges().iterator(); + iterEdge = wrappedListPath.edges().iterator(); } else { iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("paths", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java index 980f829116..8ae3bebe7a 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java @@ -87,7 +87,7 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, depth, maxDegree, capacity, limit); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); @@ -101,7 +101,7 @@ public String get(@Context GraphManager manager, limit); measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("paths", paths, false); } @@ -130,7 +130,7 @@ public String post(@Context GraphManager manager, request.depth, request.capacity, request.limit, request.withVertex, request.withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -143,7 +143,7 @@ public String post(@Context GraphManager manager, step, request.depth, request.nearest, request.capacity, request.limit); - Collection paths = wrappedPathCollection.getPaths(); + Collection paths = wrappedPathCollection.paths(); measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); @@ -160,14 +160,14 @@ public String post(@Context GraphManager manager, } Iterator iterEdge; - Set edges = wrappedPathCollection.getEdges(); + Set edges = wrappedPathCollection.edges(); if (request.withEdge && !edges.isEmpty()) { iterEdge = edges.iterator(); } else { iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("paths", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java index abbccb804a..28ded20e60 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RaysAPI.java @@ -81,7 +81,7 @@ public String get(@Context GraphManager manager, "max degree '{}', capacity '{}' and limit '{}'", graph, sourceV, direction, edgeLabel, depth, maxDegree, capacity, limit); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -114,8 +114,8 @@ public String get(@Context GraphManager manager, } else { iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - - return manager.serializer(g, measure.getResult()) + + return manager.serializer(g, measure.measures()) .writePaths("rays", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java index 764e2f7a91..29e5a867a2 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java @@ -85,7 +85,7 @@ public String get(@Context GraphManager manager, graph, sourceV, direction, edgeLabel, depth, sourceInRing, maxDegree, capacity, limit, withVertex, withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id source = VertexAPI.checkAndParseVertexId(sourceV); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -119,7 +119,7 @@ public String get(@Context GraphManager manager, iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("rings", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java index a7b1a87cc6..fe26165067 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java @@ -79,7 +79,7 @@ public String get(@Context GraphManager manager, "direction {}, edge label {}, max degree '{}' and limit '{}'", graph, vertex, other, direction, edgeLabel, maxDegree, limit); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(vertex); Id targetId = VertexAPI.checkAndParseVertexId(other); @@ -93,7 +93,7 @@ public String get(@Context GraphManager manager, measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeList("same_neighbors", neighbors); } @@ -105,7 +105,7 @@ public String sameNeighbors(@Context GraphManager manager, Request request) { LOG.debug("Graph [{}] get same neighbors among batch, '{}'", graph, request.toString()); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Directions dir = Directions.convert(EdgeAPI.parseDirection(request.direction)); HugeGraph g = graph(manager, graph); @@ -133,7 +133,7 @@ public String sameNeighbors(@Context GraphManager manager, } else { iterVertex = ids.iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeMap(ImmutableMap.of("same_neighbors", neighbors, "vertices", iterVertex)); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java index b74e7eb8ce..c89e83873d 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java @@ -85,7 +85,7 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, depth, maxDegree, skipDegree, capacity, withVertex, withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); @@ -121,7 +121,7 @@ public String get(@Context GraphManager manager, iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeMap(ImmutableMap.of("path", path.vertices(), "vertices", iterVertex, "edges", iterEdge)); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java index 71d195944a..93ea81384c 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java @@ -84,7 +84,7 @@ public String get(@Context GraphManager manager, graph, source, direction, edgeLabel, weight, maxDegree, capacity, limit, withVertex, withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -116,7 +116,7 @@ public String get(@Context GraphManager manager, iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeWeightedPaths(paths, iterVertex, iterEdge); } } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java index 12a6088ade..bded530416 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java @@ -94,7 +94,7 @@ public String post(@Context GraphManager manager, graph, request.sources, request.targets, request.steps, request.capacity, request.limit, request.withVertex, request.withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); HugeGraph g = graph(manager, graph); Iterator sources = request.sources.vertices(g); @@ -109,7 +109,7 @@ public String post(@Context GraphManager manager, measure.addIterCount(traverser.vertexIterCounter.get(), traverser.edgeIterCounter.get()); - Set paths = wrappedPathSet.getPaths(); + Set paths = wrappedPathSet.paths(); Iterator iterVertex; Set vertexIds = new HashSet<>(); @@ -124,14 +124,14 @@ public String post(@Context GraphManager manager, } Iterator iterEdge; - Set edges = wrappedPathSet.getEdges(); + Set edges = wrappedPathSet.edges(); if (request.withEdge && !edges.isEmpty()) { iterEdge = edges.iterator(); } else { iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writePaths("paths", paths, false, iterVertex, iterEdge); } diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java index 9bee43d221..0defd4b90e 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java @@ -85,7 +85,7 @@ public String get(@Context GraphManager manager, graph, source, target, direction, edgeLabel, weight, maxDegree, skipDegree, capacity, withVertex, withEdge); - ApiMeasure measure = new ApiMeasure(); + ApiMeasurer measure = new ApiMeasurer(); Id sourceId = VertexAPI.checkAndParseVertexId(source); Id targetId = VertexAPI.checkAndParseVertexId(target); Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); @@ -103,7 +103,7 @@ public String get(@Context GraphManager manager, traverser.edgeIterCounter.get()); if (node == null) { - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeWeightedPath(null, QueryResults.emptyIterator(), QueryResults.emptyIterator()); @@ -126,7 +126,7 @@ public String get(@Context GraphManager manager, iterEdge = HugeTraverser.EdgeRecord.getEdgeIds(edges).iterator(); } - return manager.serializer(g, measure.getResult()) + return manager.serializer(g, measure.measures()) .writeWeightedPath(node, iterVertex, iterEdge); } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java index 0301037de9..3a4fe68286 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java @@ -18,7 +18,6 @@ package org.apache.hugegraph.traversal.algorithm; import java.util.Collection; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -282,23 +281,20 @@ protected int accessedNodes() { } public static class WrappedPathCollection { - private final Collection paths; - private Set edges = Collections.emptySet(); - public WrappedPathCollection(Collection paths) { - this.paths = paths; - } + private final Collection paths; + private final Set edges; public WrappedPathCollection(Collection paths, Set edges) { this.paths = paths; this.edges = edges; } - public Collection getPaths() { + public Collection paths() { return paths; } - public Set getEdges() { + public Set edges() { return edges; } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java index f579d352e9..aa498fa956 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/MultiNodeShortestPathTraverser.java @@ -132,6 +132,7 @@ public WrappedListPath multiNodeShortestPathSingle(List> pairs, } public static class WrappedListPath { + private final List paths; private final Set edges; @@ -140,11 +141,11 @@ public WrappedListPath(List paths, Set edges) { this.edges = edges; } - public List getPaths() { + public List paths() { return paths; } - public Set getEdges() { + public Set edges() { return edges; } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java index d5b3c63c5c..c89bff2500 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java @@ -18,7 +18,6 @@ package org.apache.hugegraph.traversal.algorithm; import java.util.Collection; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -282,23 +281,20 @@ public boolean lastSuperStep() { } public static class WrappedPathSet { - private final Set paths; - private Set edges = Collections.emptySet(); - public WrappedPathSet(Set paths) { - this.paths = paths; - } + private final Set paths; + private final Set edges; public WrappedPathSet(Set paths, Set edges) { this.paths = paths; this.edges = edges; } - public Set getPaths() { + public Set paths() { return paths; } - public Set getEdges() { + public Set edges() { return edges; } } From 1e33cdac91d75a665ffc6d3bccd6a6b4047baa99 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:48:09 +0800 Subject: [PATCH 09/16] Empty commit From 262ae05fdeea28f70bb7203e50965e224fa106ca Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Mon, 31 Jul 2023 23:27:51 +0800 Subject: [PATCH 10/16] Empty commit From 793ead8e468d3958c2f9aa25ebbc055a54b48f0d Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 11 Aug 2023 15:34:13 +0800 Subject: [PATCH 11/16] fix: 1. change System.currentTimeMillis() to System.nanoTime(); 2. modify addCount() --- .../java/org/apache/hugegraph/api/API.java | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java index 226f908034..a0540d2fe4 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java @@ -44,29 +44,25 @@ public class API { - protected static final Logger LOG = Log.logger(API.class); - public static final String CHARSET = "UTF-8"; - public static final String TEXT_PLAIN = MediaType.TEXT_PLAIN; public static final String APPLICATION_JSON = MediaType.APPLICATION_JSON; public static final String APPLICATION_JSON_WITH_CHARSET = - APPLICATION_JSON + ";charset=" + CHARSET; + APPLICATION_JSON + ";charset=" + CHARSET; public static final String JSON = MediaType.APPLICATION_JSON_TYPE - .getSubtype(); - + .getSubtype(); public static final String ACTION_APPEND = "append"; public static final String ACTION_ELIMINATE = "eliminate"; public static final String ACTION_CLEAR = "clear"; - + protected static final Logger LOG = Log.logger(API.class); private static final Meter SUCCEED_METER = - MetricsUtil.registerMeter(API.class, "commit-succeed"); + MetricsUtil.registerMeter(API.class, "commit-succeed"); private static final Meter ILLEGAL_ARG_ERROR_METER = - MetricsUtil.registerMeter(API.class, "illegal-arg"); + MetricsUtil.registerMeter(API.class, "illegal-arg"); private static final Meter EXPECTED_ERROR_METER = - MetricsUtil.registerMeter(API.class, "expected-error"); + MetricsUtil.registerMeter(API.class, "expected-error"); private static final Meter UNKNOWN_ERROR_METER = - MetricsUtil.registerMeter(API.class, "unknown-error"); + MetricsUtil.registerMeter(API.class, "unknown-error"); public static HugeGraph graph(GraphManager manager, String graph) { HugeGraph g = manager.graph(graph); @@ -193,17 +189,17 @@ public static class ApiMeasurer { public static final String EDGE_ITER = "edge_iterations"; public static final String VERTICE_ITER = "vertice_iterations"; - public static final String COST = "cost"; + public static final String COST = "cost(ns)"; private final long timeStart; private final Map measures; public ApiMeasurer() { - this.timeStart = System.currentTimeMillis(); + this.timeStart = System.nanoTime(); this.measures = InsertionOrderUtil.newMap(); } public Map measures() { - measures.put(COST, System.currentTimeMillis() - timeStart); + measures.put(COST, System.nanoTime() - timeStart); return measures; } @@ -224,8 +220,7 @@ protected void addCount(String key, long value) { if (current == null) { measures.put(key, new MutableLong(value)); } else if (current instanceof MutableLong) { - MutableLong currentMutableLong = (MutableLong) current; - currentMutableLong.add(value); + ((MutableLong) measures.computeIfAbsent(key, MutableLong::new)).add(value); } else if (current instanceof Long) { Long currentLong = (Long) current; measures.put(key, new MutableLong(currentLong + value)); From 5bb446ac3352a8f42dbdededdfaa3210d9298d0e Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Fri, 11 Aug 2023 19:40:07 +0800 Subject: [PATCH 12/16] fix: rollback change in .gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7eca2cb39a..47bbf40170 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,6 @@ upload-files/ demo* gen-java *.class -swagger-ui-* -hugegraph-dist/dist.sh ### STS ### .apt_generated From cea5db2004d93180cc24febda152df5ceffd4fc9 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Sat, 12 Aug 2023 18:59:21 +0800 Subject: [PATCH 13/16] fix: rollback ServerOptions.java code style --- .../hugegraph/config/ServerOptions.java | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java b/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java index 0ad77d6d9d..e66b593568 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java @@ -25,6 +25,20 @@ public class ServerOptions extends OptionHolder { + private ServerOptions() { + super(); + } + + private static volatile ServerOptions instance; + + public static synchronized ServerOptions instance() { + if (instance == null) { + instance = new ServerOptions(); + instance.registerOptions(); + } + return instance; + } + public static final ConfigOption REST_SERVER_URL = new ConfigOption<>( "restserver.url", @@ -32,6 +46,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "http://127.0.0.1:8080" ); + public static final ConfigOption SERVER_ID = new ConfigOption<>( "server.id", @@ -39,6 +54,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "server-1" ); + public static final ConfigOption SERVER_ROLE = new ConfigOption<>( "server.role", @@ -47,6 +63,7 @@ public class ServerOptions extends OptionHolder { allowValues("master", "worker", "computer"), "master" ); + public static final ConfigOption MAX_WORKER_THREADS = new ConfigOption<>( "restserver.max_worker_threads", @@ -54,6 +71,7 @@ public class ServerOptions extends OptionHolder { rangeInt(2, Integer.MAX_VALUE), 2 * CoreOptions.CPUS ); + public static final ConfigOption MIN_FREE_MEMORY = new ConfigOption<>( "restserver.min_free_memory", @@ -63,6 +81,7 @@ public class ServerOptions extends OptionHolder { nonNegativeInt(), 64 ); + public static final ConfigOption REQUEST_TIMEOUT = new ConfigOption<>( "restserver.request_timeout", @@ -71,6 +90,7 @@ public class ServerOptions extends OptionHolder { rangeInt(-1, Integer.MAX_VALUE), 30 ); + public static final ConfigOption CONN_IDLE_TIMEOUT = new ConfigOption<>( "restserver.connection_idle_timeout", @@ -79,6 +99,7 @@ public class ServerOptions extends OptionHolder { rangeInt(-1, Integer.MAX_VALUE), 30 ); + public static final ConfigOption CONN_MAX_REQUESTS = new ConfigOption<>( "restserver.connection_max_requests", @@ -87,6 +108,7 @@ public class ServerOptions extends OptionHolder { rangeInt(-1, Integer.MAX_VALUE), 256 ); + public static final ConfigOption GREMLIN_SERVER_URL = new ConfigOption<>( "gremlinserver.url", @@ -94,6 +116,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "http://127.0.0.1:8182" ); + public static final ConfigOption GREMLIN_SERVER_TIMEOUT = new ConfigOption<>( "gremlinserver.timeout", @@ -101,6 +124,7 @@ public class ServerOptions extends OptionHolder { positiveInt(), 30 ); + public static final ConfigOption GREMLIN_SERVER_MAX_ROUTE = new ConfigOption<>( "gremlinserver.max_route", @@ -108,6 +132,7 @@ public class ServerOptions extends OptionHolder { positiveInt(), 2 * CoreOptions.CPUS ); + public static final ConfigOption GRAPHS = new ConfigOption<>( "graphs", @@ -115,6 +140,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "./conf/graphs" ); + public static final ConfigOption MAX_VERTICES_PER_BATCH = new ConfigOption<>( "batch.max_vertices_per_batch", @@ -122,6 +148,7 @@ public class ServerOptions extends OptionHolder { positiveInt(), 500 ); + public static final ConfigOption MAX_EDGES_PER_BATCH = new ConfigOption<>( "batch.max_edges_per_batch", @@ -129,6 +156,7 @@ public class ServerOptions extends OptionHolder { positiveInt(), 500 ); + public static final ConfigOption MAX_WRITE_RATIO = new ConfigOption<>( "batch.max_write_ratio", @@ -137,6 +165,7 @@ public class ServerOptions extends OptionHolder { rangeInt(0, 100), 50 ); + public static final ConfigOption MAX_WRITE_THREADS = new ConfigOption<>( "batch.max_write_threads", @@ -145,6 +174,7 @@ public class ServerOptions extends OptionHolder { "batch.max_write_ratio * restserver.max_worker_threads.", nonNegativeInt(), 0); + public static final ConfigOption RAFT_GROUP_PEERS = new ConfigOption<>( "raft.group_peers", @@ -152,13 +182,15 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "127.0.0.1:8090" ); + public static final ConfigOption ALLOW_TRACE = new ConfigOption<>( "exception.allow_trace", "Whether to allow exception trace stack.", disallowEmpty(), - true + false ); + public static final ConfigOption AUTHENTICATOR = new ConfigOption<>( "auth.authenticator", @@ -168,6 +200,7 @@ public class ServerOptions extends OptionHolder { null, "" ); + public static final ConfigOption AUTH_GRAPH_STORE = new ConfigOption<>( "auth.graph_store", @@ -176,6 +209,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "hugegraph" ); + public static final ConfigOption AUTH_ADMIN_TOKEN = new ConfigOption<>( "auth.admin_token", @@ -184,6 +218,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "162f7848-0b6d-4faf-b557-3a0797869c55" ); + public static final ConfigListOption AUTH_USER_TOKENS = new ConfigListOption<>( "auth.user_tokens", @@ -192,6 +227,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "hugegraph:9fd95c9c-711b-415b-b85f-d4df46ba5c31" ); + public static final ConfigOption AUTH_REMOTE_URL = new ConfigOption<>( "auth.remote_url", @@ -202,6 +238,7 @@ public class ServerOptions extends OptionHolder { null, "" ); + public static final ConfigOption SSL_KEYSTORE_FILE = new ConfigOption<>( "ssl.keystore_file", @@ -210,6 +247,7 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), "conf/hugegraph-server.keystore" ); + public static final ConfigOption SSL_KEYSTORE_PASSWORD = new ConfigOption<>( "ssl.keystore_password", @@ -218,6 +256,7 @@ public class ServerOptions extends OptionHolder { null, "hugegraph" ); + public static final ConfigOption ENABLE_DYNAMIC_CREATE_DROP = new ConfigOption<>( "graphs.enable_dynamic_create_drop", @@ -225,17 +264,4 @@ public class ServerOptions extends OptionHolder { disallowEmpty(), true ); - private static volatile ServerOptions instance; - - private ServerOptions() { - super(); - } - - public static synchronized ServerOptions instance() { - if (instance == null) { - instance = new ServerOptions(); - instance.registerOptions(); - } - return instance; - } -} +} \ No newline at end of file From 4cc5f461fd3955746d6b9b1542a5e01bfeab4d2b Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Sat, 12 Aug 2023 19:12:39 +0800 Subject: [PATCH 14/16] fix: rollback API.java code style and add exception in else branch --- .../main/java/org/apache/hugegraph/api/API.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java index a0540d2fe4..99fe67e5ba 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/API.java @@ -48,21 +48,21 @@ public class API { public static final String TEXT_PLAIN = MediaType.TEXT_PLAIN; public static final String APPLICATION_JSON = MediaType.APPLICATION_JSON; public static final String APPLICATION_JSON_WITH_CHARSET = - APPLICATION_JSON + ";charset=" + CHARSET; + APPLICATION_JSON + ";charset=" + CHARSET; public static final String JSON = MediaType.APPLICATION_JSON_TYPE - .getSubtype(); + .getSubtype(); public static final String ACTION_APPEND = "append"; public static final String ACTION_ELIMINATE = "eliminate"; public static final String ACTION_CLEAR = "clear"; protected static final Logger LOG = Log.logger(API.class); private static final Meter SUCCEED_METER = - MetricsUtil.registerMeter(API.class, "commit-succeed"); + MetricsUtil.registerMeter(API.class, "commit-succeed"); private static final Meter ILLEGAL_ARG_ERROR_METER = - MetricsUtil.registerMeter(API.class, "illegal-arg"); + MetricsUtil.registerMeter(API.class, "illegal-arg"); private static final Meter EXPECTED_ERROR_METER = - MetricsUtil.registerMeter(API.class, "expected-error"); + MetricsUtil.registerMeter(API.class, "expected-error"); private static final Meter UNKNOWN_ERROR_METER = - MetricsUtil.registerMeter(API.class, "unknown-error"); + MetricsUtil.registerMeter(API.class, "unknown-error"); public static HugeGraph graph(GraphManager manager, String graph) { HugeGraph g = manager.graph(graph); @@ -224,6 +224,9 @@ protected void addCount(String key, long value) { } else if (current instanceof Long) { Long currentLong = (Long) current; measures.put(key, new MutableLong(currentLong + value)); + } else { + throw new NotSupportedException("addCount() method's 'value' datatype must be " + + "Long or MutableLong"); } } From 92ba7c8b5d4eb93eb6a21dcf93dc368a585a4915 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Sat, 12 Aug 2023 19:14:56 +0800 Subject: [PATCH 15/16] fix: fix code style --- .../hugegraph/api/traversers/AllShortestPathsAPI.java | 2 +- .../api/traversers/CustomizedCrosspointsAPI.java | 4 ++-- .../hugegraph/api/traversers/CustomizedPathsAPI.java | 10 +++++----- .../api/traversers/FusiformSimilarityAPI.java | 3 +-- .../apache/hugegraph/api/traversers/KneighborAPI.java | 4 ++-- .../org/apache/hugegraph/api/traversers/KoutAPI.java | 9 ++++----- .../org/apache/hugegraph/api/traversers/PathsAPI.java | 2 +- .../org/apache/hugegraph/api/traversers/RingsAPI.java | 2 +- .../hugegraph/api/traversers/ShortestPathAPI.java | 2 +- .../api/traversers/SingleSourceShortestPathAPI.java | 2 +- .../hugegraph/api/traversers/TemplatePathsAPI.java | 2 +- .../api/traversers/WeightedShortestPathAPI.java | 2 +- 12 files changed, 21 insertions(+), 23 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java index 387e7531be..e432f81ea7 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/AllShortestPathsAPI.java @@ -81,7 +81,7 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " + "direction {}, edge label {}, max depth '{}', " + "max degree '{}', skipped degree '{}', capacity '{}', " + - "with vertex '{}' and with edge '{}'", + "with_vertex '{}' and with_edge '{}'", graph, source, target, direction, edgeLabel, depth, maxDegree, skipDegree, capacity, withVertex, withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java index ca06c3ed5f..c393a93519 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java @@ -94,8 +94,8 @@ public String post(@Context GraphManager manager, "The steps of crosspoints request can't be empty"); LOG.debug("Graph [{}] get customized crosspoints from source vertex " + - "'{}', with path_pattern '{}', with path '{}', with vertex " + - "'{}', capacity '{}', limit '{}' and with edge '{}'", + "'{}', with path_pattern '{}', with path '{}', with_vertex " + + "'{}', capacity '{}', limit '{}' and with_edge '{}'", graph, request.sources, request.pathPatterns, request.withPath, request.withVertex, request.capacity, request.limit, request.withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java index e8613c1b17..5641e31193 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedPathsAPI.java @@ -65,10 +65,10 @@ public class CustomizedPathsAPI extends API { private static final Logger LOG = Log.logger(CustomizedPathsAPI.class); private static List step(HugeGraph graph, - PathRequest req) { - int stepSize = req.steps.size(); + PathRequest request) { + int stepSize = request.steps.size(); List steps = new ArrayList<>(stepSize); - for (Step step : req.steps) { + for (Step step : request.steps) { steps.add(step.jsonToStep(graph)); } return steps; @@ -92,7 +92,7 @@ public String post(@Context GraphManager manager, LOG.debug("Graph [{}] get customized paths from source vertex '{}', " + "with steps '{}', sort by '{}', capacity '{}', limit '{}', " + - "with vertex '{}' and with edge '{}'", graph, request.sources, request.steps, + "with_vertex '{}' and with_edge '{}'", graph, request.sources, request.steps, request.sortBy, request.capacity, request.limit, request.withVertex, request.withEdge); @@ -129,7 +129,7 @@ public String post(@Context GraphManager manager, } Iterator iterEdge; - Set edges = traverser.getEdgeRecord().getEdges(paths); + Set edges = traverser.edgeResults().getEdges(paths); if (request.withEdge && !edges.isEmpty()) { iterEdge = edges.iterator(); } else { diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java index e22962d840..1b2273dc4a 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/FusiformSimilarityAPI.java @@ -101,8 +101,7 @@ public String post(@Context GraphManager manager, E.checkArgument(sources != null && sources.hasNext(), "The source vertices can't be empty"); - FusiformSimilarityTraverser traverser = - new FusiformSimilarityTraverser(g); + FusiformSimilarityTraverser traverser = new FusiformSimilarityTraverser(g); SimilarsMap result = traverser.fusiformSimilarity( sources, request.direction, request.label, request.minNeighbors, request.alpha, diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java index 9981dbe592..a0e7d0c4ee 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KneighborAPI.java @@ -124,7 +124,7 @@ public String post(@Context GraphManager manager, "The steps of request can't be null"); if (request.countOnly) { E.checkArgument(!request.withVertex && !request.withPath && !request.withEdge, - "Can't return vertex or path or edge when count only"); + "Can't return vertex, edge or path when count only"); } LOG.debug("Graph [{}] get customized kneighbor from source vertex " + @@ -185,7 +185,7 @@ public String post(@Context GraphManager manager, Iterator iterEdge = Collections.emptyIterator(); if (request.withPath) { - Set edges = results.getEdgeIdRecord().getEdges(paths); + Set edges = results.edgeResults().getEdges(paths); if (request.withEdge) { iterEdge = edges.iterator(); } else { diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java index 9d75fd4a3d..1adf2be5eb 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java @@ -110,8 +110,8 @@ public String get(@Context GraphManager manager, } if (count_only) { - return manager.serializer(g, measure.measures()).writeMap(ImmutableMap.of( - "vertices_size", ids.size())); + return manager.serializer(g, measure.measures()) + .writeMap(ImmutableMap.of("vertices_size", ids.size())); } return manager.serializer(g, measure.measures()).writeList("vertices", ids); } @@ -130,7 +130,7 @@ public String post(@Context GraphManager manager, "The steps of request can't be null"); if (request.countOnly) { E.checkArgument(!request.withVertex && !request.withPath && !request.withEdge, - "Can't return vertex or path or edge when count only"); + "Can't return vertex, edge or path when count only"); } LOG.debug("Graph [{}] get customized kout from source vertex '{}', " + @@ -193,7 +193,7 @@ public String post(@Context GraphManager manager, Iterator iterEdge = Collections.emptyIterator(); if (request.withPath) { - Set edges = results.getEdgeIdRecord().getEdges(paths); + Set edges = results.edgeResults().getEdges(paths); if (request.withEdge) { iterEdge = edges.iterator(); } else { @@ -226,7 +226,6 @@ private static class Request { public boolean withVertex = false; @JsonProperty("with_path") public boolean withPath = false; - @JsonProperty("with_edge") public boolean withEdge = false; diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java index 8ae3bebe7a..50bca7f75b 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/PathsAPI.java @@ -125,7 +125,7 @@ public String post(@Context GraphManager manager, LOG.debug("Graph [{}] get paths from source vertices '{}', target " + "vertices '{}', with step '{}', max depth '{}', " + - "capacity '{}', limit '{}', with vertex '{}' and with edge '{}'", + "capacity '{}', limit '{}', with_vertex '{}' and with_edge '{}'", graph, request.sources, request.targets, request.step, request.depth, request.capacity, request.limit, request.withVertex, request.withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java index 29e5a867a2..3a44fd85a1 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/RingsAPI.java @@ -81,7 +81,7 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get rings paths reachable from '{}' with " + "direction '{}', edge label '{}', max depth '{}', " + "source in ring '{}', max degree '{}', capacity '{}', " + - "limit '{}', with vertex '{}' and with edge '{}'", + "limit '{}', with_vertex '{}' and with_edge '{}'", graph, sourceV, direction, edgeLabel, depth, sourceInRing, maxDegree, capacity, limit, withVertex, withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java index c89e83873d..dcc8489ae1 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/ShortestPathAPI.java @@ -81,7 +81,7 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get shortest path from '{}', to '{}' with " + "direction {}, edge label {}, max depth '{}', " + "max degree '{}', skipped maxDegree '{}', capacity '{}', " + - "with vertex '{}' and with edge '{}'", + "with_vertex '{}' and with_edge '{}'", graph, source, target, direction, edgeLabel, depth, maxDegree, skipDegree, capacity, withVertex, withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java index 93ea81384c..eab339d958 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SingleSourceShortestPathAPI.java @@ -80,7 +80,7 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get single source shortest path from '{}' " + "with direction {}, edge label {}, weight property {}, " + "max degree '{}', capacity '{}', limit '{}', " + - "with vertex '{}' and with edge '{}'", + "with_vertex '{}' and with_edge '{}'", graph, source, direction, edgeLabel, weight, maxDegree, capacity, limit, withVertex, withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java index bded530416..9b3739acb2 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/TemplatePathsAPI.java @@ -90,7 +90,7 @@ public String post(@Context GraphManager manager, LOG.debug("Graph [{}] get template paths from source vertices '{}', " + "target vertices '{}', with steps '{}', " + - "capacity '{}', limit '{}', with vertex '{}' and with edge '{}'", + "capacity '{}', limit '{}', with_vertex '{}' and with_edge '{}'", graph, request.sources, request.targets, request.steps, request.capacity, request.limit, request.withVertex, request.withEdge); diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java index 0defd4b90e..1c25661f15 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/WeightedShortestPathAPI.java @@ -81,7 +81,7 @@ public String get(@Context GraphManager manager, LOG.debug("Graph [{}] get weighted shortest path between '{}' and " + "'{}' with direction {}, edge label {}, weight property {}, " + "max degree '{}', skip degree '{}', capacity '{}', " + - "with vertex '{}' and with edge '{}'", + "with_vertex '{}' and with_edge '{}'", graph, source, target, direction, edgeLabel, weight, maxDegree, skipDegree, capacity, withVertex, withEdge); From 559bff1c5c124d9609d4de541034b1ede9624b89 Mon Sep 17 00:00:00 2001 From: wucc <77946882+DanGuge@users.noreply.github.com> Date: Sat, 12 Aug 2023 19:20:35 +0800 Subject: [PATCH 16/16] fix: name style & code style * rename edgeRecord to edgeResults * fix Request class code style in SameNeighborsAPI.java --- .../traversers/CustomizedCrosspointsAPI.java | 2 +- .../api/traversers/SameNeighborsAPI.java | 17 +++---- .../algorithm/CollectionPathsTraverser.java | 4 +- .../algorithm/CustomizePathsTraverser.java | 11 ++--- .../CustomizedCrosspointsTraverser.java | 10 ++--- .../algorithm/KneighborTraverser.java | 2 +- .../traversal/algorithm/KoutTraverser.java | 2 +- .../traversal/algorithm/PathTraverser.java | 7 +-- .../algorithm/ShortestPathTraverser.java | 44 +++++++++---------- .../algorithm/TemplatePathsTraverser.java | 4 +- .../records/SingleWayMultiPathsRecords.java | 10 ++--- 11 files changed, 55 insertions(+), 58 deletions(-) diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java index c393a93519..cadbd2ce00 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/CustomizedCrosspointsAPI.java @@ -133,7 +133,7 @@ public String post(@Context GraphManager manager, Iterator iterEdge = Collections.emptyIterator(); if (request.withPath) { - Set edges = traverser.getEdgeRecord().getEdges(paths.paths()); + Set edges = traverser.edgeResults().getEdges(paths.paths()); if (request.withEdge) { iterEdge = edges.iterator(); } else { diff --git a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java index fe26165067..489ca08054 100644 --- a/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java +++ b/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/SameNeighborsAPI.java @@ -41,7 +41,6 @@ import com.codahale.metrics.annotation.Timed; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; import io.swagger.v3.oas.annotations.tags.Tag; @@ -139,6 +138,7 @@ public String sameNeighbors(@Context GraphManager manager, } private static class Request { + @JsonProperty("max_degree") public long maxDegree = Long.parseLong(DEFAULT_MAX_DEGREE); @JsonProperty("limit") @@ -154,16 +154,11 @@ private static class Request { @Override public String toString() { - ObjectMapper om = new ObjectMapper(); - String vertexStr; - try { - vertexStr = om.writeValueAsString(this.vertexList); - } catch (Exception e) { - throw new RuntimeException(e); - } - return String.format("SameNeighborsBatchRequest{vertex=%s,direction=%s,label=%s," + - "max_degree=%d,limit=%d,with_vertex=%s", vertexStr, this.direction, - this.labels, this.maxDegree, this.limit, this.withVertex); + return String.format("SameNeighborsBatchRequest{vertex_list=%s," + + "direction=%s,label=%s,max_degree=%d," + + "limit=%d,with_vertex=%s", + this.vertexList, this.direction, this.labels, + this.maxDegree, this.limit, this.withVertex); } } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java index 3a4fe68286..51e919dff8 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CollectionPathsTraverser.java @@ -84,14 +84,14 @@ public WrappedPathCollection paths(Iterator sources, traverser.forward(); if (traverser.finished()) { Collection paths = traverser.paths(); - return new WrappedPathCollection(paths, traverser.edgeRecord.getEdges(paths)); + return new WrappedPathCollection(paths, traverser.edgeResults.getEdges(paths)); } // Backward traverser.backward(); if (traverser.finished()) { Collection paths = traverser.paths(); - return new WrappedPathCollection(paths, traverser.edgeRecord.getEdges(paths)); + return new WrappedPathCollection(paths, traverser.edgeResults.getEdges(paths)); } } while (true); } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java index 87f4702cb0..28e30367d6 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizePathsTraverser.java @@ -38,11 +38,12 @@ import jakarta.ws.rs.core.MultivaluedMap; public class CustomizePathsTraverser extends HugeTraverser { - private final EdgeRecord edgeRecord; + + private final EdgeRecord edgeResults; public CustomizePathsTraverser(HugeGraph graph) { super(graph); - this.edgeRecord = new EdgeRecord(false); + this.edgeResults = new EdgeRecord(false); } public static List topNPath(List paths, @@ -108,7 +109,7 @@ public List customizedPaths(Iterator vertices, this.edgeIterCounter.addAndGet(1L); Id target = edge.id().otherVertexId(); - this.edgeRecord.addEdge(entry.getKey(), target, edge); + this.edgeResults.addEdge(entry.getKey(), target, edge); for (Node n : entry.getValue()) { // If have loop, skip target @@ -171,8 +172,8 @@ public List customizedPaths(Iterator vertices, return paths; } - public EdgeRecord getEdgeRecord() { - return edgeRecord; + public EdgeRecord edgeResults() { + return edgeResults; } public static class WeightNode extends Node { diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java index a6df06f88e..7b6bf8f76f 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/CustomizedCrosspointsTraverser.java @@ -42,11 +42,11 @@ public class CustomizedCrosspointsTraverser extends HugeTraverser { - private final EdgeRecord edgeRecord; + private final EdgeRecord edgeResults; public CustomizedCrosspointsTraverser(HugeGraph graph) { super(graph); - this.edgeRecord = new EdgeRecord(false); + this.edgeResults = new EdgeRecord(false); } private static CrosspointsPaths intersectionPaths(List sources, @@ -98,8 +98,8 @@ private static CrosspointsPaths intersectionPaths(List sources, return new CrosspointsPaths(newSet(intersection), results); } - public EdgeRecord getEdgeRecord() { - return edgeRecord; + public EdgeRecord edgeResults() { + return edgeResults; } public CrosspointsPaths crosspointsPaths(Iterator vertices, @@ -143,7 +143,7 @@ public CrosspointsPaths crosspointsPaths(Iterator vertices, edgeCount += 1; Id target = edge.id().otherVertexId(); - this.edgeRecord.addEdge(entry.getKey(), target, edge); + this.edgeResults.addEdge(entry.getKey(), target, edge); for (Node n : entry.getValue()) { // If have loop, skip target diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java index ac8aa579c9..b3ae29ac8f 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KneighborTraverser.java @@ -92,7 +92,7 @@ public KneighborRecords customizedKneighbor(Id source, EdgeStep step, Id target = edge.id().otherVertexId(); records.addPath(v, target); - records.getEdgeIdRecord().addEdge(v, target, edge); + records.edgeResults().addEdge(v, target, edge); this.edgeIterCounter.addAndGet(1L); } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java index bb97be0aa3..9f40be8fbd 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/KoutTraverser.java @@ -124,7 +124,7 @@ public KoutRecords customizedKout(Id source, EdgeStep step, records.addPath(v, target); this.checkCapacity(capacity, records.accessed(), depth[0]); - records.getEdgeIdRecord().addEdge(v, target, edge); + records.edgeResults().addEdge(v, target, edge); this.edgeIterCounter.addAndGet(1L); } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java index 6ba7eb68d5..ac98872c41 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/PathTraverser.java @@ -28,6 +28,7 @@ import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.structure.HugeEdge; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser.EdgeRecord; import org.apache.hugegraph.traversal.algorithm.steps.EdgeStep; import org.apache.hugegraph.traversal.algorithm.strategy.TraverseStrategy; import org.apache.tinkerpop.gremlin.structure.Edge; @@ -50,7 +51,7 @@ public abstract class PathTraverser { protected Set paths; protected TraverseStrategy traverseStrategy; - protected HugeTraverser.EdgeRecord edgeRecord; + protected EdgeRecord edgeResults; public PathTraverser(HugeTraverser traverser, TraverseStrategy strategy, Collection sources, Collection targets, @@ -79,7 +80,7 @@ public PathTraverser(HugeTraverser traverser, TraverseStrategy strategy, this.paths = this.newPathSet(); - this.edgeRecord = new HugeTraverser.EdgeRecord(concurrent); + this.edgeResults = new EdgeRecord(concurrent); } public void forward() { @@ -148,7 +149,7 @@ private void traverseOne(Id v, EdgeStep step, boolean forward) { Id target = edge.id().otherVertexId(); this.traverser.edgeIterCounter.addAndGet(1L); - this.edgeRecord.addEdge(v, target, edge); + this.edgeResults.addEdge(v, target, edge); this.processOne(v, target, forward); } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java index 1783ab21fd..45ccdc6345 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/ShortestPathTraverser.java @@ -84,11 +84,11 @@ public Path shortestPath(Id sourceV, Id targetV, Directions dir, } this.vertexIterCounter.addAndGet(traverser.vertexCount); - this.edgeIterCounter.addAndGet(traverser.record.accessed()); + this.edgeIterCounter.addAndGet(traverser.pathResults.accessed()); Path path = paths.isEmpty() ? Path.EMPTY : paths.iterator().next(); - Set edges = traverser.edgeRecord.getEdges(path); + Set edges = traverser.edgeResults.getEdges(path); path.setEdges(edges); return path; } @@ -137,16 +137,16 @@ public PathSet allShortestPaths(Id sourceV, Id targetV, Directions dir, } this.vertexIterCounter.addAndGet(traverser.vertexCount); - this.edgeIterCounter.addAndGet(traverser.record.accessed()); + this.edgeIterCounter.addAndGet(traverser.pathResults.accessed()); - paths.setEdges(traverser.edgeRecord.getEdges(paths)); + paths.setEdges(traverser.edgeResults.getEdges(paths)); return paths; } private class Traverser { - private final ShortestPathRecords record; - private final EdgeRecord edgeRecord; + private final ShortestPathRecords pathResults; + private final EdgeRecord edgeResults; private final Directions direction; private final Map labels; private final long degree; @@ -157,8 +157,8 @@ private class Traverser { public Traverser(Id sourceV, Id targetV, Directions dir, Map labels, long degree, long skipDegree, long capacity) { - this.record = new ShortestPathRecords(sourceV, targetV); - this.edgeRecord = new EdgeRecord(false); + this.pathResults = new ShortestPathRecords(sourceV, targetV); + this.edgeResults = new EdgeRecord(false); this.direction = dir; this.labels = labels; this.degree = degree; @@ -168,7 +168,7 @@ public Traverser(Id sourceV, Id targetV, Directions dir, } public PathSet traverse(boolean all) { - return this.record.sourcesLessThanTargets() ? + return this.pathResults.sourcesLessThanTargets() ? this.forward(all) : this.backward(all); } @@ -180,9 +180,9 @@ public PathSet forward(boolean all) { PathSet results = new PathSet(); long degree = this.skipDegree > 0L ? this.skipDegree : this.degree; - this.record.startOneLayer(true); - while (this.record.hasNextKey()) { - Id source = this.record.nextKey(); + this.pathResults.startOneLayer(true); + while (this.pathResults.hasNextKey()) { + Id source = this.pathResults.nextKey(); Iterator edges = edgesOfVertex(source, this.direction, this.labels, degree); @@ -195,9 +195,9 @@ public PathSet forward(boolean all) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); - this.edgeRecord.addEdge(source, target, edge); + this.edgeResults.addEdge(source, target, edge); - PathSet paths = this.record.findPath(target, + PathSet paths = this.pathResults.findPath(target, t -> !this.superNode(t, this.direction), all, false); @@ -212,7 +212,7 @@ public PathSet forward(boolean all) { } - this.record.finishOneLayer(); + this.pathResults.finishOneLayer(); return results; } @@ -226,9 +226,9 @@ public PathSet backward(boolean all) { long degree = this.skipDegree > 0L ? this.skipDegree : this.degree; Directions opposite = this.direction.opposite(); - this.record.startOneLayer(false); - while (this.record.hasNextKey()) { - Id source = this.record.nextKey(); + this.pathResults.startOneLayer(false); + while (this.pathResults.hasNextKey()) { + Id source = this.pathResults.nextKey(); Iterator edges = edgesOfVertex(source, opposite, this.labels, degree); @@ -241,9 +241,9 @@ public PathSet backward(boolean all) { HugeEdge edge = (HugeEdge) edges.next(); Id target = edge.id().otherVertexId(); - this.edgeRecord.addEdge(source, target, edge); + this.edgeResults.addEdge(source, target, edge); - PathSet paths = this.record.findPath(target, + PathSet paths = this.pathResults.findPath(target, t -> !this.superNode(t, opposite), all, false); @@ -258,7 +258,7 @@ public PathSet backward(boolean all) { } // Re-init targets - this.record.finishOneLayer(); + this.pathResults.finishOneLayer(); return results; } @@ -273,7 +273,7 @@ private boolean superNode(Id vertex, Directions direction) { } private long accessed() { - return this.record.accessed(); + return this.pathResults.accessed(); } } } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java index c89bff2500..949014e192 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/TemplatePathsTraverser.java @@ -80,14 +80,14 @@ public WrappedPathSet templatePaths(Iterator sources, traverser.forward(); if (traverser.finished()) { Set paths = traverser.paths(); - return new WrappedPathSet(paths, traverser.edgeRecord.getEdges(paths)); + return new WrappedPathSet(paths, traverser.edgeResults.getEdges(paths)); } // Backward traverser.backward(); if (traverser.finished()) { Set paths = traverser.paths(); - return new WrappedPathSet(paths, traverser.edgeRecord.getEdges(paths)); + return new WrappedPathSet(paths, traverser.edgeResults.getEdges(paths)); } } while (true); } diff --git a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java index 31de69c2ec..d41adc92a8 100644 --- a/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java +++ b/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/records/SingleWayMultiPathsRecords.java @@ -26,7 +26,7 @@ import org.apache.hugegraph.HugeException; import org.apache.hugegraph.backend.id.Id; import org.apache.hugegraph.perf.PerfUtil.Watched; -import org.apache.hugegraph.traversal.algorithm.HugeTraverser; +import org.apache.hugegraph.traversal.algorithm.HugeTraverser.EdgeRecord; import org.apache.hugegraph.traversal.algorithm.HugeTraverser.Path; import org.apache.hugegraph.traversal.algorithm.HugeTraverser.PathSet; import org.apache.hugegraph.traversal.algorithm.records.record.Int2IntRecord; @@ -45,7 +45,7 @@ public abstract class SingleWayMultiPathsRecords extends AbstractRecords { private final int sourceCode; private final boolean nearest; private final IntSet accessedVertices; - private final HugeTraverser.EdgeRecord edgeRecord; + private final EdgeRecord edgeResults; private IntIterator parentRecordKeys; public SingleWayMultiPathsRecords(RecordType type, boolean concurrent, @@ -59,7 +59,7 @@ public SingleWayMultiPathsRecords(RecordType type, boolean concurrent, firstRecord.addPath(this.sourceCode, 0); this.records = new Stack<>(); this.records.push(firstRecord); - this.edgeRecord = new HugeTraverser.EdgeRecord(concurrent); + this.edgeResults = new EdgeRecord(concurrent); this.accessedVertices = CollectionFactory.newIntSet(); } @@ -178,8 +178,8 @@ protected final Stack records() { return this.records; } - public HugeTraverser.EdgeRecord getEdgeIdRecord() { - return edgeRecord; + public EdgeRecord edgeResults() { + return edgeResults; } public abstract int size();