Percolator should cache index field data instances.

Before the index reader used by the percolator didn't allow to register a CoreCloseListener, but now it does, making it safe to cache index field data cache entries.
Creating field data structures is relatively expensive and caching them can save a lot of noise if many queries are evaluated in a percolator call.

Closes #6806
Closes #7081
This commit is contained in:
Martijn van Groningen 2014-07-29 19:13:03 +02:00
parent 3c83c0f9d7
commit c8cc59df57
4 changed files with 19 additions and 49 deletions

View File

@ -38,11 +38,10 @@ import org.elasticsearch.index.mapper.internal.IndexFieldMapper;
import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
import org.elasticsearch.index.service.IndexService; import org.elasticsearch.index.service.IndexService;
import org.elasticsearch.index.settings.IndexSettings; import org.elasticsearch.index.settings.IndexSettings;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCacheListener; import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCacheListener;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -299,40 +298,4 @@ public class IndexFieldDataService extends AbstractIndexComponent {
return (IFD) fieldData; return (IFD) fieldData;
} }
public <IFD extends IndexFieldData<?>> IFD getForFieldDirect(FieldMapper<?> mapper) {
final FieldMapper.Names fieldNames = mapper.names();
final FieldDataType type = mapper.fieldDataType();
if (type == null) {
throw new ElasticsearchIllegalArgumentException("found no fielddata type for field [" + fieldNames.fullName() + "]");
}
final boolean docValues = mapper.hasDocValues();
IndexFieldData.Builder builder = null;
String format = type.getFormat(indexSettings);
if (format != null && FieldDataType.DOC_VALUES_FORMAT_VALUE.equals(format) && !docValues) {
logger.warn("field [" + fieldNames.fullName() + "] has no doc values, will use default field data format");
format = null;
}
if (format != null) {
builder = buildersByTypeAndFormat.get(Tuple.tuple(type.getType(), format));
if (builder == null) {
logger.warn("failed to find format [" + format + "] for field [" + fieldNames.fullName() + "], will use default");
}
}
if (builder == null && docValues) {
builder = docValuesBuildersByType.get(type.getType());
}
if (builder == null) {
builder = buildersByType.get(type.getType());
}
if (builder == null) {
throw new ElasticsearchIllegalArgumentException("failed to find field data builder for field " + fieldNames.fullName() + ", and type " + type.getType());
}
CircuitBreakerService circuitBreakerService = new NoneCircuitBreakerService();
@SuppressWarnings("unchecked")
IFD ifd = (IFD) builder.build(index, indexSettings, mapper, new IndexFieldDataCache.None(), circuitBreakerService, indexService.mapperService());
return ifd;
}
} }

View File

