2929import org .elasticsearch .common .ParsingException ;
3030import org .elasticsearch .common .Strings ;
3131import org .elasticsearch .common .bytes .BytesReference ;
32+ import org .elasticsearch .common .compress .CompressedXContent ;
3233import org .elasticsearch .common .io .stream .StreamInput ;
3334import org .elasticsearch .common .io .stream .StreamOutput ;
3435import org .elasticsearch .common .settings .Settings ;
4748import org .elasticsearch .index .mapper .DateFieldMapper ;
4849import org .elasticsearch .indices .SystemIndices ;
4950import org .elasticsearch .xcontent .ConstructingObjectParser ;
51+ import org .elasticsearch .xcontent .ObjectParser ;
5052import org .elasticsearch .xcontent .ParseField ;
5153import org .elasticsearch .xcontent .ToXContentObject ;
5254import org .elasticsearch .xcontent .XContentBuilder ;
55+ import org .elasticsearch .xcontent .XContentFactory ;
5356import org .elasticsearch .xcontent .XContentParser ;
5457import org .elasticsearch .xcontent .XContentParserConfiguration ;
5558import org .elasticsearch .xcontent .XContentType ;
5861import java .time .Instant ;
5962import java .time .temporal .ChronoUnit ;
6063import java .util .ArrayList ;
64+ import java .util .Base64 ;
6165import java .util .Comparator ;
6266import java .util .HashMap ;
6367import java .util .List ;
7074import java .util .function .Predicate ;
7175import java .util .stream .Collectors ;
7276
77+ import static org .elasticsearch .cluster .metadata .ComposableIndexTemplate .EMPTY_MAPPINGS ;
7378import static org .elasticsearch .cluster .metadata .MetadataCreateDataStreamService .lookupTemplateForDataStream ;
7479import static org .elasticsearch .common .xcontent .XContentParserUtils .ensureExpectedToken ;
7580import static org .elasticsearch .index .IndexSettings .LIFECYCLE_ORIGINATION_DATE ;
@@ -89,6 +94,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
8994 public static final String FAILURE_STORE_PREFIX = ".fs-" ;
9095 public static final DateFormatter DATE_FORMATTER = DateFormatter .forPattern ("uuuu.MM.dd" );
9196 public static final String TIMESTAMP_FIELD_NAME = "@timestamp" ;
97+
9298 // Timeseries indices' leaf readers should be sorted by desc order of their timestamp field, as it allows search time optimizations
9399 public static final Comparator <LeafReader > TIMESERIES_LEAF_READERS_SORTER = Comparator .comparingLong ((LeafReader r ) -> {
94100 try {
@@ -120,6 +126,7 @@ public final class DataStream implements SimpleDiffable<DataStream>, ToXContentO
120126 @ Nullable
121127 private final Map <String , Object > metadata ;
122128 private final Settings settings ;
129+ private final CompressedXContent mappings ;
123130 private final boolean hidden ;
124131 private final boolean replicated ;
125132 private final boolean system ;
@@ -156,6 +163,7 @@ public DataStream(
156163 generation ,
157164 metadata ,
158165 Settings .EMPTY ,
166+ EMPTY_MAPPINGS ,
159167 hidden ,
160168 replicated ,
161169 system ,
@@ -176,6 +184,7 @@ public DataStream(
176184 long generation ,
177185 Map <String , Object > metadata ,
178186 Settings settings ,
187+ CompressedXContent mappings ,
179188 boolean hidden ,
180189 boolean replicated ,
181190 boolean system ,
@@ -192,6 +201,7 @@ public DataStream(
192201 generation ,
193202 metadata ,
194203 settings ,
204+ mappings ,
195205 hidden ,
196206 replicated ,
197207 system ,
@@ -210,6 +220,7 @@ public DataStream(
210220 long generation ,
211221 Map <String , Object > metadata ,
212222 Settings settings ,
223+ CompressedXContent mappings ,
213224 boolean hidden ,
214225 boolean replicated ,
215226 boolean system ,
@@ -225,6 +236,7 @@ public DataStream(
225236 this .generation = generation ;
226237 this .metadata = metadata ;
227238 this .settings = Objects .requireNonNull (settings );
239+ this .mappings = Objects .requireNonNull (mappings );
228240 assert system == false || hidden ; // system indices must be hidden
229241 this .hidden = hidden ;
230242 this .replicated = replicated ;
@@ -286,11 +298,18 @@ public static DataStream read(StreamInput in) throws IOException {
286298 } else {
287299 settings = Settings .EMPTY ;
288300 }
301+ CompressedXContent mappings ;
302+ if (in .getTransportVersion ().onOrAfter (TransportVersions .MAPPINGS_IN_DATA_STREAMS )) {
303+ mappings = CompressedXContent .readCompressedString (in );
304+ } else {
305+ mappings = EMPTY_MAPPINGS ;
306+ }
289307 return new DataStream (
290308 name ,
291309 generation ,
292310 metadata ,
293311 settings ,
312+ mappings ,
294313 hidden ,
295314 replicated ,
296315 system ,
@@ -381,8 +400,8 @@ public boolean rolloverOnWrite() {
381400 return backingIndices .rolloverOnWrite ;
382401 }
383402
384- public ComposableIndexTemplate getEffectiveIndexTemplate (ProjectMetadata projectMetadata ) {
385- return getMatchingIndexTemplate (projectMetadata ).mergeSettings (settings );
403+ public ComposableIndexTemplate getEffectiveIndexTemplate (ProjectMetadata projectMetadata ) throws IOException {
404+ return getMatchingIndexTemplate (projectMetadata ).mergeSettings (settings ). mergeMappings ( mappings ) ;
386405 }
387406
388407 public Settings getEffectiveSettings (ProjectMetadata projectMetadata ) {
@@ -391,6 +410,10 @@ public Settings getEffectiveSettings(ProjectMetadata projectMetadata) {
391410 return templateSettings .merge (settings );
392411 }
393412
413+ public CompressedXContent getEffectiveMappings (ProjectMetadata projectMetadata ) throws IOException {
414+ return getMatchingIndexTemplate (projectMetadata ).mergeMappings (mappings ).template ().mappings ();
415+ }
416+
394417 private ComposableIndexTemplate getMatchingIndexTemplate (ProjectMetadata projectMetadata ) {
395418 return lookupTemplateForDataStream (name , projectMetadata );
396419 }
@@ -510,6 +533,10 @@ public Settings getSettings() {
510533 return settings ;
511534 }
512535
536+ public CompressedXContent getMappings () {
537+ return mappings ;
538+ }
539+
513540 @ Override
514541 public boolean isHidden () {
515542 return hidden ;
@@ -1354,6 +1381,9 @@ public void writeTo(StreamOutput out) throws IOException {
13541381 || out .getTransportVersion ().isPatchFrom (TransportVersions .SETTINGS_IN_DATA_STREAMS_8_19 )) {
13551382 settings .writeTo (out );
13561383 }
1384+ if (out .getTransportVersion ().onOrAfter (TransportVersions .MAPPINGS_IN_DATA_STREAMS )) {
1385+ mappings .writeTo (out );
1386+ }
13571387 }
13581388
13591389 public static final ParseField NAME_FIELD = new ParseField ("name" );
@@ -1376,6 +1406,7 @@ public void writeTo(StreamOutput out) throws IOException {
13761406 public static final ParseField FAILURE_AUTO_SHARDING_FIELD = new ParseField ("failure_auto_sharding" );
13771407 public static final ParseField DATA_STREAM_OPTIONS_FIELD = new ParseField ("options" );
13781408 public static final ParseField SETTINGS_FIELD = new ParseField ("settings" );
1409+ public static final ParseField MAPPINGS_FIELD = new ParseField ("mappings" );
13791410
13801411 @ SuppressWarnings ("unchecked" )
13811412 private static final ConstructingObjectParser <DataStream , Void > PARSER = new ConstructingObjectParser <>(
@@ -1385,6 +1416,7 @@ public void writeTo(StreamOutput out) throws IOException {
13851416 (Long ) args [2 ],
13861417 (Map <String , Object >) args [3 ],
13871418 args [17 ] == null ? Settings .EMPTY : (Settings ) args [17 ],
1419+ args [18 ] == null ? EMPTY_MAPPINGS : (CompressedXContent ) args [18 ],
13881420 args [4 ] != null && (boolean ) args [4 ],
13891421 args [5 ] != null && (boolean ) args [5 ],
13901422 args [6 ] != null && (boolean ) args [6 ],
@@ -1456,6 +1488,18 @@ public void writeTo(StreamOutput out) throws IOException {
14561488 DATA_STREAM_OPTIONS_FIELD
14571489 );
14581490 PARSER .declareObject (ConstructingObjectParser .optionalConstructorArg (), (p , c ) -> Settings .fromXContent (p ), SETTINGS_FIELD );
1491+ PARSER .declareField (ConstructingObjectParser .optionalConstructorArg (), (p , c ) -> {
1492+ XContentParser .Token token = p .currentToken ();
1493+ if (token == XContentParser .Token .VALUE_STRING ) {
1494+ return new CompressedXContent (Base64 .getDecoder ().decode (p .text ()));
1495+ } else if (token == XContentParser .Token .VALUE_EMBEDDED_OBJECT ) {
1496+ return new CompressedXContent (p .binaryValue ());
1497+ } else if (token == XContentParser .Token .START_OBJECT ) {
1498+ return new CompressedXContent (Strings .toString (XContentFactory .jsonBuilder ().map (p .mapOrdered ())));
1499+ } else {
1500+ throw new IllegalArgumentException ("Unexpected token: " + token );
1501+ }
1502+ }, MAPPINGS_FIELD , ObjectParser .ValueType .VALUE_OBJECT_ARRAY );
14591503 }
14601504
14611505 public static DataStream fromXContent (XContentParser parser ) throws IOException {
@@ -1520,6 +1564,20 @@ public XContentBuilder toXContent(
15201564 builder .startObject (SETTINGS_FIELD .getPreferredName ());
15211565 this .settings .toXContent (builder , params );
15221566 builder .endObject ();
1567+
1568+ String context = params .param (Metadata .CONTEXT_MODE_PARAM , Metadata .CONTEXT_MODE_API );
1569+ boolean binary = params .paramAsBoolean ("binary" , false );
1570+ if (Metadata .CONTEXT_MODE_API .equals (context ) || binary == false ) {
1571+ Map <String , Object > uncompressedMapping = XContentHelper .convertToMap (this .mappings .uncompressed (), true , XContentType .JSON )
1572+ .v2 ();
1573+ if (uncompressedMapping .isEmpty () == false ) {
1574+ builder .field (MAPPINGS_FIELD .getPreferredName ());
1575+ builder .map (uncompressedMapping );
1576+ }
1577+ } else {
1578+ builder .field (MAPPINGS_FIELD .getPreferredName (), mappings .compressed ());
1579+ }
1580+
15231581 builder .endObject ();
15241582 return builder ;
15251583 }
@@ -1864,6 +1922,7 @@ public static class Builder {
18641922 @ Nullable
18651923 private Map <String , Object > metadata = null ;
18661924 private Settings settings = Settings .EMPTY ;
1925+ private CompressedXContent mappings = EMPTY_MAPPINGS ;
18671926 private boolean hidden = false ;
18681927 private boolean replicated = false ;
18691928 private boolean system = false ;
@@ -1892,6 +1951,7 @@ private Builder(DataStream dataStream) {
18921951 generation = dataStream .generation ;
18931952 metadata = dataStream .metadata ;
18941953 settings = dataStream .settings ;
1954+ mappings = dataStream .mappings ;
18951955 hidden = dataStream .hidden ;
18961956 replicated = dataStream .replicated ;
18971957 system = dataStream .system ;
@@ -1928,6 +1988,11 @@ public Builder setSettings(Settings settings) {
19281988 return this ;
19291989 }
19301990
1991+ public Builder setMappings (CompressedXContent mappings ) {
1992+ this .mappings = mappings ;
1993+ return this ;
1994+ }
1995+
19311996 public Builder setHidden (boolean hidden ) {
19321997 this .hidden = hidden ;
19331998 return this ;
@@ -1989,6 +2054,7 @@ public DataStream build() {
19892054 generation ,
19902055 metadata ,
19912056 settings ,
2057+ mappings ,
19922058 hidden ,
19932059 replicated ,
19942060 system ,
0 commit comments