This is an automated email from the ASF dual-hosted git repository. jermy pushed a commit to branch only-one-id-query-optimize in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git
commit a929396e2de355689823a3ca6f985d877a2f65ca Author: Jermy Li <[email protected]> AuthorDate: Sat Aug 30 22:35:18 2025 +0800 perf(core): optimize queryVerticesByIds for only-one-id query Change-Id: Ic6e01eb8e2b4c97c5263cfa0f78c58b6033435da --- .../hugegraph/backend/tx/GraphTransaction.java | 272 ++++++++++++++++----- 1 file changed, 208 insertions(+), 64 deletions(-) diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java index e50fa5c6f..515043097 100644 --- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java +++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java @@ -102,6 +102,7 @@ import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; import jakarta.ws.rs.ForbiddenException; @@ -307,8 +308,8 @@ public class GraphTransaction extends IndexableTransaction { return false; } - @Watched(prefix = "tx") @Override + @Watched(prefix = "graph") protected BackendMutation prepareCommit() { // Serialize and add updates into super.deletions if (!this.removedVertices.isEmpty() || !this.removedEdges.isEmpty()) { @@ -514,6 +515,7 @@ public class GraphTransaction extends IndexableTransaction { } @Override + @Watched(prefix = "graph") public void commit() throws BackendException { try { super.commit(); @@ -523,6 +525,7 @@ public class GraphTransaction extends IndexableTransaction { } @Override + @Watched(prefix = "graph") public void rollback() throws BackendException { // Rollback properties changes for (HugeProperty<?> prop : this.updatedOldestProps) { @@ -536,6 +539,7 @@ public class GraphTransaction extends IndexableTransaction { } @Override + @Watched(prefix = "graph") public QueryResults<BackendEntry> query(Query query) { if (!(query instanceof ConditionQuery)) { // It's a sysprop-query, don't need to optimize @@ -550,6 +554,7 @@ public class GraphTransaction extends IndexableTransaction { } @Override + @Watched(prefix = "graph") public Number queryNumber(Query query) { boolean isConditionQuery = query instanceof ConditionQuery; boolean hasUpdate = this.hasUpdate(); @@ -709,6 +714,7 @@ public class GraphTransaction extends IndexableTransaction { this.afterWrite(); } + @Watched(prefix = "graph") public Iterator<Vertex> queryAdjacentVertices(Iterator<Edge> edges) { if (this.lazyLoadAdjacentVertex) { return new MapperIterator<>(edges, edge -> { @@ -726,15 +732,18 @@ public class GraphTransaction extends IndexableTransaction { }); } + @Watched(prefix = "graph") public Iterator<Vertex> queryAdjacentVertices(Object... vertexIds) { return this.queryVerticesByIds(vertexIds, true, this.checkAdjacentVertexExist); } + @Watched(prefix = "graph") public Iterator<Vertex> queryVertices(Object... vertexIds) { return this.queryVerticesByIds(vertexIds, false, false); } + @Watched(prefix = "graph") public Vertex queryVertex(Object vertexId) { Iterator<Vertex> iter = this.queryVerticesByIds(new Object[]{vertexId}, false, true); @@ -775,40 +784,103 @@ public class GraphTransaction extends IndexableTransaction { return this.queryVerticesByIds(vertexIds, adjacentVertex, checkMustExist, HugeType.VERTEX); } + @Watched(prefix = "graph") protected Iterator<Vertex> queryVerticesByIds(Object[] vertexIds, boolean adjacentVertex, boolean checkMustExist, HugeType type) { Query.checkForceCapacity(vertexIds.length); - // NOTE: allowed duplicated vertices if query by duplicated ids - List<Id> ids = InsertionOrderUtil.newList(); - Map<Id, HugeVertex> vertices = new HashMap<>(vertexIds.length); + List<Id> ids; + Map<Id, HugeVertex> vertices; + boolean verticesUpdated = this.verticesInTxSize() > 0; - IdQuery query = new IdQuery(type); - for (Object vertexId : vertexIds) { - HugeVertex vertex; - Id id = HugeVertex.getIdValue(vertexId); - if (id == null || this.removedVertices.containsKey(id)) { - // The record has been deleted - continue; - } else if ((vertex = this.addedVertices.get(id)) != null || - (vertex = this.updatedVertices.get(id)) != null) { - if (vertex.expired()) { - continue; + if (vertexIds.length == 1) { + Id id = HugeVertex.getIdValue(vertexIds[0]); + + boolean tryQueryBackend = true; + if (id == null) { + tryQueryBackend = false; + ids = ImmutableList.of(); + } else { + ids = ImmutableList.of(id); + } + + HugeVertex vertex = null; + if (id != null && verticesUpdated) { + if (this.removedVertices.containsKey(id)) { + // The record has been deleted + tryQueryBackend = false; + } else if ((vertex = this.addedVertices.get(id)) != null || + (vertex = this.updatedVertices.get(id)) != null) { + // Found from local tx + tryQueryBackend = false; + if (vertex.expired()) { + vertex = null; + } else { + assert vertex != null; + } } - // Found from local tx - vertices.put(vertex.id(), vertex); + } + + if (vertex != null) { + assert !tryQueryBackend; + vertices = ImmutableMap.of(vertex.id(), vertex); + } else if (!tryQueryBackend) { + assert vertex == null; + vertices = ImmutableMap.of(); } else { - // Prepare to query from backend store - query.query(id); + // Query from backend store + IdQuery query = new IdQuery.OneIdQuery(type, id); + Iterator<HugeVertex> it = this.queryVerticesFromBackend(query); + vertex = QueryResults.one(it); + if (vertex == null) { + vertices = ImmutableMap.of(); + } else { + vertices = ImmutableMap.of(vertex.id(), vertex); + } + } + } else { + // NOTE: allowed duplicated vertices if query by duplicated ids + ids = InsertionOrderUtil.newList(); + vertices = new HashMap<>(vertexIds.length); + + IdQuery query = new IdQuery(type); + for (Object vertexId : vertexIds) { + Id id = HugeVertex.getIdValue(vertexId); + if (id == null) { + continue; + } + boolean foundLocal = false; + if (verticesUpdated) { + HugeVertex vertex; + if (this.removedVertices.containsKey(id)) { + // The record has been deleted + continue; + } + if ((vertex = this.addedVertices.get(id)) != null || + (vertex = this.updatedVertices.get(id)) != null) { + if (vertex.expired()) { + continue; + } + // Found from local tx + foundLocal = true; + vertices.put(vertex.id(), vertex); + } else { + assert !foundLocal; + } + } + if (!foundLocal) { + // Prepare to query from backend store + query.query(id); + } + ids.add(id); } - ids.add(id); - } - if (!query.empty()) { - // Query from backend store - query.mustSortByInput(false); - Iterator<HugeVertex> it = this.queryVerticesFromBackend(query); - QueryResults.fillMap(it, vertices); + if (!query.empty()) { + // Query from backend store + query.mustSortByInput(false); + Iterator<HugeVertex> it = this.queryVerticesFromBackend(query); + QueryResults.fillMap(it, vertices); + } } return new MapperIterator<>(ids.iterator(), id -> { @@ -830,11 +902,13 @@ public class GraphTransaction extends IndexableTransaction { }); } + @Watched(prefix = "graph") public Iterator<Vertex> queryVertices() { Query q = new Query(HugeType.VERTEX); return this.queryVertices(q); } + @Watched(prefix = "graph") public Iterator<Vertex> queryVertices(Query query) { if (this.hasUpdate()) { E.checkArgument(query.noLimitAndOffset(), @@ -856,6 +930,7 @@ public class GraphTransaction extends IndexableTransaction { return this.skipOffsetOrStopLimit(r, query); } + @Watched(prefix = "graph") protected Iterator<HugeVertex> queryVerticesFromBackend(Query query) { assert query.resultType().isVertex(); @@ -917,14 +992,17 @@ public class GraphTransaction extends IndexableTransaction { this.afterWrite(); } + @Watched(prefix = "graph") public Iterator<Edge> queryEdgesByVertex(Id id) { return this.queryEdges(constructEdgesQuery(id, Directions.BOTH, new Id[0])); } + @Watched(prefix = "graph") public Iterator<Edge> queryEdges(Object... edgeIds) { return this.queryEdgesByIds(edgeIds, false); } + @Watched(prefix = "graph") public Edge queryEdge(Object edgeId) { Iterator<Edge> iter = this.queryEdgesByIds(new Object[]{edgeId}, true); Edge edge = QueryResults.one(iter); @@ -934,57 +1012,121 @@ public class GraphTransaction extends IndexableTransaction { return edge; } + @Watched(prefix = "graph") protected Iterator<Edge> queryEdgesByIds(Object[] edgeIds, boolean verifyId) { Query.checkForceCapacity(edgeIds.length); - // NOTE: allowed duplicated edges if query by duplicated ids - List<Id> ids = InsertionOrderUtil.newList(); - Map<Id, HugeEdge> edges = new HashMap<>(edgeIds.length); + List<Id> ids; + Map<Id, HugeEdge> edges; + boolean edgesUpdated = this.edgesInTxSize() > 0; - IdQuery query = new IdQuery(HugeType.EDGE); - for (Object edgeId : edgeIds) { - HugeEdge edge; - EdgeId id = HugeEdge.getIdValue(edgeId, !verifyId); + if (edgeIds.length == 1) { + EdgeId id = HugeEdge.getIdValue(edgeIds[0], !verifyId); + + boolean tryQueryBackend = true; if (id == null) { - continue; + tryQueryBackend = false; + ids = ImmutableList.of(); + } else { + if (id.direction() == Directions.IN) { + id = id.switchDirection(); + } + ids = ImmutableList.of(id); + } + + HugeEdge edge = null; + if (id != null && edgesUpdated) { + if (this.removedEdges.containsKey(id)) { + // The record has been deleted + tryQueryBackend = false; + } else if ((edge = this.addedEdges.get(id)) != null || + (edge = this.updatedEdges.get(id)) != null) { + // Found from local tx + tryQueryBackend = false; + if (edge.expired()) { + edge = null; + } else { + assert edge != null; + } + } } - if (id.direction() == Directions.IN) { - id = id.switchDirection(); + + if (edge != null) { + assert !tryQueryBackend; + edges = ImmutableMap.of(edge.id(), edge); + } else if (!tryQueryBackend) { + assert edge == null; + edges = ImmutableMap.of(); + } else { + // Query from backend store + IdQuery query = new IdQuery.OneIdQuery(HugeType.EDGE, id); + Iterator<HugeEdge> it = this.queryEdgesFromBackend(query); + edge = QueryResults.one(it); + if (edge == null) { + edges = ImmutableMap.of(); + } else { + edges = ImmutableMap.of(edge.id(), edge); + } } - if (this.removedEdges.containsKey(id)) { - // The record has been deleted - continue; - } else if ((edge = this.addedEdges.get(id)) != null || - (edge = this.updatedEdges.get(id)) != null) { - if (edge.expired()) { + } else { + // NOTE: allowed duplicated edges if query by duplicated ids + ids = InsertionOrderUtil.newList(); + edges = new HashMap<>(edgeIds.length); + + IdQuery query = new IdQuery(HugeType.EDGE); + for (Object edgeId : edgeIds) { + HugeEdge edge; + EdgeId id = HugeEdge.getIdValue(edgeId, !verifyId); + if (id == null) { continue; } - // Found from local tx - edges.put(edge.id(), edge); - } else { - // Prepare to query from backend store - query.query(id); + if (id.direction() == Directions.IN) { + id = id.switchDirection(); + } + + boolean foundLocal = false; + if (edgesUpdated) { + if (this.removedEdges.containsKey(id)) { + // The record has been deleted + continue; + } + if ((edge = this.addedEdges.get(id)) != null || + (edge = this.updatedEdges.get(id)) != null) { + if (edge.expired()) { + continue; + } + // Found from local tx + foundLocal = true; + edges.put(edge.id(), edge); + } else { + assert !foundLocal; + } + } + if (!foundLocal) { + // Prepare to query from backend store + query.query(id); + } + ids.add(id); } - ids.add(id); - } - if (!query.empty()) { - // Query from backend store - if (edges.isEmpty() && query.idsSize() == ids.size()) { - /* - * Sort at the lower layer and return directly if there is no - * local vertex and duplicated id. - */ + if (!query.empty()) { + // Query from backend store + if (edges.isEmpty() && query.idsSize() == ids.size()) { + /* + * Sort at the lower layer and return directly if there is + * no local vertex and duplicated id. + */ + Iterator<HugeEdge> it = this.queryEdgesFromBackend(query); + @SuppressWarnings({ "unchecked", "rawtypes" }) + Iterator<Edge> r = (Iterator) it; + return r; + } + + query.mustSortByInput(false); Iterator<HugeEdge> it = this.queryEdgesFromBackend(query); - @SuppressWarnings({"unchecked", "rawtypes"}) - Iterator<Edge> r = (Iterator) it; - return r; + QueryResults.fillMap(it, edges); } - - query.mustSortByInput(false); - Iterator<HugeEdge> it = this.queryEdgesFromBackend(query); - QueryResults.fillMap(it, edges); } return new MapperIterator<>(ids.iterator(), id -> { @@ -993,6 +1135,7 @@ public class GraphTransaction extends IndexableTransaction { }); } + @Watched(prefix = "graph") public Iterator<Edge> queryEdges() { Query q = new Query(HugeType.EDGE); return this.queryEdges(q); @@ -1046,6 +1189,7 @@ public class GraphTransaction extends IndexableTransaction { return this.skipOffsetOrStopLimit(r, query); } + @Watched(prefix = "graph") protected Iterator<HugeEdge> queryEdgesFromBackend(Query query) { assert query.resultType().isEdge(); @@ -1543,7 +1687,7 @@ public class GraphTransaction extends IndexableTransaction { * Just query by primary-key(id), ignore other user-props(if exists) * that it will be filtered by queryVertices(Query) */ - return new IdQuery(query, id); + return new IdQuery.OneIdQuery(query, id); } } }
