private Query optimizeQuery()

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;
    }