Make sure to accept empty unnested mappings in create index requests. (#37089)

This commit is contained in:
Julie Tibshirani 2019-01-03 11:53:08 -08:00 committed by GitHub
parent e613bcae43
commit 54f53d2a51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 45 deletions

View File

@ -172,12 +172,29 @@ public class DocumentMapperParser {
return extractMapping(type, root); return extractMapping(type, root);
} }
/**
* Given an optional type name and mapping definition, returns the type and a normalized form of the mappings.
*
* The provided mapping definition may or may not contain the type name as the root key in the map. This method
* attempts to unwrap the mappings, so that they no longer contain a type name at the root. If no type name can
* be found, through either the 'type' parameter or by examining the provided mappings, then an exception will be
* thrown.
*
* @param type An optional type name.
* @param root The mapping definition.
*
* @return A tuple of the form (type, normalized mappings).
*/
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
private Tuple<String, Map<String, Object>> extractMapping(String type, Map<String, Object> root) throws MapperParsingException { private Tuple<String, Map<String, Object>> extractMapping(String type, Map<String, Object> root) throws MapperParsingException {
if (root.size() == 0) { if (root.size() == 0) {
// if we don't have any keys throw an exception if (type != null) {
throw new MapperParsingException("malformed mapping no root object found"); return new Tuple<>(type, root);
} else {
throw new MapperParsingException("malformed mapping, no type name found");
}
} }
String rootName = root.keySet().iterator().next(); String rootName = root.keySet().iterator().next();
Tuple<String, Map<String, Object>> mapping; Tuple<String, Map<String, Object>> mapping;
if (type == null || type.equals(rootName)) { if (type == null || type.equals(rootName)) {

View File

@ -24,17 +24,20 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.UnavailableShardsException; import org.elasticsearch.action.UnavailableShardsException;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.gateway.MetaStateService; import org.elasticsearch.gateway.MetaStateService;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.index.query.RangeQueryBuilder;
@ -120,6 +123,56 @@ public class CreateIndexIT extends ESIntegTestCase {
} }
} }
public void testNonNestedMappings() throws Exception {
assertAcked(prepareCreate("test")
.addMapping("_doc", XContentFactory.jsonBuilder().startObject()
.startObject("properties")
.startObject("date")
.field("type", "date")
.endObject()
.endObject()
.endObject()));
GetMappingsResponse response = client().admin().indices().prepareGetMappings("test").get();
ImmutableOpenMap<String, MappingMetaData> mappings = response.mappings().get("test");
assertNotNull(mappings);
MappingMetaData metadata = mappings.get("_doc");
assertNotNull(metadata);
assertFalse(metadata.sourceAsMap().isEmpty());
}
public void testEmptyNestedMappings() throws Exception {
assertAcked(prepareCreate("test")
.addMapping("_doc", XContentFactory.jsonBuilder().startObject().endObject()));
GetMappingsResponse response = client().admin().indices().prepareGetMappings("test").get();
ImmutableOpenMap<String, MappingMetaData> mappings = response.mappings().get("test");
assertNotNull(mappings);
MappingMetaData metadata = mappings.get("_doc");
assertNotNull(metadata);
assertTrue(metadata.sourceAsMap().isEmpty());
}
public void testEmptyMappings() throws Exception {
assertAcked(prepareCreate("test")
.addMapping("_doc", XContentFactory.jsonBuilder().startObject()
.startObject("_doc").endObject()
.endObject()));
GetMappingsResponse response = client().admin().indices().prepareGetMappings("test").get();
ImmutableOpenMap<String, MappingMetaData> mappings = response.mappings().get("test");
assertNotNull(mappings);
MappingMetaData metadata = mappings.get("_doc");
assertNotNull(metadata);
assertTrue(metadata.sourceAsMap().isEmpty());
}
public void testInvalidShardCountSettings() throws Exception { public void testInvalidShardCountSettings() throws Exception {
int value = randomIntBetween(-10, 0); int value = randomIntBetween(-10, 0);
try { try {

View File

@ -97,17 +97,6 @@ public class MetaDataIndexTemplateServiceTests extends ESSingleNodeTestCase {
assertThat(errors.get(0).getMessage(), equalTo("Alias [foobar] cannot be the same as any pattern in [foo, foobar]")); assertThat(errors.get(0).getMessage(), equalTo("Alias [foobar] cannot be the same as any pattern in [foo, foobar]"));
} }
public void testIndexTemplateWithValidateEmptyMapping() throws Exception {
PutRequest request = new PutRequest("api", "validate_template");
request.patterns(Collections.singletonList("validate_template"));
request.putMapping("type1", "{}");
List<Throwable> errors = putTemplateDetail(request);
assertThat(errors.size(), equalTo(1));
assertThat(errors.get(0), instanceOf(MapperParsingException.class));
assertThat(errors.get(0).getMessage(), containsString("malformed mapping no root object found"));
}
public void testIndexTemplateWithValidateMapping() throws Exception { public void testIndexTemplateWithValidateMapping() throws Exception {
PutRequest request = new PutRequest("api", "validate_template"); PutRequest request = new PutRequest("api", "validate_template");
request.patterns(Collections.singletonList("te*")); request.patterns(Collections.singletonList("te*"));
@ -132,17 +121,6 @@ public class MetaDataIndexTemplateServiceTests extends ESSingleNodeTestCase {
assertThat(errors.get(0).getMessage(), containsString("Failed to parse mapping ")); assertThat(errors.get(0).getMessage(), containsString("Failed to parse mapping "));
} }
public void testBlankMapping() throws Exception {
PutRequest request = new PutRequest("api", "blank_mapping");
request.patterns(Collections.singletonList("te*"));
request.putMapping("type1", "{}");
List<Throwable> errors = putTemplateDetail(request);
assertThat(errors.size(), equalTo(1));
assertThat(errors.get(0), instanceOf(MapperParsingException.class));
assertThat(errors.get(0).getMessage(), containsString("malformed mapping no root object found"));
}
public void testAliasInvalidFilterInvalidJson() throws Exception { public void testAliasInvalidFilterInvalidJson() throws Exception {
//invalid json: put index template fails //invalid json: put index template fails
PutRequest request = new PutRequest("api", "blank_mapping"); PutRequest request = new PutRequest("api", "blank_mapping");

View File

@ -39,8 +39,6 @@ import org.elasticsearch.test.InternalSettingsPlugin;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
@ -179,25 +177,7 @@ public class MapperServiceTests extends ESSingleNodeTestCase {
assertWarnings("[unmapped_type:string] should be replaced with [unmapped_type:keyword]"); assertWarnings("[unmapped_type:string] should be replaced with [unmapped_type:keyword]");
} }
public void testMergeWithMap() throws Throwable { public void testPartitionedConstraints() {
IndexService indexService1 = createIndex("index1");
MapperService mapperService = indexService1.mapperService();
Map<String, Map<String, Object>> mappings = new HashMap<>();
mappings.put(MapperService.DEFAULT_MAPPING, MapperService.parseMapping(xContentRegistry(), "{}"));
MapperException e = expectThrows(MapperParsingException.class,
() -> mapperService.merge(mappings, MergeReason.MAPPING_UPDATE));
assertThat(e.getMessage(), startsWith("Failed to parse mapping [" + MapperService.DEFAULT_MAPPING + "]: "));
mappings.clear();
mappings.put("type1", MapperService.parseMapping(xContentRegistry(), "{}"));
e = expectThrows( MapperParsingException.class,
() -> mapperService.merge(mappings, MergeReason.MAPPING_UPDATE));
assertThat(e.getMessage(), startsWith("Failed to parse mapping [type1]: "));
}
public void testPartitionedConstraints() {
// partitioned index must have routing // partitioned index must have routing
IllegalArgumentException noRoutingException = expectThrows(IllegalArgumentException.class, () -> { IllegalArgumentException noRoutingException = expectThrows(IllegalArgumentException.class, () -> {
client().admin().indices().prepareCreate("test-index") client().admin().indices().prepareCreate("test-index")