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 <jin@apache.org>
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
index 5b2fb1d..94f64f3 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
@@ -565,6 +565,10 @@
return this.value;
}
+ public void value(Object value) {
+ this.value = value;
+ }
+
public void serialKey(Object key) {
this.serialKey = key;
}
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 2f950c2..a438683 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
@@ -540,6 +540,23 @@
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 b25b705..f43557b 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.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;
@@ -1413,8 +1414,7 @@
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);
@@ -1434,11 +1434,10 @@
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);
}
@@ -1448,25 +1447,60 @@
// 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) {
- LOG.debug("Query edges by sortKeys: {}", query);
- return query;
+ 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());
+ }
+ }
+ }
+
+ 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 ca2986d..b262ed0 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
@@ -27,6 +27,7 @@
import org.apache.hugegraph.backend.id.Id;
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.Frequency;
import org.apache.hugegraph.util.E;
@@ -99,6 +100,17 @@
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 e226e38..2555289 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 @@
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);
}