mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 01:22:26 -04:00
Adding mappings to data streams (#129787)
This commit is contained in:
parent
5be4100afa
commit
528bd9c234
9 changed files with 373 additions and 30 deletions
|
@ -54,6 +54,7 @@ import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -261,6 +262,7 @@ public class TransportGetDataStreamsAction extends TransportLocalProjectMetadata
|
||||||
Settings settings = dataStream.getEffectiveSettings(state.metadata());
|
Settings settings = dataStream.getEffectiveSettings(state.metadata());
|
||||||
ilmPolicyName = settings.get(IndexMetadata.LIFECYCLE_NAME);
|
ilmPolicyName = settings.get(IndexMetadata.LIFECYCLE_NAME);
|
||||||
if (indexMode == null && state.metadata().templatesV2().get(indexTemplate) != null) {
|
if (indexMode == null && state.metadata().templatesV2().get(indexTemplate) != null) {
|
||||||
|
try {
|
||||||
indexMode = resolveMode(
|
indexMode = resolveMode(
|
||||||
state,
|
state,
|
||||||
indexSettingProviders,
|
indexSettingProviders,
|
||||||
|
@ -268,6 +270,9 @@ public class TransportGetDataStreamsAction extends TransportLocalProjectMetadata
|
||||||
settings,
|
settings,
|
||||||
dataStream.getEffectiveIndexTemplate(state.metadata())
|
dataStream.getEffectiveIndexTemplate(state.metadata())
|
||||||
);
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
indexTemplatePreferIlmValue = PREFER_ILM_SETTING.get(settings);
|
indexTemplatePreferIlmValue = PREFER_ILM_SETTING.get(settings);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -258,6 +258,7 @@ public class UpdateTimeSeriesRangeServiceTests extends ESTestCase {
|
||||||
2,
|
2,
|
||||||
ds2.getMetadata(),
|
ds2.getMetadata(),
|
||||||
ds2.getSettings(),
|
ds2.getSettings(),
|
||||||
|
ds2.getMappings(),
|
||||||
ds2.isHidden(),
|
ds2.isHidden(),
|
||||||
ds2.isReplicated(),
|
ds2.isReplicated(),
|
||||||
ds2.isSystem(),
|
ds2.isSystem(),
|
||||||
|
|
|
@ -323,6 +323,7 @@ public class TransportVersions {
|
||||||
public static final TransportVersion ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED = def(9_109_00_0);
|
public static final TransportVersion ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED = def(9_109_00_0);
|
||||||
public static final TransportVersion ML_INFERENCE_COHERE_API_VERSION = def(9_110_0_00);
|
public static final TransportVersion ML_INFERENCE_COHERE_API_VERSION = def(9_110_0_00);
|
||||||
public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN = def(9_111_0_00);
|
public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN = def(9_111_0_00);
|
||||||
|
public static final TransportVersion MAPPINGS_IN_DATA_STREAMS = def(9_112_0_00);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* STOP! READ THIS FIRST! No, really,
|
* STOP! READ THIS FIRST! No, really,
|
||||||
|
|
|
@ -19,18 +19,24 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
import org.elasticsearch.core.Nullable;
|
import org.elasticsearch.core.Nullable;
|
||||||
import org.elasticsearch.index.mapper.DataStreamTimestampFieldMapper;
|
import org.elasticsearch.index.mapper.DataStreamTimestampFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
|
import org.elasticsearch.index.mapper.Mapping;
|
||||||
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
||||||
import org.elasticsearch.xcontent.ParseField;
|
import org.elasticsearch.xcontent.ParseField;
|
||||||
import org.elasticsearch.xcontent.ToXContentObject;
|
import org.elasticsearch.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.xcontent.XContentBuilder;
|
import org.elasticsearch.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.xcontent.XContentParser;
|
import org.elasticsearch.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.xcontent.XContentParserConfiguration;
|
||||||
|
import org.elasticsearch.xcontent.XContentType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -51,6 +57,14 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
|
||||||
private static final ParseField ALLOW_AUTO_CREATE = new ParseField("allow_auto_create");
|
private static final ParseField ALLOW_AUTO_CREATE = new ParseField("allow_auto_create");
|
||||||
private static final ParseField IGNORE_MISSING_COMPONENT_TEMPLATES = new ParseField("ignore_missing_component_templates");
|
private static final ParseField IGNORE_MISSING_COMPONENT_TEMPLATES = new ParseField("ignore_missing_component_templates");
|
||||||
private static final ParseField DEPRECATED = new ParseField("deprecated");
|
private static final ParseField DEPRECATED = new ParseField("deprecated");
|
||||||
|
public static final CompressedXContent EMPTY_MAPPINGS;
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
EMPTY_MAPPINGS = new CompressedXContent(Map.of());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static final ConstructingObjectParser<ComposableIndexTemplate, Void> PARSER = new ConstructingObjectParser<>(
|
public static final ConstructingObjectParser<ComposableIndexTemplate, Void> PARSER = new ConstructingObjectParser<>(
|
||||||
|
@ -338,6 +352,64 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
|
||||||
return mergedIndexTemplateBuilder.build();
|
return mergedIndexTemplateBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComposableIndexTemplate mergeMappings(CompressedXContent mappings) throws IOException {
|
||||||
|
Objects.requireNonNull(mappings);
|
||||||
|
if (Mapping.EMPTY.toCompressedXContent().equals(mappings) && this.template() != null && this.template().mappings() != null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
ComposableIndexTemplate.Builder mergedIndexTemplateBuilder = this.toBuilder();
|
||||||
|
Template.Builder mergedTemplateBuilder;
|
||||||
|
CompressedXContent templateMappings;
|
||||||
|
if (this.template() == null) {
|
||||||
|
mergedTemplateBuilder = Template.builder();
|
||||||
|
templateMappings = null;
|
||||||
|
} else {
|
||||||
|
mergedTemplateBuilder = Template.builder(this.template());
|
||||||
|
templateMappings = this.template().mappings();
|
||||||
|
}
|
||||||
|
mergedTemplateBuilder.mappings(templateMappings == null ? mappings : merge(templateMappings, mappings));
|
||||||
|
mergedIndexTemplateBuilder.template(mergedTemplateBuilder);
|
||||||
|
return mergedIndexTemplateBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private CompressedXContent merge(CompressedXContent originalMapping, CompressedXContent mappingAddition) throws IOException {
|
||||||
|
Map<String, Object> mappingAdditionMap = XContentHelper.convertToMap(mappingAddition.uncompressed(), true, XContentType.JSON).v2();
|
||||||
|
Map<String, Object> combinedMappingMap = new HashMap<>();
|
||||||
|
if (originalMapping != null) {
|
||||||
|
Map<String, Object> originalMappingMap = XContentHelper.convertToMap(originalMapping.uncompressed(), true, XContentType.JSON)
|
||||||
|
.v2();
|
||||||
|
if (originalMappingMap.containsKey(MapperService.SINGLE_MAPPING_NAME)) {
|
||||||
|
combinedMappingMap.putAll((Map<String, ?>) originalMappingMap.get(MapperService.SINGLE_MAPPING_NAME));
|
||||||
|
} else {
|
||||||
|
combinedMappingMap.putAll(originalMappingMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XContentHelper.update(combinedMappingMap, mappingAdditionMap, true);
|
||||||
|
return convertMappingMapToXContent(combinedMappingMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CompressedXContent convertMappingMapToXContent(Map<String, Object> rawAdditionalMapping) throws IOException {
|
||||||
|
CompressedXContent compressedXContent;
|
||||||
|
if (rawAdditionalMapping.isEmpty()) {
|
||||||
|
compressedXContent = EMPTY_MAPPINGS;
|
||||||
|
} else {
|
||||||
|
try (var parser = XContentHelper.mapToXContentParser(XContentParserConfiguration.EMPTY, rawAdditionalMapping)) {
|
||||||
|
compressedXContent = mappingFromXContent(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compressedXContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CompressedXContent mappingFromXContent(XContentParser parser) throws IOException {
|
||||||
|
XContentParser.Token token = parser.nextToken();
|
||||||
|
if (token == XContentParser.Token.START_OBJECT) {
|
||||||
|
return new CompressedXContent(Strings.toString(XContentFactory.jsonBuilder().map(parser.mapOrdered())));
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unexpected token: " + token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(
|
return Objects.hash(
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.cluster.metadata.DataStreamLifecycle.DownsamplingRound;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
import org.elasticsearch.common.compress.CompressedXContent;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
@ -47,9 +48,11 @@ import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.mapper.DateFieldMapper;
|
import org.elasticsearch.index.mapper.DateFieldMapper;
|
||||||
import org.elasticsearch.indices.SystemIndices;
|
import org.elasticsearch.indices.SystemIndices;
|
||||||
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
||||||
|
import org.elasticsearch.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.xcontent.ParseField;
|
import org.elasticsearch.xcontent.ParseField;
|
||||||
import org.elasticsearch.xcontent.ToXContentObject;
|
import org.elasticsearch.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.xcontent.XContentBuilder;
|
import org.elasticsearch.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.xcontent.XContentParser;
|
import org.elasticsearch.xcontent.XContentParser;
|
||||||
import org.elasticsearch.xcontent.XContentParserConfiguration;
|
import org.elasticsearch.xcontent.XContentParserConfiguration;
|
||||||
import org.elasticsearch.xcontent.XContentType;
|
import org.elasticsearch.xcontent.XContentType;
|
||||||
|
@ -58,6 +61,7 @@ import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -70,6 +74,7 @@ import java.util.function.LongSupplier;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.elasticsearch.cluster.metadata.ComposableIndexTemplate.EMPTY_MAPPINGS;
|
||||||
import static org.elasticsearch.cluster.metadata.MetadataCreateDataStreamService.lookupTemplateForDataStream;
|
import static org.elasticsearch.cluster.metadata.MetadataCreateDataStreamService.lookupTemplateForDataStream;
|
||||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
|
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
|
||||||
import static org.elasticsearch.index.IndexSettings.LIFECYCLE_ORIGINATION_DATE;
|
import static org.elasticsearch.index.IndexSettings.LIFECYCLE_ORIGINATION_DATE;
|
||||||
|
@ -89,6 +94,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
public static final String FAILURE_STORE_PREFIX = ".fs-";
|
public static final String FAILURE_STORE_PREFIX = ".fs-";
|
||||||
public static final DateFormatter DATE_FORMATTER = DateFormatter.forPattern("uuuu.MM.dd");
|
public static final DateFormatter DATE_FORMATTER = DateFormatter.forPattern("uuuu.MM.dd");
|
||||||
public static final String TIMESTAMP_FIELD_NAME = "@timestamp";
|
public static final String TIMESTAMP_FIELD_NAME = "@timestamp";
|
||||||
|
|
||||||
// Timeseries indices' leaf readers should be sorted by desc order of their timestamp field, as it allows search time optimizations
|
// Timeseries indices' leaf readers should be sorted by desc order of their timestamp field, as it allows search time optimizations
|
||||||
public static final Comparator<LeafReader> TIMESERIES_LEAF_READERS_SORTER = Comparator.comparingLong((LeafReader r) -> {
|
public static final Comparator<LeafReader> TIMESERIES_LEAF_READERS_SORTER = Comparator.comparingLong((LeafReader r) -> {
|
||||||
try {
|
try {
|
||||||
|
@ -120,6 +126,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Map<String, Object> metadata;
|
private final Map<String, Object> metadata;
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
|
private final CompressedXContent mappings;
|
||||||
private final boolean hidden;
|
private final boolean hidden;
|
||||||
private final boolean replicated;
|
private final boolean replicated;
|
||||||
private final boolean system;
|
private final boolean system;
|
||||||
|
@ -156,6 +163,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
Settings.EMPTY,
|
Settings.EMPTY,
|
||||||
|
EMPTY_MAPPINGS,
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -176,6 +184,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
long generation,
|
long generation,
|
||||||
Map<String, Object> metadata,
|
Map<String, Object> metadata,
|
||||||
Settings settings,
|
Settings settings,
|
||||||
|
CompressedXContent mappings,
|
||||||
boolean hidden,
|
boolean hidden,
|
||||||
boolean replicated,
|
boolean replicated,
|
||||||
boolean system,
|
boolean system,
|
||||||
|
@ -192,6 +201,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
settings,
|
settings,
|
||||||
|
mappings,
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -210,6 +220,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
long generation,
|
long generation,
|
||||||
Map<String, Object> metadata,
|
Map<String, Object> metadata,
|
||||||
Settings settings,
|
Settings settings,
|
||||||
|
CompressedXContent mappings,
|
||||||
boolean hidden,
|
boolean hidden,
|
||||||
boolean replicated,
|
boolean replicated,
|
||||||
boolean system,
|
boolean system,
|
||||||
|
@ -225,6 +236,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
this.generation = generation;
|
this.generation = generation;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.settings = Objects.requireNonNull(settings);
|
this.settings = Objects.requireNonNull(settings);
|
||||||
|
this.mappings = Objects.requireNonNull(mappings);
|
||||||
assert system == false || hidden; // system indices must be hidden
|
assert system == false || hidden; // system indices must be hidden
|
||||||
this.hidden = hidden;
|
this.hidden = hidden;
|
||||||
this.replicated = replicated;
|
this.replicated = replicated;
|
||||||
|
@ -286,11 +298,18 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
} else {
|
} else {
|
||||||
settings = Settings.EMPTY;
|
settings = Settings.EMPTY;
|
||||||
}
|
}
|
||||||
|
CompressedXContent mappings;
|
||||||
|
if (in.getTransportVersion().onOrAfter(TransportVersions.MAPPINGS_IN_DATA_STREAMS)) {
|
||||||
|
mappings = CompressedXContent.readCompressedString(in);
|
||||||
|
} else {
|
||||||
|
mappings = EMPTY_MAPPINGS;
|
||||||
|
}
|
||||||
return new DataStream(
|
return new DataStream(
|
||||||
name,
|
name,
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
settings,
|
settings,
|
||||||
|
mappings,
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -381,8 +400,8 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
return backingIndices.rolloverOnWrite;
|
return backingIndices.rolloverOnWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComposableIndexTemplate getEffectiveIndexTemplate(ProjectMetadata projectMetadata) {
|
public ComposableIndexTemplate getEffectiveIndexTemplate(ProjectMetadata projectMetadata) throws IOException {
|
||||||
return getMatchingIndexTemplate(projectMetadata).mergeSettings(settings);
|
return getMatchingIndexTemplate(projectMetadata).mergeSettings(settings).mergeMappings(mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings getEffectiveSettings(ProjectMetadata projectMetadata) {
|
public Settings getEffectiveSettings(ProjectMetadata projectMetadata) {
|
||||||
|
@ -391,6 +410,10 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
return templateSettings.merge(settings);
|
return templateSettings.merge(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompressedXContent getEffectiveMappings(ProjectMetadata projectMetadata) throws IOException {
|
||||||
|
return getMatchingIndexTemplate(projectMetadata).mergeMappings(mappings).template().mappings();
|
||||||
|
}
|
||||||
|
|
||||||
private ComposableIndexTemplate getMatchingIndexTemplate(ProjectMetadata projectMetadata) {
|
private ComposableIndexTemplate getMatchingIndexTemplate(ProjectMetadata projectMetadata) {
|
||||||
return lookupTemplateForDataStream(name, projectMetadata);
|
return lookupTemplateForDataStream(name, projectMetadata);
|
||||||
}
|
}
|
||||||
|
@ -510,6 +533,10 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompressedXContent getMappings() {
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHidden() {
|
public boolean isHidden() {
|
||||||
return hidden;
|
return hidden;
|
||||||
|
@ -1354,6 +1381,9 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
|| out.getTransportVersion().isPatchFrom(TransportVersions.SETTINGS_IN_DATA_STREAMS_8_19)) {
|
|| out.getTransportVersion().isPatchFrom(TransportVersions.SETTINGS_IN_DATA_STREAMS_8_19)) {
|
||||||
settings.writeTo(out);
|
settings.writeTo(out);
|
||||||
}
|
}
|
||||||
|
if (out.getTransportVersion().onOrAfter(TransportVersions.MAPPINGS_IN_DATA_STREAMS)) {
|
||||||
|
mappings.writeTo(out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final ParseField NAME_FIELD = new ParseField("name");
|
public static final ParseField NAME_FIELD = new ParseField("name");
|
||||||
|
@ -1376,6 +1406,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
public static final ParseField FAILURE_AUTO_SHARDING_FIELD = new ParseField("failure_auto_sharding");
|
public static final ParseField FAILURE_AUTO_SHARDING_FIELD = new ParseField("failure_auto_sharding");
|
||||||
public static final ParseField DATA_STREAM_OPTIONS_FIELD = new ParseField("options");
|
public static final ParseField DATA_STREAM_OPTIONS_FIELD = new ParseField("options");
|
||||||
public static final ParseField SETTINGS_FIELD = new ParseField("settings");
|
public static final ParseField SETTINGS_FIELD = new ParseField("settings");
|
||||||
|
public static final ParseField MAPPINGS_FIELD = new ParseField("mappings");
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static final ConstructingObjectParser<DataStream, Void> PARSER = new ConstructingObjectParser<>(
|
private static final ConstructingObjectParser<DataStream, Void> PARSER = new ConstructingObjectParser<>(
|
||||||
|
@ -1385,6 +1416,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
(Long) args[2],
|
(Long) args[2],
|
||||||
(Map<String, Object>) args[3],
|
(Map<String, Object>) args[3],
|
||||||
args[17] == null ? Settings.EMPTY : (Settings) args[17],
|
args[17] == null ? Settings.EMPTY : (Settings) args[17],
|
||||||
|
args[18] == null ? EMPTY_MAPPINGS : (CompressedXContent) args[18],
|
||||||
args[4] != null && (boolean) args[4],
|
args[4] != null && (boolean) args[4],
|
||||||
args[5] != null && (boolean) args[5],
|
args[5] != null && (boolean) args[5],
|
||||||
args[6] != null && (boolean) args[6],
|
args[6] != null && (boolean) args[6],
|
||||||
|
@ -1456,6 +1488,18 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
DATA_STREAM_OPTIONS_FIELD
|
DATA_STREAM_OPTIONS_FIELD
|
||||||
);
|
);
|
||||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> Settings.fromXContent(p), SETTINGS_FIELD);
|
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> Settings.fromXContent(p), SETTINGS_FIELD);
|
||||||
|
PARSER.declareField(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> {
|
||||||
|
XContentParser.Token token = p.currentToken();
|
||||||
|
if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
|
return new CompressedXContent(Base64.getDecoder().decode(p.text()));
|
||||||
|
} else if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) {
|
||||||
|
return new CompressedXContent(p.binaryValue());
|
||||||
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
|
return new CompressedXContent(Strings.toString(XContentFactory.jsonBuilder().map(p.mapOrdered())));
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unexpected token: " + token);
|
||||||
|
}
|
||||||
|
}, MAPPINGS_FIELD, ObjectParser.ValueType.VALUE_OBJECT_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataStream fromXContent(XContentParser parser) throws IOException {
|
public static DataStream fromXContent(XContentParser parser) throws IOException {
|
||||||
|
@ -1520,6 +1564,20 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
builder.startObject(SETTINGS_FIELD.getPreferredName());
|
builder.startObject(SETTINGS_FIELD.getPreferredName());
|
||||||
this.settings.toXContent(builder, params);
|
this.settings.toXContent(builder, params);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
|
String context = params.param(Metadata.CONTEXT_MODE_PARAM, Metadata.CONTEXT_MODE_API);
|
||||||
|
boolean binary = params.paramAsBoolean("binary", false);
|
||||||
|
if (Metadata.CONTEXT_MODE_API.equals(context) || binary == false) {
|
||||||
|
Map<String, Object> uncompressedMapping = XContentHelper.convertToMap(this.mappings.uncompressed(), true, XContentType.JSON)
|
||||||
|
.v2();
|
||||||
|
if (uncompressedMapping.isEmpty() == false) {
|
||||||
|
builder.field(MAPPINGS_FIELD.getPreferredName());
|
||||||
|
builder.map(uncompressedMapping);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.field(MAPPINGS_FIELD.getPreferredName(), mappings.compressed());
|
||||||
|
}
|
||||||
|
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
@ -1864,6 +1922,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
@Nullable
|
@Nullable
|
||||||
private Map<String, Object> metadata = null;
|
private Map<String, Object> metadata = null;
|
||||||
private Settings settings = Settings.EMPTY;
|
private Settings settings = Settings.EMPTY;
|
||||||
|
private CompressedXContent mappings = EMPTY_MAPPINGS;
|
||||||
private boolean hidden = false;
|
private boolean hidden = false;
|
||||||
private boolean replicated = false;
|
private boolean replicated = false;
|
||||||
private boolean system = false;
|
private boolean system = false;
|
||||||
|
@ -1892,6 +1951,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
generation = dataStream.generation;
|
generation = dataStream.generation;
|
||||||
metadata = dataStream.metadata;
|
metadata = dataStream.metadata;
|
||||||
settings = dataStream.settings;
|
settings = dataStream.settings;
|
||||||
|
mappings = dataStream.mappings;
|
||||||
hidden = dataStream.hidden;
|
hidden = dataStream.hidden;
|
||||||
replicated = dataStream.replicated;
|
replicated = dataStream.replicated;
|
||||||
system = dataStream.system;
|
system = dataStream.system;
|
||||||
|
@ -1928,6 +1988,11 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setMappings(CompressedXContent mappings) {
|
||||||
|
this.mappings = mappings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder setHidden(boolean hidden) {
|
public Builder setHidden(boolean hidden) {
|
||||||
this.hidden = hidden;
|
this.hidden = hidden;
|
||||||
return this;
|
return this;
|
||||||
|
@ -1989,6 +2054,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
settings,
|
settings,
|
||||||
|
mappings,
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
|
|
@ -332,6 +332,7 @@ public class MetadataCreateDataStreamService {
|
||||||
initialGeneration,
|
initialGeneration,
|
||||||
template.metadata() != null ? Map.copyOf(template.metadata()) : null,
|
template.metadata() != null ? Map.copyOf(template.metadata()) : null,
|
||||||
Settings.EMPTY,
|
Settings.EMPTY,
|
||||||
|
ComposableIndexTemplate.EMPTY_MAPPINGS,
|
||||||
hidden,
|
hidden,
|
||||||
false,
|
false,
|
||||||
isSystem,
|
isSystem,
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.elasticsearch.cluster.metadata.ComposableIndexTemplate.EMPTY_MAPPINGS;
|
||||||
import static org.elasticsearch.cluster.metadata.DataStream.TIMESTAMP_FIELD_NAME;
|
import static org.elasticsearch.cluster.metadata.DataStream.TIMESTAMP_FIELD_NAME;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -283,9 +284,7 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMergeEmptySettingsIntoTemplateWithNonEmptySettings() {
|
public void testMergeEmptySettingsIntoTemplateWithNonEmptySettings() {
|
||||||
// We only have settings from the template, so the effective template will just be the original template
|
// Attempting to merge in null settings ought to fail
|
||||||
Settings templateSettings = randomSettings();
|
|
||||||
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(randomMappings(null));
|
|
||||||
ComposableIndexTemplate indexTemplate = randomInstance();
|
ComposableIndexTemplate indexTemplate = randomInstance();
|
||||||
expectThrows(NullPointerException.class, () -> indexTemplate.mergeSettings(null));
|
expectThrows(NullPointerException.class, () -> indexTemplate.mergeSettings(null));
|
||||||
assertThat(indexTemplate.mergeSettings(Settings.EMPTY), equalTo(indexTemplate));
|
assertThat(indexTemplate.mergeSettings(Settings.EMPTY), equalTo(indexTemplate));
|
||||||
|
@ -325,12 +324,14 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
|
||||||
.put("index.setting3", "templateValue")
|
.put("index.setting3", "templateValue")
|
||||||
.put("index.setting4", "templateValue")
|
.put("index.setting4", "templateValue")
|
||||||
.build();
|
.build();
|
||||||
|
List<String> componentTemplates = List.of("component_template_1");
|
||||||
CompressedXContent templateMappings = randomMappings(randomDataStreamTemplate());
|
CompressedXContent templateMappings = randomMappings(randomDataStreamTemplate());
|
||||||
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
||||||
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
.indexPatterns(List.of(dataStreamName))
|
.indexPatterns(List.of(dataStreamName))
|
||||||
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
.template(templateBuilder)
|
.template(templateBuilder)
|
||||||
|
.componentTemplates(componentTemplates)
|
||||||
.build();
|
.build();
|
||||||
Settings mergedSettings = Settings.builder()
|
Settings mergedSettings = Settings.builder()
|
||||||
.put("index.setting1", "dataStreamValue")
|
.put("index.setting1", "dataStreamValue")
|
||||||
|
@ -342,7 +343,62 @@ public class ComposableIndexTemplateTests extends SimpleDiffableSerializationTes
|
||||||
.indexPatterns(List.of(dataStreamName))
|
.indexPatterns(List.of(dataStreamName))
|
||||||
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
.template(expectedTemplateBuilder)
|
.template(expectedTemplateBuilder)
|
||||||
|
.componentTemplates(componentTemplates)
|
||||||
.build();
|
.build();
|
||||||
assertThat(indexTemplate.mergeSettings(dataStreamSettings), equalTo(expectedEffectiveTemplate));
|
assertThat(indexTemplate.mergeSettings(dataStreamSettings), equalTo(expectedEffectiveTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMergeEmptyMappingsIntoTemplateWithNonEmptySettings() throws IOException {
|
||||||
|
// Attempting to merge in null mappings ought to fail
|
||||||
|
ComposableIndexTemplate indexTemplate = randomInstance();
|
||||||
|
expectThrows(NullPointerException.class, () -> indexTemplate.mergeMappings(null));
|
||||||
|
assertThat(indexTemplate.mergeMappings(EMPTY_MAPPINGS), equalTo(indexTemplate));
|
||||||
|
assertThat(indexTemplate.mergeSettings(Settings.EMPTY), equalTo(indexTemplate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMergeNonEmptyMappingsIntoTemplateWithEmptyMappings() throws IOException {
|
||||||
|
// We only have settings from the data stream, so we expect to get only those back in the effective template
|
||||||
|
CompressedXContent dataStreamMappings = randomMappings(randomDataStreamTemplate());
|
||||||
|
String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
|
||||||
|
Settings templateSettings = Settings.EMPTY;
|
||||||
|
CompressedXContent templateMappings = new CompressedXContent(Map.of("_doc", Map.of()));
|
||||||
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
||||||
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
|
.indexPatterns(List.of(dataStreamName))
|
||||||
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
.template(templateBuilder)
|
||||||
|
.build();
|
||||||
|
Template.Builder expectedTemplateBuilder = Template.builder().settings(templateSettings).mappings(dataStreamMappings);
|
||||||
|
ComposableIndexTemplate expectedEffectiveTemplate = ComposableIndexTemplate.builder()
|
||||||
|
.indexPatterns(List.of(dataStreamName))
|
||||||
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
.template(expectedTemplateBuilder)
|
||||||
|
.build();
|
||||||
|
assertThat(indexTemplate.mergeMappings(dataStreamMappings), equalTo(expectedEffectiveTemplate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMergeMappings() throws IOException {
|
||||||
|
// Here we have settings from both the template and the data stream, so we expect the data stream settings to take precedence
|
||||||
|
CompressedXContent dataStreamMappings = new CompressedXContent(Map.of());
|
||||||
|
String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
|
||||||
|
CompressedXContent templateMappings = new CompressedXContent(Map.of("_doc", Map.of()));
|
||||||
|
Settings templateSettings = randomSettings();
|
||||||
|
List<String> componentTemplates = List.of("component_template_1");
|
||||||
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
||||||
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
|
.indexPatterns(List.of(dataStreamName))
|
||||||
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
.template(templateBuilder)
|
||||||
|
.componentTemplates(componentTemplates)
|
||||||
|
.build();
|
||||||
|
Template.Builder expectedTemplateBuilder = Template.builder().settings(templateSettings).mappings(EMPTY_MAPPINGS);
|
||||||
|
ComposableIndexTemplate expectedEffectiveTemplate = ComposableIndexTemplate.builder()
|
||||||
|
.indexPatterns(List.of(dataStreamName))
|
||||||
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
.template(expectedTemplateBuilder)
|
||||||
|
.componentTemplates(componentTemplates)
|
||||||
|
.build();
|
||||||
|
ComposableIndexTemplate merged = indexTemplate.mergeMappings(dataStreamMappings);
|
||||||
|
assertThat(merged, equalTo(expectedEffectiveTemplate));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,6 @@ import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.elasticsearch.cluster.metadata.ComponentTemplateTests.randomMappings;
|
|
||||||
import static org.elasticsearch.cluster.metadata.DataStream.getDefaultBackingIndexName;
|
import static org.elasticsearch.cluster.metadata.DataStream.getDefaultBackingIndexName;
|
||||||
import static org.elasticsearch.cluster.metadata.DataStream.getDefaultFailureStoreName;
|
import static org.elasticsearch.cluster.metadata.DataStream.getDefaultFailureStoreName;
|
||||||
import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.newInstance;
|
import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.newInstance;
|
||||||
|
@ -98,6 +97,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
var generation = instance.getGeneration();
|
var generation = instance.getGeneration();
|
||||||
var metadata = instance.getMetadata();
|
var metadata = instance.getMetadata();
|
||||||
var settings = instance.getSettings();
|
var settings = instance.getSettings();
|
||||||
|
var mappings = instance.getMappings();
|
||||||
var isHidden = instance.isHidden();
|
var isHidden = instance.isHidden();
|
||||||
var isReplicated = instance.isReplicated();
|
var isReplicated = instance.isReplicated();
|
||||||
var isSystem = instance.isSystem();
|
var isSystem = instance.isSystem();
|
||||||
|
@ -110,7 +110,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
var autoShardingEvent = instance.getAutoShardingEvent();
|
var autoShardingEvent = instance.getAutoShardingEvent();
|
||||||
var failureRolloverOnWrite = instance.getFailureComponent().isRolloverOnWrite();
|
var failureRolloverOnWrite = instance.getFailureComponent().isRolloverOnWrite();
|
||||||
var failureAutoShardingEvent = instance.getDataComponent().getAutoShardingEvent();
|
var failureAutoShardingEvent = instance.getDataComponent().getAutoShardingEvent();
|
||||||
switch (between(0, 16)) {
|
switch (between(0, 17)) {
|
||||||
case 0 -> name = randomAlphaOfLength(10);
|
case 0 -> name = randomAlphaOfLength(10);
|
||||||
case 1 -> indices = randomNonEmptyIndexInstances();
|
case 1 -> indices = randomNonEmptyIndexInstances();
|
||||||
case 2 -> generation = instance.getGeneration() + randomIntBetween(1, 10);
|
case 2 -> generation = instance.getGeneration() + randomIntBetween(1, 10);
|
||||||
|
@ -179,6 +179,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
? null
|
? null
|
||||||
: new DataStreamAutoShardingEvent(indices.getLast().getName(), randomIntBetween(1, 10), randomMillisUpToYear9999());
|
: new DataStreamAutoShardingEvent(indices.getLast().getName(), randomIntBetween(1, 10), randomMillisUpToYear9999());
|
||||||
case 16 -> settings = randomValueOtherThan(settings, DataStreamTestHelper::randomSettings);
|
case 16 -> settings = randomValueOtherThan(settings, DataStreamTestHelper::randomSettings);
|
||||||
|
case 17 -> mappings = randomValueOtherThan(mappings, ComponentTemplateTests::randomMappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DataStream(
|
return new DataStream(
|
||||||
|
@ -186,6 +187,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
settings,
|
settings,
|
||||||
|
mappings,
|
||||||
isHidden,
|
isHidden,
|
||||||
isReplicated,
|
isReplicated,
|
||||||
isSystem,
|
isSystem,
|
||||||
|
@ -1948,6 +1950,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
isSystem,
|
isSystem,
|
||||||
randomBoolean(),
|
randomBoolean(),
|
||||||
isSystem,
|
isSystem,
|
||||||
|
@ -2141,6 +2144,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
randomNonNegativeInt(),
|
randomNonNegativeInt(),
|
||||||
null,
|
null,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -2160,6 +2164,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
randomNonNegativeInt(),
|
randomNonNegativeInt(),
|
||||||
null,
|
null,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -2186,6 +2191,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
randomNonNegativeInt(),
|
randomNonNegativeInt(),
|
||||||
null,
|
null,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -2211,6 +2217,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
randomNonNegativeInt(),
|
randomNonNegativeInt(),
|
||||||
null,
|
null,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -2234,6 +2241,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
randomNonNegativeInt(),
|
randomNonNegativeInt(),
|
||||||
null,
|
null,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -2266,6 +2274,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
randomNonNegativeInt(),
|
randomNonNegativeInt(),
|
||||||
null,
|
null,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
hidden,
|
hidden,
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -2529,13 +2538,31 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
.indexPatterns(List.of(dataStream.getName()))
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
.template(templateBuilder)
|
.template(templateBuilder)
|
||||||
|
.componentTemplates(List.of("component-template-1"))
|
||||||
.build();
|
.build();
|
||||||
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
||||||
.indexTemplates(Map.of(dataStream.getName(), indexTemplate));
|
.indexTemplates(Map.of(dataStream.getName(), indexTemplate))
|
||||||
|
.componentTemplates(
|
||||||
|
Map.of(
|
||||||
|
"component-template-1",
|
||||||
|
new ComponentTemplate(
|
||||||
|
Template.builder()
|
||||||
|
.settings(
|
||||||
|
Settings.builder()
|
||||||
|
.put("index.setting1", "componentTemplateValue")
|
||||||
|
.put("index.setting5", "componentTemplateValue")
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
1L,
|
||||||
|
Map.of()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
Settings mergedSettings = Settings.builder()
|
Settings mergedSettings = Settings.builder()
|
||||||
.put("index.setting1", "dataStreamValue")
|
.put("index.setting1", "dataStreamValue")
|
||||||
.put("index.setting2", "dataStreamValue")
|
.put("index.setting2", "dataStreamValue")
|
||||||
.put("index.setting4", "templateValue")
|
.put("index.setting4", "templateValue")
|
||||||
|
.put("index.setting5", "componentTemplateValue")
|
||||||
.build();
|
.build();
|
||||||
assertThat(dataStream.getEffectiveSettings(projectMetadataBuilder.build()), equalTo(mergedSettings));
|
assertThat(dataStream.getEffectiveSettings(projectMetadataBuilder.build()), equalTo(mergedSettings));
|
||||||
}
|
}
|
||||||
|
@ -2547,28 +2574,40 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
assertThrows(IllegalArgumentException.class, () -> dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()));
|
assertThrows(IllegalArgumentException.class, () -> dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetEffectiveIndexTemplateTemplateSettingsOnly() {
|
public void testGetEffectiveIndexTemplateTemplateNoOverrides() throws IOException {
|
||||||
// We only have settings from the template, so the effective template will just be the original template
|
// We only have settings and mappings from the template, so the effective template will just be the original template
|
||||||
DataStream dataStream = createDataStream(Settings.EMPTY);
|
DataStream dataStream = createDataStream(Settings.EMPTY, ComposableIndexTemplate.EMPTY_MAPPINGS);
|
||||||
Settings templateSettings = randomSettings();
|
Settings templateSettings = randomSettings();
|
||||||
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(randomMappings());
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(randomMappings());
|
||||||
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
.indexPatterns(List.of(dataStream.getName()))
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
.template(templateBuilder)
|
.template(templateBuilder)
|
||||||
|
.componentTemplates(List.of("component-template-1"))
|
||||||
.build();
|
.build();
|
||||||
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
||||||
.indexTemplates(Map.of(dataStream.getName(), indexTemplate));
|
.indexTemplates(Map.of(dataStream.getName(), indexTemplate))
|
||||||
|
.componentTemplates(
|
||||||
|
Map.of(
|
||||||
|
"component-template-1",
|
||||||
|
new ComponentTemplate(
|
||||||
|
Template.builder().settings(Settings.builder().put("index.setting5", "componentTemplateValue")).build(),
|
||||||
|
1L,
|
||||||
|
Map.of()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(indexTemplate));
|
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(indexTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetEffectiveIndexTemplateDataStreamSettingsOnly() {
|
public void testGetEffectiveIndexTemplateDataStreamSettingsOnly() throws IOException {
|
||||||
// We only have settings from the data stream, so we expect to get only those back in the effective template
|
// We only have settings from the data stream, so we expect to get only those back in the effective template
|
||||||
Settings dataStreamSettings = randomSettings();
|
Settings dataStreamSettings = randomSettings();
|
||||||
DataStream dataStream = createDataStream(dataStreamSettings);
|
DataStream dataStream = createDataStream(dataStreamSettings, ComposableIndexTemplate.EMPTY_MAPPINGS);
|
||||||
Settings templateSettings = Settings.EMPTY;
|
Settings templateSettings = Settings.EMPTY;
|
||||||
CompressedXContent templateMappings = randomMappings();
|
CompressedXContent templateMappings = randomMappings();
|
||||||
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
||||||
|
|
||||||
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
.indexPatterns(List.of(dataStream.getName()))
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
@ -2585,20 +2624,80 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(expectedEffectiveTemplate));
|
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(expectedEffectiveTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetEffectiveIndexTemplate() {
|
public void testGetEffectiveIndexTemplate() throws IOException {
|
||||||
// Here we have settings from both the template and the data stream, so we expect the data stream settings to take precedence
|
// Here we have settings from both the template and the data stream, so we expect the data stream settings to take precedence
|
||||||
Settings dataStreamSettings = Settings.builder()
|
Settings dataStreamSettings = Settings.builder()
|
||||||
.put("index.setting1", "dataStreamValue")
|
.put("index.setting1", "dataStreamValue")
|
||||||
.put("index.setting2", "dataStreamValue")
|
.put("index.setting2", "dataStreamValue")
|
||||||
.put("index.setting3", (String) null) // This one gets removed from the effective settings
|
.put("index.setting3", (String) null) // This one gets removed from the effective settings
|
||||||
.build();
|
.build();
|
||||||
DataStream dataStream = createDataStream(dataStreamSettings);
|
CompressedXContent dataStreamMappings = new CompressedXContent(
|
||||||
|
Map.of("properties", Map.of("field2", Map.of("type", "text"), "field3", Map.of("type", "keyword")))
|
||||||
|
);
|
||||||
|
DataStream dataStream = createDataStream(dataStreamSettings, dataStreamMappings);
|
||||||
Settings templateSettings = Settings.builder()
|
Settings templateSettings = Settings.builder()
|
||||||
.put("index.setting1", "templateValue")
|
.put("index.setting1", "templateValue")
|
||||||
.put("index.setting3", "templateValue")
|
.put("index.setting3", "templateValue")
|
||||||
.put("index.setting4", "templateValue")
|
.put("index.setting4", "templateValue")
|
||||||
.build();
|
.build();
|
||||||
CompressedXContent templateMappings = randomMappings();
|
CompressedXContent templateMappings = new CompressedXContent(
|
||||||
|
Map.of("_doc", Map.of("properties", Map.of("field1", Map.of("type", "keyword"), "field2", Map.of("type", "keyword"))))
|
||||||
|
);
|
||||||
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
||||||
|
List<String> componentTemplates = List.of("component-template-1");
|
||||||
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
.template(templateBuilder)
|
||||||
|
.componentTemplates(componentTemplates)
|
||||||
|
.build();
|
||||||
|
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
||||||
|
.indexTemplates(Map.of(dataStream.getName(), indexTemplate))
|
||||||
|
.componentTemplates(
|
||||||
|
Map.of(
|
||||||
|
"component-template-1",
|
||||||
|
new ComponentTemplate(
|
||||||
|
Template.builder().settings(Settings.builder().put("index.setting5", "componentTemplateValue")).build(),
|
||||||
|
1L,
|
||||||
|
Map.of()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Settings mergedSettings = Settings.builder()
|
||||||
|
.put("index.setting1", "dataStreamValue")
|
||||||
|
.put("index.setting2", "dataStreamValue")
|
||||||
|
.put("index.setting4", "templateValue")
|
||||||
|
.build();
|
||||||
|
CompressedXContent mergedMappings = new CompressedXContent(
|
||||||
|
Map.of(
|
||||||
|
"properties",
|
||||||
|
Map.of("field1", Map.of("type", "keyword"), "field2", Map.of("type", "text"), "field3", Map.of("type", "keyword"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Template.Builder expectedTemplateBuilder = Template.builder().settings(mergedSettings).mappings(mergedMappings);
|
||||||
|
ComposableIndexTemplate expectedEffectiveTemplate = ComposableIndexTemplate.builder()
|
||||||
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
.template(expectedTemplateBuilder)
|
||||||
|
.componentTemplates(componentTemplates)
|
||||||
|
.build();
|
||||||
|
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(expectedEffectiveTemplate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetEffectiveMappingsNoMatchingTemplate() {
|
||||||
|
// No matching template, so we expect an IllegalArgumentException
|
||||||
|
DataStream dataStream = createTestInstance();
|
||||||
|
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault());
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> dataStream.getEffectiveMappings(projectMetadataBuilder.build()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetEffectiveIndexTemplateDataStreamMappingsOnly() throws IOException {
|
||||||
|
// We only have mappings from the data stream, so we expect to get only those back in the effective template
|
||||||
|
CompressedXContent dataStreamMappings = randomMappings();
|
||||||
|
DataStream dataStream = createDataStream(Settings.EMPTY, dataStreamMappings);
|
||||||
|
Settings templateSettings = Settings.EMPTY;
|
||||||
|
CompressedXContent templateMappings = new CompressedXContent(Map.of("_doc", Map.of()));
|
||||||
|
;
|
||||||
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
Template.Builder templateBuilder = Template.builder().settings(templateSettings).mappings(templateMappings);
|
||||||
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
ComposableIndexTemplate indexTemplate = ComposableIndexTemplate.builder()
|
||||||
.indexPatterns(List.of(dataStream.getName()))
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
|
@ -2607,12 +2706,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
.build();
|
.build();
|
||||||
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
ProjectMetadata.Builder projectMetadataBuilder = ProjectMetadata.builder(randomProjectIdOrDefault())
|
||||||
.indexTemplates(Map.of(dataStream.getName(), indexTemplate));
|
.indexTemplates(Map.of(dataStream.getName(), indexTemplate));
|
||||||
Settings mergedSettings = Settings.builder()
|
Template.Builder expectedTemplateBuilder = Template.builder().settings(templateSettings).mappings(dataStreamMappings);
|
||||||
.put("index.setting1", "dataStreamValue")
|
|
||||||
.put("index.setting2", "dataStreamValue")
|
|
||||||
.put("index.setting4", "templateValue")
|
|
||||||
.build();
|
|
||||||
Template.Builder expectedTemplateBuilder = Template.builder().settings(mergedSettings).mappings(templateMappings);
|
|
||||||
ComposableIndexTemplate expectedEffectiveTemplate = ComposableIndexTemplate.builder()
|
ComposableIndexTemplate expectedEffectiveTemplate = ComposableIndexTemplate.builder()
|
||||||
.indexPatterns(List.of(dataStream.getName()))
|
.indexPatterns(List.of(dataStream.getName()))
|
||||||
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
|
||||||
|
@ -2621,11 +2715,30 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(expectedEffectiveTemplate));
|
assertThat(dataStream.getEffectiveIndexTemplate(projectMetadataBuilder.build()), equalTo(expectedEffectiveTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CompressedXContent randomMappings() {
|
||||||
|
try {
|
||||||
|
return new CompressedXContent("{\"_doc\": {\"properties\":{\"" + randomAlphaOfLength(5) + "\":{\"type\":\"keyword\"}}}}");
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail("got an IO exception creating fake mappings: " + e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DataStream createDataStream(Settings settings) {
|
private DataStream createDataStream(Settings settings) {
|
||||||
DataStream dataStream = createTestInstance();
|
DataStream dataStream = createTestInstance();
|
||||||
return dataStream.copy().setSettings(settings).build();
|
return dataStream.copy().setSettings(settings).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataStream createDataStream(CompressedXContent mappings) {
|
||||||
|
DataStream dataStream = createTestInstance();
|
||||||
|
return dataStream.copy().setMappings(mappings).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataStream createDataStream(Settings settings, CompressedXContent mappings) {
|
||||||
|
DataStream dataStream = createTestInstance();
|
||||||
|
return dataStream.copy().setSettings(settings).setMappings(mappings).build();
|
||||||
|
}
|
||||||
|
|
||||||
private record DataStreamMetadata(Long creationTimeInMillis, Long rolloverTimeInMillis, Long originationTimeInMillis) {
|
private record DataStreamMetadata(Long creationTimeInMillis, Long rolloverTimeInMillis, Long originationTimeInMillis) {
|
||||||
public static DataStreamMetadata dataStreamMetadata(Long creationTimeInMillis, Long rolloverTimeInMillis) {
|
public static DataStreamMetadata dataStreamMetadata(Long creationTimeInMillis, Long rolloverTimeInMillis) {
|
||||||
return new DataStreamMetadata(creationTimeInMillis, rolloverTimeInMillis, null);
|
return new DataStreamMetadata(creationTimeInMillis, rolloverTimeInMillis, null);
|
||||||
|
@ -2669,4 +2782,19 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
|
||||||
builder.put(im, false);
|
builder.put(im, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ToXContent.Params getToXContentParams() {
|
||||||
|
if (randomBoolean()) {
|
||||||
|
return ToXContent.EMPTY_PARAMS;
|
||||||
|
}
|
||||||
|
return new ToXContent.MapParams(
|
||||||
|
Map.of(
|
||||||
|
"binary",
|
||||||
|
randomFrom("true", "false"),
|
||||||
|
Metadata.CONTEXT_MODE_PARAM,
|
||||||
|
randomFrom(Metadata.XContentContext.values()).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.cluster.routing.allocation.AllocationService;
|
||||||
import org.elasticsearch.cluster.routing.allocation.WriteLoadForecaster;
|
import org.elasticsearch.cluster.routing.allocation.WriteLoadForecaster;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
import org.elasticsearch.common.UUIDs;
|
import org.elasticsearch.common.UUIDs;
|
||||||
|
import org.elasticsearch.common.compress.CompressedXContent;
|
||||||
import org.elasticsearch.common.settings.IndexScopedSettings;
|
import org.elasticsearch.common.settings.IndexScopedSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.core.CheckedFunction;
|
import org.elasticsearch.core.CheckedFunction;
|
||||||
|
@ -58,6 +59,7 @@ import org.hamcrest.Description;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -85,6 +87,7 @@ import static org.elasticsearch.test.ESTestCase.randomIntBetween;
|
||||||
import static org.elasticsearch.test.ESTestCase.randomMap;
|
import static org.elasticsearch.test.ESTestCase.randomMap;
|
||||||
import static org.elasticsearch.test.ESTestCase.randomMillisUpToYear9999;
|
import static org.elasticsearch.test.ESTestCase.randomMillisUpToYear9999;
|
||||||
import static org.elasticsearch.test.ESTestCase.randomPositiveTimeValue;
|
import static org.elasticsearch.test.ESTestCase.randomPositiveTimeValue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -365,6 +368,7 @@ public final class DataStreamTestHelper {
|
||||||
generation,
|
generation,
|
||||||
metadata,
|
metadata,
|
||||||
randomSettings(),
|
randomSettings(),
|
||||||
|
randomMappings(),
|
||||||
system ? true : randomBoolean(),
|
system ? true : randomBoolean(),
|
||||||
replicated,
|
replicated,
|
||||||
system,
|
system,
|
||||||
|
@ -400,6 +404,15 @@ public final class DataStreamTestHelper {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CompressedXContent randomMappings() {
|
||||||
|
try {
|
||||||
|
return new CompressedXContent("{\"properties\":{\"" + randomAlphaOfLength(5) + "\":{\"type\":\"keyword\"}}}");
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail("got an IO exception creating fake mappings: " + e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static DataStreamAlias randomAliasInstance() {
|
public static DataStreamAlias randomAliasInstance() {
|
||||||
List<String> dataStreams = List.of(generateRandomStringArray(5, 5, false, false));
|
List<String> dataStreams = List.of(generateRandomStringArray(5, 5, false, false));
|
||||||
return new DataStreamAlias(
|
return new DataStreamAlias(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue