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:
parent
257cdcd110
commit
78df69e6a0
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
parseField(builder, builder.name, node, parserContext);
|
if (parserContext.indexVersionCreated().before(Version.V_2_0_0)) {
|
||||||
|
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) {
|
||||||
|
|
|
@ -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" +
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue