diff --git a/core/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java b/core/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java index b898f3ffd2a..f02f924bc39 100644 --- a/core/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java +++ b/core/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java @@ -28,7 +28,6 @@ import org.elasticsearch.index.AbstractIndexComponent; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.fielddata.plain.AbstractGeoPointDVIndexFieldData; import org.elasticsearch.index.fielddata.plain.BytesBinaryDVIndexFieldData; -import org.elasticsearch.index.fielddata.plain.DisabledIndexFieldData; import org.elasticsearch.index.fielddata.plain.DocValuesIndexFieldData; import org.elasticsearch.index.fielddata.plain.GeoPointArrayIndexFieldData; import org.elasticsearch.index.fielddata.plain.IndexIndexFieldData; @@ -79,6 +78,14 @@ public class IndexFieldDataService extends AbstractIndexComponent implements Clo private static final String DOC_VALUES_FORMAT = "doc_values"; private static final String PAGED_BYTES_FORMAT = "paged_bytes"; + private static final IndexFieldData.Builder DISABLED_BUILDER = new IndexFieldData.Builder() { + @Override + public IndexFieldData build(IndexSettings indexSettings, MappedFieldType fieldType, IndexFieldDataCache cache, + CircuitBreakerService breakerService, MapperService mapperService) { + throw new IllegalStateException("Field data loading is forbidden on [" + fieldType.name() + "]"); + } + }; + private final static Map buildersByType; private final static Map docValuesBuildersByType; private final static Map, IndexFieldData.Builder> buildersByTypeAndFormat; @@ -96,7 +103,7 @@ public class IndexFieldDataService extends AbstractIndexComponent implements Clo buildersByTypeBuilder.put("geo_point", new GeoPointArrayIndexFieldData.Builder()); buildersByTypeBuilder.put(ParentFieldMapper.NAME, new ParentChildIndexFieldData.Builder()); buildersByTypeBuilder.put(IndexFieldMapper.NAME, new IndexIndexFieldData.Builder()); - buildersByTypeBuilder.put("binary", new DisabledIndexFieldData.Builder()); + buildersByTypeBuilder.put("binary", DISABLED_BUILDER); buildersByTypeBuilder.put(BooleanFieldMapper.CONTENT_TYPE, MISSING_DOC_VALUES_BUILDER); buildersByType = unmodifiableMap(buildersByTypeBuilder); @@ -117,35 +124,35 @@ public class IndexFieldDataService extends AbstractIndexComponent implements Clo buildersByTypeAndFormat = MapBuilder., IndexFieldData.Builder>newMapBuilder() .put(Tuple.tuple("string", PAGED_BYTES_FORMAT), new PagedBytesIndexFieldData.Builder()) .put(Tuple.tuple("string", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder()) - .put(Tuple.tuple("string", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("string", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("float", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.FLOAT)) - .put(Tuple.tuple("float", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("float", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("double", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.DOUBLE)) - .put(Tuple.tuple("double", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("double", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("byte", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.BYTE)) - .put(Tuple.tuple("byte", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("byte", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("short", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.SHORT)) - .put(Tuple.tuple("short", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("short", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("int", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.INT)) - .put(Tuple.tuple("int", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("int", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("long", DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.LONG)) - .put(Tuple.tuple("long", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("long", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("geo_point", ARRAY_FORMAT), new GeoPointArrayIndexFieldData.Builder()) .put(Tuple.tuple("geo_point", DOC_VALUES_FORMAT), new AbstractGeoPointDVIndexFieldData.Builder()) - .put(Tuple.tuple("geo_point", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("geo_point", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple("binary", DOC_VALUES_FORMAT), new BytesBinaryDVIndexFieldData.Builder()) - .put(Tuple.tuple("binary", DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple("binary", DISABLED_FORMAT), DISABLED_BUILDER) .put(Tuple.tuple(BooleanFieldMapper.CONTENT_TYPE, DOC_VALUES_FORMAT), new DocValuesIndexFieldData.Builder().numericType(IndexNumericFieldData.NumericType.BOOLEAN)) - .put(Tuple.tuple(BooleanFieldMapper.CONTENT_TYPE, DISABLED_FORMAT), new DisabledIndexFieldData.Builder()) + .put(Tuple.tuple(BooleanFieldMapper.CONTENT_TYPE, DISABLED_FORMAT), DISABLED_BUILDER) .immutableMap(); } diff --git a/core/src/main/java/org/elasticsearch/index/fielddata/plain/DisabledIndexFieldData.java b/core/src/main/java/org/elasticsearch/index/fielddata/plain/DisabledIndexFieldData.java deleted file mode 100644 index 86daaf1a252..00000000000 --- a/core/src/main/java/org/elasticsearch/index/fielddata/plain/DisabledIndexFieldData.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.index.fielddata.plain; - -import org.apache.lucene.index.LeafReaderContext; -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.fielddata.AtomicFieldData; -import org.elasticsearch.index.fielddata.FieldDataType; -import org.elasticsearch.index.fielddata.IndexFieldData; -import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested; -import org.elasticsearch.index.fielddata.IndexFieldDataCache; -import org.elasticsearch.index.mapper.MappedFieldType; -import org.elasticsearch.index.mapper.MapperService; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.search.MultiValueMode; - -/** - * A field data implementation that forbids loading and will throw an {@link IllegalStateException} if you try to load - * {@link AtomicFieldData} instances. - */ -public final class DisabledIndexFieldData extends AbstractIndexFieldData { - - public static class Builder implements IndexFieldData.Builder { - @Override - public IndexFieldData build(IndexSettings indexSettings, MappedFieldType fieldType, - IndexFieldDataCache cache, CircuitBreakerService breakerService, MapperService mapperService) { - // Ignore Circuit Breaker - return new DisabledIndexFieldData(indexSettings, fieldType.name(), fieldType.fieldDataType(), cache); - } - } - - public DisabledIndexFieldData(IndexSettings indexSettings, String fieldName, FieldDataType fieldDataType, IndexFieldDataCache cache) { - super(indexSettings, fieldName, fieldDataType, cache); - } - - @Override - public AtomicFieldData loadDirect(LeafReaderContext context) throws Exception { - throw fail(); - } - - @Override - protected AtomicFieldData empty(int maxDoc) { - throw fail(); - } - - @Override - public IndexFieldData.XFieldComparatorSource comparatorSource(Object missingValue, MultiValueMode sortMode, Nested nested) { - throw fail(); - } - - private IllegalStateException fail() { - return new IllegalStateException("Field data loading is forbidden on " + getFieldName()); - } - -} diff --git a/core/src/test/java/org/elasticsearch/index/fielddata/DisabledFieldDataFormatTests.java b/core/src/test/java/org/elasticsearch/index/fielddata/DisabledFieldDataFormatTests.java deleted file mode 100644 index 0601a302428..00000000000 --- a/core/src/test/java/org/elasticsearch/index/fielddata/DisabledFieldDataFormatTests.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.index.fielddata; - -import org.elasticsearch.action.search.SearchPhaseExecutionException; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.aggregations.Aggregator.SubAggCollectionMode; -import org.elasticsearch.test.ESSingleNodeTestCase; - -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; - -public class DisabledFieldDataFormatTests extends ESSingleNodeTestCase { - - public void test() throws Exception { - createIndex("test", Settings.EMPTY, "type", "s", "type=string"); - logger.info("indexing data start"); - for (int i = 0; i < 10; ++i) { - client().prepareIndex("test", "type", Integer.toString(i)).setSource("s", "value" + i).execute().actionGet(); - } - logger.info("indexing data end"); - - final int searchCycles = 1; - - client().admin().indices().prepareRefresh().execute().actionGet(); - - // disable field data - updateFormat("disabled"); - - SubAggCollectionMode aggCollectionMode = randomFrom(SubAggCollectionMode.values()); - SearchResponse resp = null; - // try to run something that relies on field data and make sure that it fails - for (int i = 0; i < searchCycles; i++) { - try { - resp = client().prepareSearch("test").setPreference(Integer.toString(i)).addAggregation(AggregationBuilders.terms("t").field("s") - .collectMode(aggCollectionMode)).execute().actionGet(); - assertFailures(resp); - } catch (SearchPhaseExecutionException e) { - // expected - } - } - - // enable it again - updateFormat("paged_bytes"); - - // try to run something that relies on field data and make sure that it works - for (int i = 0; i < searchCycles; i++) { - resp = client().prepareSearch("test").setPreference(Integer.toString(i)).addAggregation(AggregationBuilders.terms("t").field("s") - .collectMode(aggCollectionMode)).execute().actionGet(); - assertNoFailures(resp); - } - - // disable it again - updateFormat("disabled"); - - // this time, it should work because segments are already loaded - for (int i = 0; i < searchCycles; i++) { - resp = client().prepareSearch("test").setPreference(Integer.toString(i)).addAggregation(AggregationBuilders.terms("t").field("s") - .collectMode(aggCollectionMode)).execute().actionGet(); - assertNoFailures(resp); - } - - // but add more docs and the new segment won't be loaded - client().prepareIndex("test", "type", "-1").setSource("s", "value").execute().actionGet(); - client().admin().indices().prepareRefresh().execute().actionGet(); - for (int i = 0; i < searchCycles; i++) { - try { - resp = client().prepareSearch("test").setPreference(Integer.toString(i)).addAggregation(AggregationBuilders.terms("t").field("s") - .collectMode(aggCollectionMode)).execute().actionGet(); - assertFailures(resp); - } catch (SearchPhaseExecutionException e) { - // expected - } - } - } - - private void updateFormat(final String format) throws Exception { - logger.info(">> put mapping start {}", format); - assertAcked(client().admin().indices().preparePutMapping("test").setType("type").setSource( - XContentFactory.jsonBuilder().startObject().startObject("type") - .startObject("properties") - .startObject("s") - .field("type", "string") - .startObject("fielddata") - .field("format", format) - .endObject() - .endObject() - .endObject() - .endObject() - .endObject()).get()); - logger.info(">> put mapping end {}", format); - } - -} diff --git a/core/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java b/core/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java index 3d4f63daa33..e8b0d03b049 100644 --- a/core/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java +++ b/core/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java @@ -234,4 +234,23 @@ public class IndexFieldDataServiceTests extends ESSingleNodeTestCase { public void testRequireDocValuesOnBools() { doTestRequireDocValues(new BooleanFieldMapper.BooleanFieldType()); } + + public void testDisabled() { + ThreadPool threadPool = new ThreadPool("random_threadpool_name"); + StringFieldMapper.StringFieldType ft = new StringFieldMapper.StringFieldType(); + try { + IndicesFieldDataCache cache = new IndicesFieldDataCache(Settings.EMPTY, null, threadPool); + IndexFieldDataService ifds = new IndexFieldDataService(IndexSettingsModule.newIndexSettings(new Index("test"), Settings.EMPTY), cache, null, null); + ft.setName("some_str"); + ft.setFieldDataType(new FieldDataType("string", Settings.builder().put(FieldDataType.FORMAT_KEY, "disabled").build())); + try { + ifds.getForField(ft); + fail(); + } catch (IllegalStateException e) { + assertThat(e.getMessage(), containsString("Field data loading is forbidden on [some_str]")); + } + } finally { + threadPool.shutdown(); + } + } }