Skip to content

Commit d0f63c8

Browse files
Z-HUANTimbajin
andauthored
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>
1 parent dfee5bf commit d0f63c8

File tree

5 files changed

+93
-26
lines changed

5 files changed

+93
-26
lines changed

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java

+4
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,10 @@ public Object value() {
565565
return this.value;
566566
}
567567

568+
public void value(Object value) {
569+
this.value = value;
570+
}
571+
568572
public void serialKey(Object key) {
569573
this.serialKey = key;
570574
}

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java

+17
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,23 @@ public ConditionQuery copyAndResetUnshared() {
540540
return query;
541541
}
542542

543+
public Condition.Relation copyRelationAndUpdateQuery(Object key) {
544+
Condition.Relation copyRes = null;
545+
for (int i = 0; i < this.conditions.size(); i++) {
546+
Condition c = this.conditions.get(i);
547+
if (c.isRelation()) {
548+
Condition.Relation r = (Condition.Relation) c;
549+
if (r.key().equals(key)) {
550+
copyRes = r.copy();
551+
this.conditions.set(i, copyRes);
552+
break;
553+
}
554+
}
555+
}
556+
E.checkArgument(copyRes != null, "Failed to copy Condition.Relation: %s", key);
557+
return copyRes;
558+
}
559+
543560
@Override
544561
public boolean test(HugeElement element) {
545562
if (!this.ids().isEmpty() && !super.test(element)) {

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java

+58-24
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.function.BiFunction;
3030
import java.util.function.Consumer;
3131
import java.util.function.Function;
32+
import java.util.stream.Collectors;
3233

3334
import org.apache.commons.collections.CollectionUtils;
3435
import org.apache.hugegraph.HugeException;
@@ -1413,8 +1414,7 @@ private <R> QueryList<R> optimizeQueries(Query query,
14131414

14141415
private Query optimizeQuery(ConditionQuery query) {
14151416
if (query.idsSize() > 0) {
1416-
throw new HugeException(
1417-
"Not supported querying by id and conditions: %s", query);
1417+
throw new HugeException("Not supported querying by id and conditions: %s", query);
14181418
}
14191419

14201420
Id label = query.condition(HugeKeys.LABEL);
@@ -1434,11 +1434,10 @@ private Query optimizeQuery(ConditionQuery query) {
14341434
String primaryValues = query.userpropValuesString(keys);
14351435
LOG.debug("Query vertices by primaryKeys: {}", query);
14361436
// Convert {vertex-label + primary-key} to vertex-id
1437-
Id id = SplicingIdGenerator.splicing(label.asString(),
1438-
primaryValues);
1437+
Id id = SplicingIdGenerator.splicing(label.asString(), primaryValues);
14391438
/*
1440-
* Just query by primary-key(id), ignore other userprop(if
1441-
* exists) that it will be filtered by queryVertices(Query)
1439+
* Just query by primary-key(id), ignore other user-props(if exists)
1440+
* that it will be filtered by queryVertices(Query)
14421441
*/
14431442
return new IdQuery(query, id);
14441443
}
@@ -1448,25 +1447,60 @@ private Query optimizeQuery(ConditionQuery query) {
14481447
// Optimize edge query
14491448
if (query.resultType().isEdge() && label != null &&
14501449
query.condition(HugeKeys.OWNER_VERTEX) != null &&
1451-
query.condition(HugeKeys.DIRECTION) != null &&
1452-
matchEdgeSortKeys(query, false, this.graph())) {
1453-
// Query edge by sourceVertex + direction + label + sort-values
1454-
query.optimized(OptimizedType.SORT_KEYS);
1455-
query = query.copy();
1456-
// Serialize sort-values
1457-
List<Id> keys = this.graph().edgeLabel(label).sortKeys();
1458-
List<Condition> conditions =
1459-
GraphIndexTransaction.constructShardConditions(
1460-
query, keys, HugeKeys.SORT_VALUES);
1461-
query.query(conditions);
1462-
/*
1463-
* Reset all userprop since transferred to sort-keys, ignore other
1464-
* userprop(if exists) that it will be filtered by queryEdges(Query)
1465-
*/
1466-
query.resetUserpropConditions();
1450+
query.condition(HugeKeys.DIRECTION) != null) {
1451+
1452+
Directions dir = query.condition(HugeKeys.DIRECTION);
1453+
EdgeLabel edgeLabel = this.graph().edgeLabel(label);
1454+
1455+
if (query.containsRelation(HugeKeys.OWNER_VERTEX, Condition.RelationType.IN)) {
1456+
// For IN query, filter schema non-adjacent vertices.
1457+
ArrayList<Id> vertexIdList = query.condition(HugeKeys.OWNER_VERTEX);
1458+
List<Id> filterVertexList = vertexIdList.stream().filter(vertexId -> {
1459+
Vertex vertex = this.graph().vertex(vertexId);
1460+
VertexLabel vertexLabel = graph().vertexLabel(vertex.label());
1461+
return edgeLabel.linkWithVertexLabel(vertexLabel.id(), dir);
1462+
}).collect(Collectors.toList());
1463+
1464+
if (CollectionUtils.isEmpty(filterVertexList)) {
1465+
return new Query(query.resultType());
1466+
}
1467+
1468+
if (vertexIdList.size() != filterVertexList.size()) {
1469+
// Modify on the copied relation to avoid affecting other query
1470+
Condition.Relation relation =
1471+
query.copyRelationAndUpdateQuery(HugeKeys.OWNER_VERTEX);
1472+
relation.value(filterVertexList);
1473+
}
1474+
} else if (query.containsRelation(HugeKeys.OWNER_VERTEX, Condition.RelationType.EQ)) {
1475+
Id vertexId = query.condition(HugeKeys.OWNER_VERTEX);
1476+
Vertex vertex = QueryResults.one(this.queryVertices(vertexId));
1477+
if (vertex != null) {
1478+
VertexLabel vertexLabel = graph().vertexLabel(vertex.label());
1479+
// For EQ query, just skip query storage if adjacent schema doesn't exist
1480+
if (!edgeLabel.linkWithVertexLabel(vertexLabel.id(), dir)) {
1481+
return new Query(query.resultType());
1482+
}
1483+
}
1484+
}
14671485

1468-
LOG.debug("Query edges by sortKeys: {}", query);
1469-
return query;
1486+
if (matchEdgeSortKeys(query, false, this.graph())) {
1487+
// Query edge by sourceVertex + direction + label + sort-values
1488+
query.optimized(OptimizedType.SORT_KEYS);
1489+
query = query.copy();
1490+
// Serialize sort-values
1491+
List<Id> keys = this.graph().edgeLabel(label).sortKeys();
1492+
List<Condition> conditions = GraphIndexTransaction
1493+
.constructShardConditions(query, keys, HugeKeys.SORT_VALUES);
1494+
query.query(conditions);
1495+
/*
1496+
* Reset all userprop since transferred to sort-keys, ignore other
1497+
* userprop(if exists) that it will be filtered by queryEdges(Query)
1498+
*/
1499+
query.resetUserpropConditions();
1500+
1501+
LOG.debug("Query edges by sortKeys: {}", query);
1502+
return query;
1503+
}
14701504
}
14711505

14721506
/*

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.hugegraph.backend.id.Id;
2828
import org.apache.hugegraph.schema.builder.SchemaBuilder;
2929
import org.apache.hugegraph.type.HugeType;
30+
import org.apache.hugegraph.type.define.Directions;
3031
import org.apache.hugegraph.type.define.Frequency;
3132
import org.apache.hugegraph.util.E;
3233

@@ -99,6 +100,17 @@ public boolean linkWithLabel(Id id) {
99100
return this.sourceLabel.equals(id) || this.targetLabel.equals(id);
100101
}
101102

103+
public boolean linkWithVertexLabel(Id label, Directions dir) {
104+
if (dir.equals(Directions.IN)) {
105+
return this.targetLabel.equals(label);
106+
} else if (dir.equals(Directions.OUT)) {
107+
return this.sourceLabel.equals(label);
108+
} else if (dir.equals(Directions.BOTH)) {
109+
return this.targetLabel.equals(label) || this.sourceLabel.equals(label);
110+
}
111+
return false;
112+
}
113+
102114
public boolean checkLinkEqual(Id sourceLabel, Id targetLabel) {
103115
return this.sourceLabel.equals(sourceLabel) &&
104116
this.targetLabel.equals(targetLabel);

hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ private static HugeGraph initGraph(String configPath) throws Exception {
9898
try {
9999
BackendStoreInfo backendStoreInfo = graph.backendStoreInfo();
100100
if (backendStoreInfo.exists()) {
101-
LOG.info("Skip init-store due to the backend store of '{}' " +
102-
"had been initialized", graph.name());
103101
backendStoreInfo.checkVersion();
104102
/*
105103
* Init the required information for creating the admin account
106104
* (when switch from non-auth mode to auth mode)
107105
*/
108106
graph.initSystemInfo();
107+
LOG.info("Skip init-store due to the backend store of '{}' " +
108+
"had been initialized", graph.name());
109109
} else {
110110
initBackend(graph);
111111
}

0 commit comments

Comments
 (0)