From e89cef2a962b063414fc681af4e74c6db462c6ef Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Fri, 11 Feb 2022 17:07:13 +0100 Subject: [PATCH 1/2] Render Mappings more Compact in GET /_cluster/state This deduplicates index mappings in the `/_cluster_state` response. This significantly reduces the response size for large cluster states, making this debug API easier to read for humans (because understanding whether or not mappings are duplicated across indices might be valuable) and more importantly less ressource hungry as far as serialization goes. --- .../cluster/metadata/IndexMetadata.java | 28 ++++++++++++------- .../cluster/metadata/MappingMetadata.java | 3 +- .../cluster/metadata/Metadata.java | 11 ++++++++ .../admin/cluster/RestClusterStateAction.java | 12 ++++---- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetadata.java index 9b0169fe83c32..b0a82a596e45a 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetadata.java @@ -1763,18 +1763,26 @@ public static void toXContent(IndexMetadata indexMetadata, XContentBuilder build } builder.endArray(); } else { - builder.startObject(KEY_MAPPINGS); - MappingMetadata mmd = indexMetadata.mapping(); - if (mmd != null) { - Map mapping = XContentHelper.convertToMap(mmd.source().uncompressed(), false).v2(); - if (mapping.size() == 1 && mapping.containsKey(mmd.type())) { - // the type name is the root value, reduce it - mapping = (Map) mapping.get(mmd.type()); + final MappingMetadata mmd = indexMetadata.mapping(); + if (params.paramAsBoolean(Metadata.MAPPINGS_BY_HASH_PARAM, true)) { + if (mmd == null) { + builder.nullField(KEY_MAPPINGS); + } else { + builder.field(KEY_MAPPINGS, indexMetadata.mapping().getSha256()); } - builder.field(mmd.type()); - builder.map(mapping); + } else { + builder.startObject(KEY_MAPPINGS); + if (mmd != null) { + Map mapping = mmd.sourceAsMap(); + if (mapping.size() == 1 && mapping.containsKey(mmd.type())) { + // the type name is the root value, reduce it + mapping = (Map) mapping.get(mmd.type()); + } + builder.field(mmd.type()); + builder.map(mapping); + } + builder.endObject(); } - builder.endObject(); } for (Map.Entry cursor : indexMetadata.customData.entrySet()) { diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MappingMetadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MappingMetadata.java index 460a0edc320a2..a308e94aef61b 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MappingMetadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MappingMetadata.java @@ -19,6 +19,7 @@ import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.xcontent.XContentType; import java.io.IOException; import java.io.UncheckedIOException; @@ -126,7 +127,7 @@ public CompressedXContent source() { */ @SuppressWarnings("unchecked") public Map sourceAsMap() throws ElasticsearchParseException { - Map mapping = XContentHelper.convertToMap(source.compressedReference(), true).v2(); + Map mapping = XContentHelper.convertToMap(source.compressedReference(), true, XContentType.JSON).v2(); if (mapping.size() == 1 && mapping.containsKey(type())) { // the type name is the root value, reduce it mapping = (Map) mapping.get(type()); diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java index 975d68bdea9c8..b57dc7c875481 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java @@ -94,6 +94,8 @@ public class Metadata implements Iterable, Diffable, To public static final String ALL = "_all"; public static final String UNKNOWN_CLUSTER_UUID = "_na_"; + public static final String MAPPINGS_BY_HASH_PARAM = "mappings_by_hash"; + public enum XContentContext { /* Custom metadata should be returns as part of API call */ API, @@ -2124,6 +2126,15 @@ public static void toXContent(Metadata metadata, XContentBuilder builder, ToXCon builder.endObject(); if (context == XContentContext.API) { + if (params.paramAsBoolean(MAPPINGS_BY_HASH_PARAM, true)) { + builder.startObject("mappings"); + for (Map.Entry mappingEntry : metadata.getMappingsByHash().entrySet()) { + builder.startObject(mappingEntry.getKey()); + builder.mapContents(mappingEntry.getValue().sourceAsMap()); + builder.endObject(); + } + builder.endObject(); + } builder.startObject("indices"); for (IndexMetadata indexMetadata : metadata) { IndexMetadata.Builder.toXContent(indexMetadata, builder, params); diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterStateAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterStateAction.java index 6bd955fc218a0..5670da1390abb 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterStateAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterStateAction.java @@ -30,18 +30,18 @@ import org.elasticsearch.xcontent.XContentBuilder; import java.io.IOException; -import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.LongSupplier; -import static java.util.Collections.singletonMap; import static org.elasticsearch.rest.RestRequest.Method.GET; public class RestClusterStateAction extends BaseRestHandler { + public static final Map TO_XCONTENT_PARAMS = Map.of(Metadata.CONTEXT_MODE_PARAM, Metadata.CONTEXT_MODE_API); private final SettingsFilter settingsFilter; private final ThreadPool threadPool; @@ -116,10 +116,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC ) { @Override protected ToXContent.Params getParams() { - return new ToXContent.DelegatingMapParams( - singletonMap(Metadata.CONTEXT_MODE_PARAM, Metadata.CONTEXT_MODE_API), - request - ); + return new ToXContent.DelegatingMapParams(TO_XCONTENT_PARAMS, request); } }.map(response -> new RestClusterStateResponse(clusterStateRequest, response, threadPool::relativeTimeInMillis)) ); @@ -130,8 +127,9 @@ protected ToXContent.Params getParams() { static { final Set responseParams = new HashSet<>(); responseParams.add("metric"); + responseParams.add(Metadata.MAPPINGS_BY_HASH_PARAM); responseParams.addAll(Settings.FORMAT_PARAMS); - RESPONSE_PARAMS = Collections.unmodifiableSet(responseParams); + RESPONSE_PARAMS = Set.copyOf(responseParams); } @Override From a785817e41029545362eeb7c3072f9285372d97d Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Fri, 11 Feb 2022 19:04:58 +0100 Subject: [PATCH 2/2] Update docs/changelog/83846.yaml --- docs/changelog/83846.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changelog/83846.yaml diff --git a/docs/changelog/83846.yaml b/docs/changelog/83846.yaml new file mode 100644 index 0000000000000..b84f77e1da09a --- /dev/null +++ b/docs/changelog/83846.yaml @@ -0,0 +1,5 @@ +pr: 83846 +summary: Render Mappings more Compact in GET /_cluster/state +area: Cluster Coordination +type: enhancement +issues: []