5
5
*/
6
6
package org .elasticsearch .xpack .ml .dataframe ;
7
7
8
+ import org .apache .logging .log4j .LogManager ;
9
+ import org .apache .logging .log4j .Logger ;
10
+ import org .apache .logging .log4j .message .ParameterizedMessage ;
8
11
import org .elasticsearch .Version ;
9
12
import org .elasticsearch .action .ActionListener ;
10
13
import org .elasticsearch .action .admin .indices .create .CreateIndexAction ;
45
48
*/
46
49
public final class DestinationIndex {
47
50
51
+ private static final Logger logger = LogManager .getLogger (DestinationIndex .class );
52
+
48
53
public static final String INCREMENTAL_ID = "ml__incremental_id" ;
49
54
50
55
/**
@@ -62,13 +67,22 @@ public final class DestinationIndex {
62
67
private static final String PROPERTIES = "properties" ;
63
68
private static final String META = "_meta" ;
64
69
70
+ private static final String DFA_CREATOR = "data-frame-analytics" ;
71
+
65
72
/**
66
73
* We only preserve the most important settings.
67
74
* If the user needs other settings on the destination index they
68
75
* should create the destination index before starting the analytics.
69
76
*/
70
77
private static final String [] PRESERVED_SETTINGS = new String [] {"index.number_of_shards" , "index.number_of_replicas" };
71
78
79
+ /**
80
+ * This is the minimum compatible version of the destination index we can currently work with.
81
+ * If the results mappings change in a way existing destination indices will fail to index
82
+ * the results, this should be bumped accordingly.
83
+ */
84
+ public static final Version MIN_COMPATIBLE_VERSION = Version .V_7_10_0 ;
85
+
72
86
private DestinationIndex () {}
73
87
74
88
/**
@@ -130,7 +144,7 @@ private static CreateIndexRequest createIndexRequest(Clock clock, DataFrameAnaly
130
144
checkResultsFieldIsNotPresentInProperties (config , properties );
131
145
properties .putAll (createAdditionalMappings (config , Collections .unmodifiableMap (properties )));
132
146
Map <String , Object > metadata = getOrPutDefault (mappingsAsMap , META , HashMap ::new );
133
- metadata .putAll (createMetadata (config .getId (), clock ));
147
+ metadata .putAll (createMetadata (config .getId (), clock , Version . CURRENT ));
134
148
return new CreateIndexRequest (destinationIndex , settings ).mapping (type , mappingsAsMap );
135
149
}
136
150
@@ -173,12 +187,13 @@ private static Map<String, Object> createAdditionalMappings(DataFrameAnalyticsCo
173
187
return properties ;
174
188
}
175
189
176
- private static Map <String , Object > createMetadata (String analyticsId , Clock clock ) {
190
+ // Visible for testing
191
+ static Map <String , Object > createMetadata (String analyticsId , Clock clock , Version version ) {
177
192
Map <String , Object > metadata = new HashMap <>();
178
193
metadata .put (CREATION_DATE_MILLIS , clock .millis ());
179
- metadata .put (CREATED_BY , "data-frame-analytics" );
180
- Map <String , Version > versionMapping = new HashMap <>();
181
- versionMapping .put (CREATED , Version . CURRENT );
194
+ metadata .put (CREATED_BY , DFA_CREATOR );
195
+ Map <String , String > versionMapping = new HashMap <>();
196
+ versionMapping .put (CREATED , version . toString () );
182
197
metadata .put (VERSION , versionMapping );
183
198
metadata .put (ANALYTICS , analyticsId );
184
199
return metadata ;
@@ -234,4 +249,77 @@ private static void checkResultsFieldIsNotPresentInProperties(DataFrameAnalytics
234
249
DataFrameAnalyticsDest .RESULTS_FIELD .getPreferredName ());
235
250
}
236
251
}
252
+
253
+ @ SuppressWarnings ("unchecked" )
254
+ public static Metadata readMetadata (String jobId , MappingMetadata mappingMetadata ) {
255
+ Map <String , Object > mappings = mappingMetadata .getSourceAsMap ();
256
+ Map <String , Object > meta = (Map <String , Object >) mappings .get (META );
257
+ if ((meta == null ) || (DFA_CREATOR .equals (meta .get (CREATED_BY )) == false )) {
258
+ return new NoMetadata ();
259
+ }
260
+ return new DestMetadata (getVersion (jobId , meta ));
261
+ }
262
+
263
+ @ SuppressWarnings ("unchecked" )
264
+ private static Version getVersion (String jobId , Map <String , Object > meta ) {
265
+ try {
266
+ Map <String , Object > version = (Map <String , Object >) meta .get (VERSION );
267
+ String createdVersionString = (String ) version .get (CREATED );
268
+ return Version .fromString (createdVersionString );
269
+ } catch (Exception e ) {
270
+ logger .error (new ParameterizedMessage ("[{}] Could not retrieve destination index version" , jobId ), e );
271
+ return null ;
272
+ }
273
+ }
274
+
275
+ public interface Metadata {
276
+
277
+ boolean hasMetadata ();
278
+
279
+ boolean isCompatible ();
280
+
281
+ String getVersion ();
282
+ }
283
+
284
+ private static class NoMetadata implements Metadata {
285
+
286
+ @ Override
287
+ public boolean hasMetadata () {
288
+ return false ;
289
+ }
290
+
291
+ @ Override
292
+ public boolean isCompatible () {
293
+ throw new UnsupportedOperationException ();
294
+ }
295
+
296
+ @ Override
297
+ public String getVersion () {
298
+ throw new UnsupportedOperationException ();
299
+ }
300
+ }
301
+
302
+ private static class DestMetadata implements Metadata {
303
+
304
+ private final Version version ;
305
+
306
+ private DestMetadata (Version version ) {
307
+ this .version = version ;
308
+ }
309
+
310
+ @ Override
311
+ public boolean hasMetadata () {
312
+ return true ;
313
+ }
314
+
315
+ @ Override
316
+ public boolean isCompatible () {
317
+ return version == null ? false : version .onOrAfter (MIN_COMPATIBLE_VERSION );
318
+ }
319
+
320
+ @ Override
321
+ public String getVersion () {
322
+ return version == null ? "unknown" : version .toString ();
323
+ }
324
+ }
237
325
}
0 commit comments