Mappings: Lock down _routing field

`required` is now the only changeable settings (on indexes created after 1.x).

see #8143
closes #9895
This commit is contained in:
Ryan Ernst 2015-02-26 00:41:50 -08:00
parent 257cdcd110
commit 78df69e6a0
4 changed files with 21 additions and 11 deletions

View File

@ -254,6 +254,7 @@ to provide special features. They now have limited configuration options.
* `_id` configuration can no longer be changed. If you need to sort, use `_uid` instead. * `_id` configuration can no longer be changed. If you need to sort, use `_uid` instead.
* `_type` configuration can no longer be changed. * `_type` configuration can no longer be changed.
* `_index` configuration is limited to enabling the field. * `_index` configuration is limited to enabling the field.
* `_routing` configuration is limited to requiring the field.
=== Codecs === Codecs

View File

@ -103,7 +103,9 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
@Override @Override
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException { public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
RoutingFieldMapper.Builder builder = routing(); RoutingFieldMapper.Builder builder = routing();
if (parserContext.indexVersionCreated().before(Version.V_2_0_0)) {
parseField(builder, builder.name, node, parserContext); parseField(builder, builder.name, node, parserContext);
}
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) { for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next(); Map.Entry<String, Object> entry = iterator.next();
String fieldName = Strings.toUnderscoreCase(entry.getKey()); String fieldName = Strings.toUnderscoreCase(entry.getKey());
@ -227,10 +229,10 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
return builder; return builder;
} }
builder.startObject(CONTENT_TYPE); builder.startObject(CONTENT_TYPE);
if (includeDefaults || indexed != indexedDefault) { if (writePre2xSettings && (includeDefaults || indexed != indexedDefault)) {
builder.field("index", indexTokenizeOptionToString(indexed, fieldType.tokenized())); builder.field("index", indexTokenizeOptionToString(indexed, fieldType.tokenized()));
} }
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) { if (writePre2xSettings && (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored())) {
builder.field("store", fieldType.stored()); builder.field("store", fieldType.stored());
} }
if (includeDefaults || required != Defaults.REQUIRED) { if (includeDefaults || required != Defaults.REQUIRED) {

View File

@ -1072,15 +1072,19 @@ public class GetActionTests extends ElasticsearchIntegrationTest {
@Test @Test
public void testUngeneratedFieldsNotPartOfSourceUnstored() throws IOException { public void testUngeneratedFieldsNotPartOfSourceUnstored() throws IOException {
indexSingleDocumentWithUngeneratedFieldsThatAreNeverPartOf_source(false, randomBoolean()); indexSingleDocumentWithUngeneratedFieldsThatAreNeverPartOf_source(false, randomBoolean());
String[] fieldsList = {"_timestamp", "_size", "_routing"}; String[] fieldsList = {"_timestamp", "_size"};
String[] alwaysStoredFieldsList = {"_routing"};
// before refresh - document is only in translog // before refresh - document is only in translog
assertGetFieldsAlwaysNull(indexOrAlias(), "doc", "1", fieldsList, "1"); assertGetFieldsAlwaysNull(indexOrAlias(), "doc", "1", fieldsList, "1");
assertGetFieldsAlwaysWorks(indexOrAlias(), "doc", "1", alwaysStoredFieldsList, "1");
refresh(); refresh();
//after refresh - document is in translog and also indexed //after refresh - document is in translog and also indexed
assertGetFieldsAlwaysNull(indexOrAlias(), "doc", "1", fieldsList, "1"); assertGetFieldsAlwaysNull(indexOrAlias(), "doc", "1", fieldsList, "1");
assertGetFieldsAlwaysWorks(indexOrAlias(), "doc", "1", alwaysStoredFieldsList, "1");
flush(); flush();
//after flush - document is in not anymore translog - only indexed //after flush - document is in not anymore translog - only indexed
assertGetFieldsAlwaysNull(indexOrAlias(), "doc", "1", fieldsList, "1"); assertGetFieldsAlwaysNull(indexOrAlias(), "doc", "1", fieldsList, "1");
assertGetFieldsAlwaysWorks(indexOrAlias(), "doc", "1", alwaysStoredFieldsList, "1");
} }
@Test @Test
@ -1111,9 +1115,6 @@ public class GetActionTests extends ElasticsearchIntegrationTest {
" \"store\": \"" + storedString + "\",\n" + " \"store\": \"" + storedString + "\",\n" +
" \"enabled\": true\n" + " \"enabled\": true\n" +
" },\n" + " },\n" +
" \"_routing\": {\n" +
" \"store\": \"" + storedString + "\"\n" +
" },\n" +
" \"_size\": {\n" + " \"_size\": {\n" +
" \"store\": \"" + storedString + "\",\n" + " \"store\": \"" + storedString + "\",\n" +
" \"enabled\": true\n" + " \"enabled\": true\n" +

View File

@ -20,6 +20,10 @@
package org.elasticsearch.index.mapper.routing; package org.elasticsearch.index.mapper.routing;
import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexOptions;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
@ -56,24 +60,26 @@ public class RoutingTypeMapperTests extends ElasticsearchSingleNodeTest {
} }
@Test @Test
public void testSetValues() throws Exception { public void testFieldTypeSettingsBackcompat() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type") String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_routing") .startObject("_routing")
.field("store", "no") .field("store", "no")
.field("index", "no") .field("index", "no")
.endObject() .endObject()
.endObject().endObject().string(); .endObject().endObject().string();
DocumentMapper docMapper = createIndex("test").mapperService().documentMapperParser().parse(mapping); Settings indexSettings = ImmutableSettings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_1_4_2.id).build();
DocumentMapper docMapper = createIndex("test", indexSettings).mapperService().documentMapperParser().parse(mapping);
assertThat(docMapper.routingFieldMapper().fieldType().stored(), equalTo(false)); assertThat(docMapper.routingFieldMapper().fieldType().stored(), equalTo(false));
assertEquals(IndexOptions.NONE, docMapper.routingFieldMapper().fieldType().indexOptions()); assertEquals(IndexOptions.NONE, docMapper.routingFieldMapper().fieldType().indexOptions());
} }
@Test @Test
public void testThatSerializationWorksCorrectlyForIndexField() throws Exception { public void testFieldTypeSettingsSerializationBackcompat() throws Exception {
String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type") String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_routing").field("store", "no").field("index", "no").endObject() .startObject("_routing").field("store", "no").field("index", "no").endObject()
.endObject().endObject().string(); .endObject().endObject().string();
DocumentMapper enabledMapper = createIndex("test").mapperService().documentMapperParser().parse(enabledMapping); Settings indexSettings = ImmutableSettings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_1_4_2.id).build();
DocumentMapper enabledMapper = createIndex("test", indexSettings).mapperService().documentMapperParser().parse(enabledMapping);
XContentBuilder builder = JsonXContent.contentBuilder().startObject(); XContentBuilder builder = JsonXContent.contentBuilder().startObject();
enabledMapper.routingFieldMapper().toXContent(builder, ToXContent.EMPTY_PARAMS).endObject(); enabledMapper.routingFieldMapper().toXContent(builder, ToXContent.EMPTY_PARAMS).endObject();