@ -88,17 +88,17 @@ public class QueryParseContext {
private EnumSet<ParseField.Flag> parseFlags = ParseField.EMPTY_FLAGS; private EnumSet<ParseField.Flag> parseFlags = ParseField.EMPTY_FLAGS;
private final boolean disableCaching; private final boolean disableFilterCaching;
public QueryParseContext(Index index, IndexQueryParserService indexQueryParser) { public QueryParseContext(Index index, IndexQueryParserService indexQueryParser) {
this(index, indexQueryParser, false); this(index, indexQueryParser, false);
} }
public QueryParseContext(Index index, IndexQueryParserService indexQueryParser, boolean disableCaching) { public QueryParseContext(Index index, IndexQueryParserService indexQueryParser, boolean disableFilterCaching) {
this.index = index; this.index = index;
this.indexQueryParser = indexQueryParser; this.indexQueryParser = indexQueryParser;
this.propagateNoCache = disableCaching; this.propagateNoCache = disableFilterCaching;
this.disableCaching = disableCaching; this.disableFilterCaching = disableFilterCaching;
} }
public void parseFlags(EnumSet<ParseField.Flag> parseFlags) { public void parseFlags(EnumSet<ParseField.Flag> parseFlags) {
@ -178,7 +178,7 @@ public class QueryParseContext {
if (filter == null) { if (filter == null) {
return null; return null;
} }
if (this.disableCaching || this.propagateNoCache || filter instanceof NoCacheFilter) { if (this.disableFilterCaching || this.propagateNoCache || filter instanceof NoCacheFilter) {
return filter; return filter;
} }
if (cacheKey != null) { if (cacheKey != null) {
@ -188,11 +188,7 @@ public class QueryParseContext {
} }
public <IFD extends IndexFieldData<?>> IFD getForField(FieldMapper<?> mapper) { public <IFD extends IndexFieldData<?>> IFD getForField(FieldMapper<?> mapper) {
if (disableCaching) { return indexQueryParser.fieldDataService.getForField(mapper);
return indexQueryParser.fieldDataService.getForFieldDirect(mapper);
} else {
return indexQueryParser.fieldDataService.getForField(mapper);
}
} }
public void addNamedFilter(String name, Filter filter) { public void addNamedFilter(String name, Filter filter) {

View File

@ -120,13 +120,16 @@ public final class ExternalTestCluster extends TestCluster {
public void ensureEstimatedStats() { public void ensureEstimatedStats() {
if (size() > 0) { if (size() > 0) {
NodesStatsResponse nodeStats = client().admin().cluster().prepareNodesStats() NodesStatsResponse nodeStats = client().admin().cluster().prepareNodesStats()
.clear().setBreaker(true).execute().actionGet(); .clear().setBreaker(true).setIndices(true).execute().actionGet();
for (NodeStats stats : nodeStats.getNodes()) { for (NodeStats stats : nodeStats.getNodes()) {
assertThat("Fielddata breaker not reset to 0 on node: " + stats.getNode(), assertThat("Fielddata breaker not reset to 0 on node: " + stats.getNode(),
stats.getBreaker().getStats(CircuitBreaker.Name.FIELDDATA).getEstimated(), equalTo(0L)); stats.getBreaker().getStats(CircuitBreaker.Name.FIELDDATA).getEstimated(), equalTo(0L));
// ExternalTestCluster does not check the request breaker, // ExternalTestCluster does not check the request breaker,
// because checking it requires a network request, which in // because checking it requires a network request, which in
// turn increments the breaker, making it non-0 // turn increments the breaker, making it non-0
assertThat("Fielddata size must be 0 on node: " + stats.getNode(), stats.getIndices().getFieldData().getMemorySizeInBytes(), equalTo(0l));
assertThat("Filter cache size must be 0 on node: " + stats.getNode(), stats.getIndices().getFilterCache().getMemorySizeInBytes(), equalTo(0l));
} }
} }
} }

View File

@ -32,6 +32,8 @@ import org.apache.lucene.util.IOUtils;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchIllegalStateException; import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags;
import org.elasticsearch.cache.recycler.CacheRecycler; import org.elasticsearch.cache.recycler.CacheRecycler;
import org.elasticsearch.cache.recycler.PageCacheRecyclerModule; import org.elasticsearch.cache.recycler.PageCacheRecyclerModule;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
@ -70,6 +72,7 @@ import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.node.internal.InternalNode; import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.node.service.NodeService;
import org.elasticsearch.plugins.PluginsService; import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.search.SearchService; import org.elasticsearch.search.SearchService;
import org.elasticsearch.test.cache.recycler.MockBigArraysModule; import org.elasticsearch.test.cache.recycler.MockBigArraysModule;
@ -1539,6 +1542,11 @@ public final class InternalTestCluster extends TestCluster {
} catch (Exception e) { } catch (Exception e) {
fail("Exception during check for request breaker reset to 0: " + e); fail("Exception during check for request breaker reset to 0: " + e);
} }
NodeService nodeService = getInstanceFromNode(NodeService.class, nodeAndClient.node);
NodeStats stats = nodeService.stats(CommonStatsFlags.ALL, false, false, false, false, false, false, false, false, false);
assertThat("Fielddata size must be 0 on node: " + stats.getNode(), stats.getIndices().getFieldData().getMemorySizeInBytes(), equalTo(0l));
assertThat("Filter cache size must be 0 on node: " + stats.getNode(), stats.getIndices().getFilterCache().getMemorySizeInBytes(), equalTo(0l));
} }
} }
} }