forked from hugegraph/hugegraph-sync
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>
This commit is contained in:
parent
dfee5bf6aa
commit
d0f63c8ac3
|
|
@ -565,6 +565,10 @@ public abstract class Condition {
|
|||
return this.value;
|
||||
}
|
||||
|
||||
public void value(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void serialKey(Object key) {
|
||||
this.serialKey = key;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -540,6 +540,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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -1413,8 +1414,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);
|
||||
|
|
@ -1434,11 +1434,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);
|
||||
}
|
||||
|
|
@ -1448,25 +1447,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) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.apache.hugegraph.HugeGraph;
|
|||
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 @@ 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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue