[ML] Preserve _meta on results index mapping update (elastic/x-pack-elasticsearch#2274)

When mappings are updated for an index are updated most settings are
merged, but not _meta.  This change ensures that _meta is set when we
add per-job term mappings to our results index mappings.  In order to
keep the logic for updating mappings after upgrade working, we now
have to put ALL the mappings for our results along with the latest _meta
section when updating per-job term mappings.

relates elastic/x-pack-elasticsearch#2265

Original commit: elastic/x-pack-elasticsearch@f58c11a13e
This commit is contained in:
David Roberts 2017-08-16 16:16:30 +01:00 committed by GitHub
parent 0a86f00d7e
commit 6fcc3be438
3 changed files with 64 additions and 1 deletions

View File

@ -26,6 +26,7 @@ import org.elasticsearch.xpack.ml.notifications.AuditMessage;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
@ -126,6 +127,10 @@ public class ElasticsearchMappings {
} }
public static XContentBuilder docMapping() throws IOException { public static XContentBuilder docMapping() throws IOException {
return docMapping(Collections.emptyList());
}
public static XContentBuilder docMapping(Collection<String> extraTermFields) throws IOException {
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
builder.startObject(); builder.startObject();
builder.startObject(DOC_TYPE); builder.startObject(DOC_TYPE);
@ -153,6 +158,8 @@ public class ElasticsearchMappings {
addDataCountsMapping(builder); addDataCountsMapping(builder);
addModelSnapshotMapping(builder); addModelSnapshotMapping(builder);
addTermFields(builder, extraTermFields);
// end properties // end properties
builder.endObject(); builder.endObject();
// end mapping // end mapping

View File

@ -234,6 +234,8 @@ public class JobProvider {
if (!state.getMetaData().hasIndex(indexName)) { if (!state.getMetaData().hasIndex(indexName)) {
LOGGER.trace("ES API CALL: create index {}", indexName); LOGGER.trace("ES API CALL: create index {}", indexName);
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
// This assumes the requested mapping will be merged with mappings from the template,
// and may need to be revisited if template merging is ever refactored
try (XContentBuilder termFieldsMapping = ElasticsearchMappings.termFieldsMapping(ElasticsearchMappings.DOC_TYPE, termFields)) { try (XContentBuilder termFieldsMapping = ElasticsearchMappings.termFieldsMapping(ElasticsearchMappings.DOC_TYPE, termFields)) {
createIndexRequest.mapping(ElasticsearchMappings.DOC_TYPE, termFieldsMapping); createIndexRequest.mapping(ElasticsearchMappings.DOC_TYPE, termFieldsMapping);
} }
@ -298,7 +300,8 @@ public class JobProvider {
} }
private void updateIndexMappingWithTermFields(String indexName, Collection<String> termFields, ActionListener<Boolean> listener) { private void updateIndexMappingWithTermFields(String indexName, Collection<String> termFields, ActionListener<Boolean> listener) {
try (XContentBuilder termFieldsMapping = ElasticsearchMappings.termFieldsMapping(null, termFields)) { // Put the whole "doc" mapping, not just the term fields, otherwise we'll wipe the _meta section of the mapping
try (XContentBuilder termFieldsMapping = ElasticsearchMappings.docMapping(termFields)) {
client.admin().indices().preparePutMapping(indexName).setType(ElasticsearchMappings.DOC_TYPE) client.admin().indices().preparePutMapping(indexName).setType(ElasticsearchMappings.DOC_TYPE)
.setSource(termFieldsMapping) .setSource(termFieldsMapping)
.execute(new ActionListener<PutMappingResponse>() { .execute(new ActionListener<PutMappingResponse>() {
@ -312,6 +315,8 @@ public class JobProvider {
listener.onFailure(e); listener.onFailure(e);
} }
}); });
} catch (IOException e) {
listener.onFailure(e);
} }
} }

View File

@ -36,3 +36,54 @@
type: doc type: doc
fields: new_field fields: new_field
- match: {\.ml-anomalies-shared.mappings.doc.new_field.mapping.new_field.type: keyword} - match: {\.ml-anomalies-shared.mappings.doc.new_field.mapping.new_field.type: keyword}
---
"Test _meta exists when two jobs share an index":
- do:
xpack.ml.put_job:
job_id: ml-anomalies-shared-mappings-job1
body: >
{
"analysis_config" : {
"bucket_span": "1h",
"detectors" :[{"function":"count","by_field_name":"foo"}]
},
"data_description" : {
"time_field":"time"
}
}
- match: { job_id: "ml-anomalies-shared-mappings-job1" }
- do:
indices.refresh:
index: .ml-anomalies-shared
- do:
indices.get_mapping:
index: .ml-anomalies-shared
- is_true: \.ml-anomalies-shared.mappings.doc._meta.version
- do:
xpack.ml.put_job:
job_id: ml-anomalies-shared-mappings-job2
body: >
{
"analysis_config" : {
"bucket_span": "1h",
"detectors" :[{"function":"count","by_field_name":"bar"}]
},
"data_description" : {
"time_field":"time"
}
}
- match: { job_id: "ml-anomalies-shared-mappings-job2" }
- do:
indices.refresh:
index: .ml-anomalies-shared
- do:
indices.get_mapping:
index: .ml-anomalies-shared
- is_true: \.ml-anomalies-shared.mappings.doc._meta.version