in hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java [1519:1661]
private Query optimizeQuery(ConditionQuery query) {
if (query.idsSize() > 0) {
throw new HugeException("Not supported querying by id and conditions: %s", query);
}
Id label = query.condition(HugeKeys.LABEL);
// Optimize vertex query
if (label != null && query.resultType().isVertex()) {
VertexLabel vertexLabel = this.graph().vertexLabel(label);
if (vertexLabel.idStrategy() == IdStrategy.PRIMARY_KEY) {
List<Id> keys = vertexLabel.primaryKeys();
E.checkState(!keys.isEmpty(),
"The primary keys can't be empty when using " +
"'%s' id strategy for vertex label '%s'",
IdStrategy.PRIMARY_KEY, vertexLabel.name());
if (query.matchUserpropKeys(keys)) {
// Query vertex by label + primary-values
query.optimized(OptimizedType.PRIMARY_KEY);
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);
/*
* 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);
}
}
}
// Optimize edge query
if (query.resultType().isEdge() && label != null &&
query.condition(HugeKeys.OWNER_VERTEX) != null &&
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 another 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
EdgeLabel el = this.graph().edgeLabel(label);
List<Id> keys = el.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();
if (this.storeFeatures().supportsFatherAndSubEdgeLabel() &&
query.condition(HugeKeys.SUB_LABEL) == null) {
query.eq(HugeKeys.SUB_LABEL, el.id());
}
LOG.debug("Query edges by sortKeys: {}", query);
return query;
}
}
/*
* Query only by sysprops, like: by vertex label, by edge label.
* NOTE: we assume sysprops would be indexed by backend store,
* but we don't support query edges only by direction/target-vertex.
*/
if (query.allSysprop()) {
if (query.resultType().isVertex()) {
verifyVerticesConditionQuery(query);
} else if (query.resultType().isEdge()) {
// fix org.apache.hugegraph.api.traverser.EdgeExistenceAPITest#testEdgeExistenceGet
// add sub label if only the sub label is missing
ConditionQuery finalQuery = query;
if (this.storeFeatures().supportsFatherAndSubEdgeLabel() &&
query.condition(HugeKeys.SUB_LABEL) == null &&
Arrays.stream(EdgeId.KEYS)
.filter(key -> !Objects.equals(key, HugeKeys.SUB_LABEL))
.allMatch(key -> finalQuery.condition(key) != null)) {
EdgeLabel el = this.graph().edgeLabel(label);
if (!el.isFather()) {
query.eq(HugeKeys.SUB_LABEL, el.id());
}
}
verifyEdgesConditionQuery(query);
}
/*
* Just support:
* 1.not query by label
* 2.or query by label and store supports this feature
*/
boolean byLabel = (label != null && query.conditionsSize() == 1);
if (!byLabel || this.store().features().supportsQueryByLabel()) {
if (this.storeFeatures().supportsFatherAndSubEdgeLabel() && byLabel &&
query.resultType().isEdge()) {
// for memory backend
EdgeLabel edgeLabel = graph().edgeLabel(label);
if (edgeLabel.hasFather()) {
query.resetConditions();
query.eq(HugeKeys.LABEL, edgeLabel.fatherId());
query.eq(HugeKeys.SUB_LABEL, edgeLabel.id());
}
}
return query;
}
}
return null;
}