|
@@ -23,6 +23,7 @@ import org.elasticsearch.cluster.service.ClusterService;
|
|
|
import org.elasticsearch.common.Strings;
|
|
|
import org.elasticsearch.common.inject.Inject;
|
|
|
import org.elasticsearch.common.util.concurrent.CountDown;
|
|
|
+import org.elasticsearch.common.util.set.Sets;
|
|
|
import org.elasticsearch.core.Tuple;
|
|
|
import org.elasticsearch.index.shard.ShardId;
|
|
|
import org.elasticsearch.indices.IndicesService;
|
|
@@ -36,14 +37,17 @@ import org.elasticsearch.transport.TransportService;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Optional;
|
|
|
import java.util.Set;
|
|
|
+import java.util.TreeMap;
|
|
|
import java.util.function.Consumer;
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
+import java.util.stream.Stream;
|
|
|
|
|
|
import static org.elasticsearch.action.search.TransportSearchHelper.checkCCSVersionCompatibility;
|
|
|
|
|
@@ -229,43 +233,57 @@ public class TransportFieldCapabilitiesAction extends HandledTransportAction<Fie
|
|
|
FieldCapabilitiesRequest request,
|
|
|
List<FieldCapabilitiesFailure> failures
|
|
|
) {
|
|
|
- final List<FieldCapabilitiesIndexResponse> indexResponses = indexResponsesMap.values()
|
|
|
- .stream()
|
|
|
- .sorted(Comparator.comparing(FieldCapabilitiesIndexResponse::getIndexName))
|
|
|
- .toList();
|
|
|
- final String[] indices = indexResponses.stream().map(FieldCapabilitiesIndexResponse::getIndexName).toArray(String[]::new);
|
|
|
- final Map<String, Map<String, FieldCapabilities.Builder>> responseMapBuilder = new HashMap<>();
|
|
|
- for (FieldCapabilitiesIndexResponse response : indexResponses) {
|
|
|
+ Map<String, FieldCapabilitiesIndexResponse> responses = new TreeMap<>(indexResponsesMap);
|
|
|
+ Map<String, Map<String, FieldCapabilities.Builder>> responseMapBuilder = new HashMap<>();
|
|
|
+ for (FieldCapabilitiesIndexResponse response : responses.values()) {
|
|
|
innerMerge(responseMapBuilder, request, response);
|
|
|
}
|
|
|
- final Map<String, Map<String, FieldCapabilities>> responseMap = new HashMap<>();
|
|
|
+
|
|
|
+ Map<String, Map<String, FieldCapabilities>> responseMap = new HashMap<>();
|
|
|
for (Map.Entry<String, Map<String, FieldCapabilities.Builder>> entry : responseMapBuilder.entrySet()) {
|
|
|
- final Map<String, FieldCapabilities.Builder> typeMapBuilder = entry.getValue();
|
|
|
+ Map<String, FieldCapabilities.Builder> typeMapBuilder = entry.getValue();
|
|
|
+
|
|
|
+ Optional<Function<Boolean, FieldCapabilities>> unmapped = Optional.empty();
|
|
|
if (request.includeUnmapped()) {
|
|
|
- addUnmappedFields(indices, entry.getKey(), typeMapBuilder);
|
|
|
- }
|
|
|
- boolean multiTypes = typeMapBuilder.size() > 1;
|
|
|
- final Map<String, FieldCapabilities> typeMap = new HashMap<>();
|
|
|
- for (Map.Entry<String, FieldCapabilities.Builder> fieldEntry : typeMapBuilder.entrySet()) {
|
|
|
- typeMap.put(fieldEntry.getKey(), fieldEntry.getValue().build(multiTypes));
|
|
|
+ // do this directly, rather than using the builder, to save creating a whole lot of objects we don't need
|
|
|
+ unmapped = getUnmappedFields(
|
|
|
+ responses.keySet(),
|
|
|
+ entry.getKey(),
|
|
|
+ typeMapBuilder.values().stream().flatMap(FieldCapabilities.Builder::getIndices).collect(Collectors.toSet())
|
|
|
+ );
|
|
|
}
|
|
|
- responseMap.put(entry.getKey(), Collections.unmodifiableMap(typeMap));
|
|
|
+
|
|
|
+ boolean multiTypes = typeMapBuilder.size() + unmapped.map(f -> 1).orElse(0) > 1;
|
|
|
+ responseMap.put(
|
|
|
+ entry.getKey(),
|
|
|
+ Collections.unmodifiableMap(
|
|
|
+ Stream.concat(
|
|
|
+ typeMapBuilder.entrySet()
|
|
|
+ .stream()
|
|
|
+ .map(e -> Map.<String, Function<Boolean, FieldCapabilities>>entry(e.getKey(), e.getValue()::build)),
|
|
|
+ unmapped.stream().map(f -> Map.entry("unmapped", f))
|
|
|
+ ).collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().apply(multiTypes)))
|
|
|
+ )
|
|
|
+ );
|
|
|
}
|
|
|
- return new FieldCapabilitiesResponse(indices, Collections.unmodifiableMap(responseMap), failures);
|
|
|
+ return new FieldCapabilitiesResponse(responses.keySet().toArray(String[]::new), Collections.unmodifiableMap(responseMap), failures);
|
|
|
}
|
|
|
|
|
|
- private static void addUnmappedFields(String[] indices, String field, Map<String, FieldCapabilities.Builder> typeMap) {
|
|
|
- final Set<String> mappedIndices = new HashSet<>();
|
|
|
- typeMap.values().forEach(t -> t.getIndices(mappedIndices));
|
|
|
- if (mappedIndices.size() != indices.length) {
|
|
|
- final FieldCapabilities.Builder unmapped = new FieldCapabilities.Builder(field, "unmapped");
|
|
|
- for (String index : indices) {
|
|
|
- if (mappedIndices.contains(index) == false) {
|
|
|
- unmapped.add(index, false, false, false, false, null, Collections.emptyMap());
|
|
|
- }
|
|
|
- }
|
|
|
- typeMap.put("unmapped", unmapped);
|
|
|
+ private static Optional<Function<Boolean, FieldCapabilities>> getUnmappedFields(
|
|
|
+ Set<String> indices,
|
|
|
+ String field,
|
|
|
+ Set<String> mappedIndices
|
|
|
+ ) {
|
|
|
+ if (mappedIndices.size() != indices.size()) {
|
|
|
+ return Optional.of(
|
|
|
+ mt -> FieldCapabilities.buildBasic(
|
|
|
+ field,
|
|
|
+ "unmapped",
|
|
|
+ mt ? Sets.difference(indices, mappedIndices).toArray(String[]::new) : null
|
|
|
+ )
|
|
|
+ );
|
|
|
}
|
|
|
+ return Optional.empty();
|
|
|
}
|
|
|
|
|
|
private void innerMerge(
|