mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 09:28:27 +00:00
This adds the field data circuit breaker, which is used to estimate the amount of memory required to load field data before loading it. It then raises a CircuitBreakingException if the limit is exceeded. It is configured with two parameters: `indices.fielddata.cache.breaker.limit` - the maximum number of bytes of field data to be loaded before circuit breaking. Defaults to `indices.fielddata.cache.size` if set, unbounded otherwise. `indices.fielddata.cache.breaker.overhead` - a contast for all field data estimations to be multiplied with before aggregation. Defaults to 1.03. Both settings can be configured dynamically using the cluster update settings API.
171 lines
9.1 KiB
Java
171 lines
9.1 KiB
Java
/*
|
|
* Licensed to ElasticSearch and Shay Banon 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.apache.lucene.analysis.core.KeywordAnalyzer;
|
|
import org.apache.lucene.document.Document;
|
|
import org.apache.lucene.document.Field.Store;
|
|
import org.apache.lucene.document.StringField;
|
|
import org.apache.lucene.index.*;
|
|
import org.apache.lucene.store.RAMDirectory;
|
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
|
import org.elasticsearch.common.settings.Settings;
|
|
import org.elasticsearch.index.Index;
|
|
import org.elasticsearch.index.fielddata.plain.*;
|
|
import org.elasticsearch.index.mapper.ContentPath;
|
|
import org.elasticsearch.index.mapper.FieldMapper;
|
|
import org.elasticsearch.index.mapper.Mapper.BuilderContext;
|
|
import org.elasticsearch.index.mapper.MapperBuilders;
|
|
import org.elasticsearch.index.mapper.core.*;
|
|
import org.elasticsearch.indices.fielddata.breaker.DummyCircuitBreakerService;
|
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.IdentityHashMap;
|
|
import java.util.Set;
|
|
|
|
import static org.hamcrest.Matchers.instanceOf;
|
|
|
|
public class IndexFieldDataServiceTests extends ElasticsearchTestCase {
|
|
|
|
private static Settings DOC_VALUES_SETTINGS = ImmutableSettings.builder().put(FieldDataType.FORMAT_KEY, FieldDataType.DOC_VALUES_FORMAT_VALUE).build();
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public void testGetForFieldDefaults() {
|
|
final IndexFieldDataService ifdService = new IndexFieldDataService(new Index("test"), new DummyCircuitBreakerService());
|
|
for (boolean docValues : Arrays.asList(true, false)) {
|
|
final BuilderContext ctx = new BuilderContext(null, new ContentPath(1));
|
|
final StringFieldMapper stringMapper = new StringFieldMapper.Builder("string").tokenized(false).fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx);
|
|
ifdService.clear();
|
|
IndexFieldData<?> fd = ifdService.getForField(stringMapper);
|
|
if (docValues) {
|
|
assertTrue(fd instanceof SortedSetDVBytesIndexFieldData);
|
|
} else {
|
|
assertTrue(fd instanceof PagedBytesIndexFieldData);
|
|
}
|
|
|
|
for (FieldMapper<?> mapper : Arrays.asList(
|
|
new ByteFieldMapper.Builder("int").fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx),
|
|
new ShortFieldMapper.Builder("int").fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx),
|
|
new IntegerFieldMapper.Builder("int").fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx),
|
|
new LongFieldMapper.Builder("long").fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx)
|
|
)) {
|
|
ifdService.clear();
|
|
fd = ifdService.getForField(mapper);
|
|
if (docValues) {
|
|
assertTrue(fd instanceof BinaryDVNumericIndexFieldData);
|
|
} else {
|
|
assertTrue(fd instanceof PackedArrayIndexFieldData);
|
|
}
|
|
}
|
|
|
|
final FloatFieldMapper floatMapper = new FloatFieldMapper.Builder("float").fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx);
|
|
ifdService.clear();
|
|
fd = ifdService.getForField(floatMapper);
|
|
if (docValues) {
|
|
assertTrue(fd instanceof BinaryDVNumericIndexFieldData);
|
|
} else {
|
|
assertTrue(fd instanceof FloatArrayIndexFieldData);
|
|
}
|
|
|
|
final DoubleFieldMapper doubleMapper = new DoubleFieldMapper.Builder("double").fieldDataSettings(docValues ? DOC_VALUES_SETTINGS : ImmutableSettings.EMPTY).build(ctx);
|
|
ifdService.clear();
|
|
fd = ifdService.getForField(doubleMapper);
|
|
if (docValues) {
|
|
assertTrue(fd instanceof BinaryDVNumericIndexFieldData);
|
|
} else {
|
|
assertTrue(fd instanceof DoubleArrayIndexFieldData);
|
|
}
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public void testByPassDocValues() {
|
|
final IndexFieldDataService ifdService = new IndexFieldDataService(new Index("test"), new DummyCircuitBreakerService());
|
|
final BuilderContext ctx = new BuilderContext(null, new ContentPath(1));
|
|
final StringFieldMapper stringMapper = MapperBuilders.stringField("string").tokenized(false).fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(ImmutableSettings.builder().put("format", "fst").build()).build(ctx);
|
|
ifdService.clear();
|
|
IndexFieldData<?> fd = ifdService.getForField(stringMapper);
|
|
assertTrue(fd instanceof FSTBytesIndexFieldData);
|
|
|
|
final Settings fdSettings = ImmutableSettings.builder().put("format", "array").build();
|
|
for (FieldMapper<?> mapper : Arrays.asList(
|
|
new ByteFieldMapper.Builder("int").fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(fdSettings).build(ctx),
|
|
new ShortFieldMapper.Builder("int").fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(fdSettings).build(ctx),
|
|
new IntegerFieldMapper.Builder("int").fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(fdSettings).build(ctx),
|
|
new LongFieldMapper.Builder("long").fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(fdSettings).build(ctx)
|
|
)) {
|
|
ifdService.clear();
|
|
fd = ifdService.getForField(mapper);
|
|
assertTrue(fd instanceof PackedArrayIndexFieldData);
|
|
}
|
|
|
|
final FloatFieldMapper floatMapper = MapperBuilders.floatField("float").fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(fdSettings).build(ctx);
|
|
ifdService.clear();
|
|
fd = ifdService.getForField(floatMapper);
|
|
assertTrue(fd instanceof FloatArrayIndexFieldData);
|
|
|
|
final DoubleFieldMapper doubleMapper = MapperBuilders.doubleField("double").fieldDataSettings(DOC_VALUES_SETTINGS).fieldDataSettings(fdSettings).build(ctx);
|
|
ifdService.clear();
|
|
fd = ifdService.getForField(doubleMapper);
|
|
assertTrue(fd instanceof DoubleArrayIndexFieldData);
|
|
}
|
|
|
|
public void testChangeFieldDataFormat() throws Exception {
|
|
final IndexFieldDataService ifdService = new IndexFieldDataService(new Index("test"), new DummyCircuitBreakerService());
|
|
final BuilderContext ctx = new BuilderContext(null, new ContentPath(1));
|
|
final StringFieldMapper mapper1 = MapperBuilders.stringField("s").tokenized(false).fieldDataSettings(ImmutableSettings.builder().put(FieldDataType.FORMAT_KEY, "paged_bytes").build()).build(ctx);
|
|
final IndexWriter writer = new IndexWriter(new RAMDirectory(), new IndexWriterConfig(TEST_VERSION_CURRENT, new KeywordAnalyzer()));
|
|
Document doc = new Document();
|
|
doc.add(new StringField("s", "thisisastring", Store.NO));
|
|
writer.addDocument(doc);
|
|
final IndexReader reader1 = DirectoryReader.open(writer, true);
|
|
IndexFieldData<?> ifd = ifdService.getForField(mapper1);
|
|
assertThat(ifd, instanceOf(PagedBytesIndexFieldData.class));
|
|
Set<AtomicReader> oldSegments = Collections.newSetFromMap(new IdentityHashMap<AtomicReader, Boolean>());
|
|
for (AtomicReaderContext arc : reader1.leaves()) {
|
|
oldSegments.add(arc.reader());
|
|
AtomicFieldData<?> afd = ifd.load(arc);
|
|
assertThat(afd, instanceOf(PagedBytesAtomicFieldData.class));
|
|
}
|
|
// write new segment
|
|
writer.addDocument(doc);
|
|
final IndexReader reader2 = DirectoryReader.open(writer, true);
|
|
final StringFieldMapper mapper2 = MapperBuilders.stringField("s").tokenized(false).fieldDataSettings(ImmutableSettings.builder().put(FieldDataType.FORMAT_KEY, "fst").build()).build(ctx);
|
|
ifdService.onMappingUpdate();
|
|
ifd = ifdService.getForField(mapper2);
|
|
assertThat(ifd, instanceOf(FSTBytesIndexFieldData.class));
|
|
for (AtomicReaderContext arc : reader2.leaves()) {
|
|
AtomicFieldData<?> afd = ifd.load(arc);
|
|
if (oldSegments.contains(arc.reader())) {
|
|
assertThat(afd, instanceOf(PagedBytesAtomicFieldData.class));
|
|
} else {
|
|
assertThat(afd, instanceOf(FSTBytesAtomicFieldData.class));
|
|
}
|
|
}
|
|
reader1.close();
|
|
reader2.close();
|
|
writer.close();
|
|
writer.getDirectory().close();
|
|
}
|
|
|
|
}
|