Make sure to accept empty unnested mappings in create index requests. (#37089)
This commit is contained in:
parent
e613bcae43
commit
54f53d2a51
|
@ -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)) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue