All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.action.fieldcaps.FieldCapabilitiesFetcher Maven / Gradle / Ivy

There is a newer version: 8.13.4
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

package org.elasticsearch.action.fieldcaps;

import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.ObjectMapper;
import org.elasticsearch.index.mapper.RuntimeField;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.search.SearchService;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.internal.AliasFilter;
import org.elasticsearch.search.internal.ShardSearchRequest;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

/**
 * Loads the mappings for an index and computes all {@link IndexFieldCapabilities}. This
 * helper class performs the core shard operation for the field capabilities action.
 */
class FieldCapabilitiesFetcher {
    private final IndicesService indicesService;
    private final IndexFieldCapabilities.Deduplicator fieldDeduplicator;

    FieldCapabilitiesFetcher(IndicesService indicesService) {
        this.indicesService = indicesService;
        this.fieldDeduplicator = new IndexFieldCapabilities.Deduplicator();
    }

    public FieldCapabilitiesIndexResponse fetch(final FieldCapabilitiesIndexRequest request) throws IOException {
        final ShardId shardId = request.shardId();
        final IndexService indexService = indicesService.indexServiceSafe(shardId.getIndex());
        final IndexShard indexShard = indexService.getShard(request.shardId().getId());
        try (Engine.Searcher searcher = indexShard.acquireSearcher(Engine.CAN_MATCH_SEARCH_SOURCE)) {

            final SearchExecutionContext searchExecutionContext = indexService.newSearchExecutionContext(
                shardId.id(),
                0,
                searcher,
                request::nowInMillis,
                null,
                request.runtimeFields()
            );

            if (canMatchShard(request, searchExecutionContext) == false) {
                return new FieldCapabilitiesIndexResponse(request.index(), Collections.emptyList(), false);
            }

            Set fieldNames = new HashSet<>();
            for (String pattern : request.fields()) {
                fieldNames.addAll(searchExecutionContext.getMatchingFieldNames(pattern));
            }

            Predicate fieldPredicate = indicesService.getFieldFilter().apply(shardId.getIndexName());
            Map responseMap = new HashMap<>();
            for (String field : fieldNames) {
                MappedFieldType ft = searchExecutionContext.getFieldType(field);
                boolean isMetadataField = searchExecutionContext.isMetadataField(field);
                if (isMetadataField || fieldPredicate.test(ft.name())) {
                    IndexFieldCapabilities fieldCap = new IndexFieldCapabilities(
                        field,
                        ft.familyTypeName(),
                        isMetadataField,
                        ft.isSearchable(),
                        ft.isAggregatable(),
                        ft.meta()
                    );
                    responseMap.put(field, fieldDeduplicator.deduplicate(fieldCap));
                } else {
                    continue;
                }

                // Check the ancestor of the field to find nested and object fields.
                // Runtime fields are excluded since they can override any path.
                // TODO find a way to do this that does not require an instanceof check
                if (ft instanceof RuntimeField == false) {
                    int dotIndex = ft.name().lastIndexOf('.');
                    while (dotIndex > -1) {
                        String parentField = ft.name().substring(0, dotIndex);
                        if (responseMap.containsKey(parentField)) {
                            // we added this path on another field already
                            break;
                        }
                        // checks if the parent field contains sub-fields
                        if (searchExecutionContext.getFieldType(parentField) == null) {
                            // no field type, it must be an object field
                            ObjectMapper mapper = searchExecutionContext.getObjectMapper(parentField);
                            // Composite runtime fields do not have a mapped type for the root - check for null
                            if (mapper != null) {
                                String type = mapper.isNested() ? "nested" : "object";
                                IndexFieldCapabilities fieldCap = new IndexFieldCapabilities(
                                    parentField,
                                    type,
                                    false,
                                    false,
                                    false,
                                    Collections.emptyMap()
                                );
                                responseMap.put(parentField, fieldDeduplicator.deduplicate(fieldCap));
                            }
                        }
                        dotIndex = parentField.lastIndexOf('.');
                    }
                }
            }
            return new FieldCapabilitiesIndexResponse(request.index(), responseMap.values(), true);
        }
    }

    private boolean canMatchShard(FieldCapabilitiesIndexRequest req, SearchExecutionContext searchExecutionContext) throws IOException {
        if (req.indexFilter() == null || req.indexFilter() instanceof MatchAllQueryBuilder) {
            return true;
        }
        assert req.nowInMillis() != 0L;
        ShardSearchRequest searchRequest = new ShardSearchRequest(req.shardId(), null, req.nowInMillis(), AliasFilter.EMPTY);
        searchRequest.source(new SearchSourceBuilder().query(req.indexFilter()));
        return SearchService.queryStillMatchesAfterRewrite(searchRequest, searchExecutionContext);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy