Automatically created indices should honor index.mapper.dynamic. #19478

Today they don't because the create index request that is implicitly created
adds an empty mapping for the type of the document. So to Elasticsearch it
looks like this type was explicitly created and `index.mapper.dynamic` is not
checked.

Closes #17592
This commit is contained in:
Adrien Grand 2016-07-18 16:47:44 +02:00
parent 3f6c0feee3
commit 37e20c6f34
5 changed files with 39 additions and 16 deletions

View File

@ -119,29 +119,21 @@ public class TransportBulkAction extends HandledTransportAction<BulkRequest, Bul
if (needToCheck()) {
// Keep track of all unique indices and all unique types per index for the create index requests:
final Map<String, Set<String>> indicesAndTypes = new HashMap<>();
final Set<String> autoCreateIndices = new HashSet<>();
for (ActionRequest request : bulkRequest.requests) {
if (request instanceof DocumentRequest) {
DocumentRequest req = (DocumentRequest) request;
Set<String> types = indicesAndTypes.get(req.index());
if (types == null) {
indicesAndTypes.put(req.index(), types = new HashSet<>());
}
types.add(req.type());
autoCreateIndices.add(req.index());
} else {
throw new ElasticsearchException("Parsed unknown request in bulk actions: " + request.getClass().getSimpleName());
}
}
final AtomicInteger counter = new AtomicInteger(indicesAndTypes.size());
final AtomicInteger counter = new AtomicInteger(autoCreateIndices.size());
ClusterState state = clusterService.state();
for (Map.Entry<String, Set<String>> entry : indicesAndTypes.entrySet()) {
final String index = entry.getKey();
for (String index : autoCreateIndices) {
if (shouldAutoCreate(index, state)) {
CreateIndexRequest createIndexRequest = new CreateIndexRequest();
createIndexRequest.index(index);
for (String type : entry.getValue()) {
createIndexRequest.mapping(type);
}
createIndexRequest.cause("auto(bulk api)");
createIndexRequest.masterNodeTimeout(bulkRequest.timeout());
createIndexAction.execute(createIndexRequest, new ActionListener<CreateIndexResponse>() {

View File

@ -91,7 +91,6 @@ public class TransportIndexAction extends TransportWriteAction<IndexRequest, Ind
if (autoCreateIndex.shouldAutoCreate(request.index(), state)) {
CreateIndexRequest createIndexRequest = new CreateIndexRequest();
createIndexRequest.index(request.index());
createIndexRequest.mapping(request.type());
createIndexRequest.cause("auto(index api)");
createIndexRequest.masterNodeTimeout(request.timeout());
createIndexAction.execute(task, createIndexRequest, new ActionListener<CreateIndexResponse>() {

View File

@ -538,7 +538,8 @@ public class MapperService extends AbstractIndexComponent {
return new DocumentMapperForType(mapper, null);
}
if (!dynamic) {
throw new TypeMissingException(index(), type, "trying to auto create mapping, but dynamic mapping is disabled");
throw new TypeMissingException(index(),
new IllegalStateException("trying to auto create mapping, but dynamic mapping is disabled"), type);
}
mapper = parse(type, null, true);
return new DocumentMapperForType(mapper, mapper.mapping());

View File

@ -33,7 +33,12 @@ import java.util.Arrays;
public class TypeMissingException extends ElasticsearchException {
public TypeMissingException(Index index, String... types) {
super("type[" + Arrays.toString(types) + "] missing");
super("type" + Arrays.toString(types) + " missing");
setIndex(index);
}
public TypeMissingException(Index index, Throwable cause, String... types) {
super("type" + Arrays.toString(types) + " missing", cause);
setIndex(index);
}

View File

@ -18,10 +18,13 @@
*/
package org.elasticsearch.index.mapper;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.indices.TypeMissingException;
import org.elasticsearch.test.ESIntegTestCase;
import java.io.IOException;
@ -29,8 +32,9 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
public class DynamicMappingIntegrationIT extends ESIntegTestCase {
public class DynamicMappingIT extends ESIntegTestCase {
public void testConflictingDynamicMappings() {
// we don't use indexRandom because the order of requests is important here
@ -120,4 +124,26 @@ public class DynamicMappingIntegrationIT extends ESIntegTestCase {
}
}
public void testAutoCreateWithDisabledDynamicMappings() throws Exception {
assertAcked(client().admin().indices().preparePutTemplate("my_template")
.setCreate(true)
.setTemplate("index_*")
.addMapping("foo", "field", "type=keyword")
.setSettings(Settings.builder().put("index.mapper.dynamic", false).build())
.get());
// succeeds since 'foo' has an explicit mapping in the template
indexRandom(true, false, client().prepareIndex("index_1", "foo", "1").setSource("field", "abc"));
// fails since 'bar' does not have an explicit mapping in the template and dynamic template creation is disabled
TypeMissingException e1 = expectThrows(TypeMissingException.class,
() -> client().prepareIndex("index_2", "bar", "1").setSource("field", "abc").get());
assertEquals("type[bar] missing", e1.getMessage());
assertEquals("trying to auto create mapping, but dynamic mapping is disabled", e1.getCause().getMessage());
// make sure no mappings were created for bar
GetIndexResponse getIndexResponse = client().admin().indices().prepareGetIndex().addIndices("index_2").get();
assertFalse(getIndexResponse.mappings().containsKey("bar"));
}
}