You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by vg...@apache.org on 2024/02/26 10:26:22 UTC

(incubator-hugegraph) branch pd-store updated: feat(api): optimize adjacent-edges query (#2408)

This is an automated email from the ASF dual-hosted git repository.

vgalaxies pushed a commit to branch pd-store
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git


The following commit(s) were added to refs/heads/pd-store by this push:
     new 3b9507001 feat(api): optimize adjacent-edges query (#2408)
3b9507001 is described below

commit 3b9507001ef9f9a540914379361f1c50649ebb7e
Author: Z-HUANT <55...@users.noreply.github.com>
AuthorDate: Mon Feb 26 12:29:13 2024 +0800

    feat(api): optimize adjacent-edges query (#2408)
    
    Relevant issue: #2255
    
    Gremlin Query: For adjacency edge queries, if a vertex does not belong to the adjacent vertices of this edge, filter out that vertex.
    
    ---------
    
    Co-authored-by: imbajin <ji...@apache.org>
---
 .../hugegraph/backend/query/ConditionQuery.java    | 17 +++++
 .../hugegraph/backend/tx/GraphTransaction.java     | 82 +++++++++++++++-------
 .../org/apache/hugegraph/schema/EdgeLabel.java     | 12 ++++
 .../java/org/apache/hugegraph/cmd/InitStore.java   |  4 +-
 4 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
index c9cca5266..0fe2c1219 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
@@ -589,6 +589,23 @@ public class ConditionQuery extends IdQuery {
         return query;
     }
 
+    public Condition.Relation copyRelationAndUpdateQuery(Object key) {
+        Condition.Relation copyRes = null;
+        for (int i = 0; i < this.conditions.size(); i++) {
+            Condition c = this.conditions.get(i);
+            if (c.isRelation()) {
+                Condition.Relation r = (Condition.Relation) c;
+                if (r.key().equals(key)) {
+                    copyRes = r.copy();
+                    this.conditions.set(i, copyRes);
+                    break;
+                }
+            }
+        }
+        E.checkArgument(copyRes != null, "Failed to copy Condition.Relation: %s", key);
+        return copyRes;
+    }
+
     @Override
     public boolean test(HugeElement element) {
         if (!this.ids().isEmpty() && !super.test(element)) {
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 5fe3dec37..10aa73f71 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
@@ -29,6 +29,7 @@ import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.hugegraph.HugeException;
@@ -1447,8 +1448,7 @@ public class GraphTransaction extends IndexableTransaction {
 
     private Query optimizeQuery(ConditionQuery query) {
         if (query.idsSize() > 0) {
-            throw new HugeException(
-                    "Not supported querying by id and conditions: %s", query);
+            throw new HugeException("Not supported querying by id and conditions: %s", query);
         }
 
         Id label = query.condition(HugeKeys.LABEL);
@@ -1468,11 +1468,10 @@ public class GraphTransaction extends IndexableTransaction {
                     String primaryValues = query.userpropValuesString(keys);
                     LOG.debug("Query vertices by primaryKeys: {}", query);
                     // Convert {vertex-label + primary-key} to vertex-id
-                    Id id = SplicingIdGenerator.splicing(label.asString(),
-                                                         primaryValues);
+                    Id id = SplicingIdGenerator.splicing(label.asString(), primaryValues);
                     /*
-                     * Just query by primary-key(id), ignore other userprop(if
-                     * exists) that it will be filtered by queryVertices(Query)
+                     * 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);
                 }
@@ -1482,25 +1481,60 @@ public class GraphTransaction extends IndexableTransaction {
         // Optimize edge query
         if (query.resultType().isEdge() && label != null &&
             query.condition(HugeKeys.OWNER_VERTEX) != null &&
-            query.condition(HugeKeys.DIRECTION) != null &&
-            matchEdgeSortKeys(query, false, this.graph())) {
-            // Query edge by sourceVertex + direction + label + sort-values
-            query.optimized(OptimizedType.SORT_KEYS);
-            query = query.copy();
-            // Serialize sort-values
-            List<Id> keys = this.graph().edgeLabel(label).sortKeys();
-            List<Condition> conditions =
-                    GraphIndexTransaction.constructShardConditions(
-                            query, keys, HugeKeys.SORT_VALUES);
-            query.query(conditions);
-            /*
-             * Reset all userprop since transferred to sort-keys, ignore other
-             * userprop(if exists) that it will be filtered by queryEdges(Query)
-             */
-            query.resetUserpropConditions();
+            query.condition(HugeKeys.DIRECTION) != null) {
+
+            Directions dir = query.condition(HugeKeys.DIRECTION);
+            EdgeLabel edgeLabel = this.graph().edgeLabel(label);
+
+            if (query.containsRelation(HugeKeys.OWNER_VERTEX, Condition.RelationType.IN)) {
+                // For IN query, filter schema non-adjacent vertices.
+                ArrayList<Id> vertexIdList = query.condition(HugeKeys.OWNER_VERTEX);
+                List<Id> filterVertexList = vertexIdList.stream().filter(vertexId -> {
+                    Vertex vertex = this.graph().vertex(vertexId);
+                    VertexLabel vertexLabel = graph().vertexLabel(vertex.label());
+                    return edgeLabel.linkWithVertexLabel(vertexLabel.id(), dir);
+                }).collect(Collectors.toList());
+
+                if (CollectionUtils.isEmpty(filterVertexList)) {
+                    return new Query(query.resultType());
+                }
+
+                if (vertexIdList.size() != filterVertexList.size()) {
+                    // Modify on the copied relation to avoid affecting other query
+                    Condition.Relation relation = 
+                            query.copyRelationAndUpdateQuery(HugeKeys.OWNER_VERTEX);
+                    relation.value(filterVertexList);
+                }
+            } else if (query.containsRelation(HugeKeys.OWNER_VERTEX, Condition.RelationType.EQ)) {
+                Id vertexId = query.condition(HugeKeys.OWNER_VERTEX);
+                Vertex vertex = QueryResults.one(this.queryVertices(vertexId));
+                if (vertex != null) {
+                    VertexLabel vertexLabel = graph().vertexLabel(vertex.label());
+                    // For EQ query, just skip query storage if adjacent schema doesn't exist
+                    if (!edgeLabel.linkWithVertexLabel(vertexLabel.id(), dir)) {
+                        return new Query(query.resultType());
+                    }
+                }
+            }
 
-            LOG.debug("Query edges by sortKeys: {}", query);
-            return query;
+            if (matchEdgeSortKeys(query, false, this.graph())) {
+                // Query edge by sourceVertex + direction + label + sort-values
+                query.optimized(OptimizedType.SORT_KEYS);
+                query = query.copy();
+                // Serialize sort-values
+                List<Id> keys = this.graph().edgeLabel(label).sortKeys();
+                List<Condition> conditions = GraphIndexTransaction
+                        .constructShardConditions(query, keys, HugeKeys.SORT_VALUES);
+                query.query(conditions);
+                /*
+                 * Reset all userprop since transferred to sort-keys, ignore other
+                 * userprop(if exists) that it will be filtered by queryEdges(Query)
+                 */
+                query.resetUserpropConditions();
+
+                LOG.debug("Query edges by sortKeys: {}", query);
+                return query;
+            }
         }
 
         /*
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
index 8a9b184e2..b9fac4643 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
@@ -31,6 +31,7 @@ import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.schema.builder.SchemaBuilder;
 import org.apache.hugegraph.type.HugeType;
+import org.apache.hugegraph.type.define.Directions;
 import org.apache.hugegraph.type.define.EdgeLabelType;
 import org.apache.hugegraph.type.define.Frequency;
 import org.apache.hugegraph.type.define.SchemaStatus;
@@ -110,6 +111,17 @@ public class EdgeLabel extends SchemaLabel {
         return this.sourceLabel.equals(id) || this.targetLabel.equals(id);
     }
 
+    public boolean linkWithVertexLabel(Id label, Directions dir) {
+        if (dir.equals(Directions.IN)) {
+            return this.targetLabel.equals(label);
+        } else if (dir.equals(Directions.OUT)) {
+            return this.sourceLabel.equals(label);
+        } else if (dir.equals(Directions.BOTH)) {
+            return this.targetLabel.equals(label) || this.sourceLabel.equals(label);
+        }
+        return false;
+    }
+
     public boolean checkLinkEqual(Id sourceLabel, Id targetLabel) {
         return this.sourceLabel.equals(sourceLabel) &&
                this.targetLabel.equals(targetLabel);
diff --git a/hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java b/hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java
index e226e381f..255528932 100644
--- a/hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java
+++ b/hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java
@@ -98,14 +98,14 @@ public class InitStore {
         try {
             BackendStoreInfo backendStoreInfo = graph.backendStoreInfo();
             if (backendStoreInfo.exists()) {
-                LOG.info("Skip init-store due to the backend store of '{}' " +
-                         "had been initialized", graph.name());
                 backendStoreInfo.checkVersion();
                 /*
                  * Init the required information for creating the admin account
                  * (when switch from non-auth mode to auth mode)
                  */
                 graph.initSystemInfo();
+                LOG.info("Skip init-store due to the backend store of '{}' " +
+                         "had been initialized", graph.name());
             } else {
                 initBackend(graph);
             }