Internal: Remove the query parser cache.

The original goal of this cache was to avoid parsing the same query several
times in case several shards are held on the same node. While this might
sound like a good idea, this would only help when parsing the query takes
non-negligible time compared to actually running the query, which should not
be the case.
This commit is contained in:
Adrien Grand 2015-04-28 18:01:47 +02:00
parent 87cf1452d5
commit 9d890c472b
10 changed files with 12 additions and 342 deletions

View File

@ -101,8 +101,6 @@ public class TransportClearIndicesCacheAction extends TransportBroadcastOperatio
IndexService service = indicesService.indexService(request.shardId().getIndex());
if (service != null) {
IndexShard shard = service.shard(request.shardId().id());
// we always clear the query cache
service.cache().queryParserCache().clear();
boolean clearedAtLeastOne = false;
if (request.filterCache()) {
clearedAtLeastOne = true;

View File

@ -20,18 +20,12 @@
package org.elasticsearch.index.cache;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
import org.elasticsearch.index.cache.filter.FilterCache;
import org.elasticsearch.index.cache.query.parser.QueryParserCache;
import org.elasticsearch.index.settings.IndexSettings;
import java.io.Closeable;
@ -40,30 +34,18 @@ import java.io.IOException;
/**
*
*/
public class IndexCache extends AbstractIndexComponent implements Closeable, ClusterStateListener {
public class IndexCache extends AbstractIndexComponent implements Closeable {
private final FilterCache filterCache;
private final QueryParserCache queryParserCache;
private final BitsetFilterCache bitsetFilterCache;
private ClusterService clusterService;
@Inject
public IndexCache(Index index, @IndexSettings Settings indexSettings, FilterCache filterCache, QueryParserCache queryParserCache, BitsetFilterCache bitsetFilterCache) {
public IndexCache(Index index, @IndexSettings Settings indexSettings, FilterCache filterCache, BitsetFilterCache bitsetFilterCache) {
super(index, indexSettings);
this.filterCache = filterCache;
this.queryParserCache = queryParserCache;
this.bitsetFilterCache = bitsetFilterCache;
}
@Inject(optional = true)
public void setClusterService(@Nullable ClusterService clusterService) {
this.clusterService = clusterService;
if (clusterService != null) {
clusterService.add(this);
}
}
public FilterCache filter() {
return filterCache;
}
@ -75,29 +57,14 @@ public class IndexCache extends AbstractIndexComponent implements Closeable, Clu
return bitsetFilterCache;
}
public QueryParserCache queryParserCache() {
return this.queryParserCache;
}
@Override
public void close() throws IOException {
IOUtils.close(filterCache, queryParserCache, bitsetFilterCache);
if (clusterService != null) {
clusterService.remove(this);
}
IOUtils.close(filterCache, bitsetFilterCache);
}
public void clear(String reason) {
filterCache.clear(reason);
queryParserCache.clear();
bitsetFilterCache.clear(reason);
}
@Override
public void clusterChanged(ClusterChangedEvent event) {
// clear the query parser cache if the metadata (mappings) changed...
if (event.metaDataChanged()) {
queryParserCache.clear();
}
}
}

View File

@ -23,7 +23,6 @@ import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.cache.bitset.BitsetFilterCacheModule;
import org.elasticsearch.index.cache.filter.FilterCacheModule;
import org.elasticsearch.index.cache.query.parser.QueryParserCacheModule;
/**
*
@ -39,7 +38,6 @@ public class IndexCacheModule extends AbstractModule {
@Override
protected void configure() {
new FilterCacheModule(settings).configure(binder());
new QueryParserCacheModule(settings).configure(binder());
new BitsetFilterCacheModule(settings).configure(binder());
bind(IndexCache.class).asEagerSingleton();

View File

@ -1,39 +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.cache.query.parser;
import org.apache.lucene.queryparser.classic.QueryParserSettings;
import org.apache.lucene.search.Query;
import org.elasticsearch.index.IndexComponent;
import java.io.Closeable;
/**
* The main benefit of the query parser cache is to not parse the same query string on different shards.
* Less about long running query strings.
*/
public interface QueryParserCache extends IndexComponent, Closeable {
Query get(QueryParserSettings queryString);
void put(QueryParserSettings queryString, Query query);
void clear();
}

View File

@ -1,44 +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.cache.query.parser;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Scopes;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.cache.query.parser.resident.ResidentQueryParserCache;
/**
*
*/
public class QueryParserCacheModule extends AbstractModule {
private final Settings settings;
public QueryParserCacheModule(Settings settings) {
this.settings = settings;
}
@Override
protected void configure() {
bind(QueryParserCache.class)
.to(settings.getAsClass("index.cache.query.parser.type", ResidentQueryParserCache.class, "org.elasticsearch.index.cache.query.parser.", "QueryParserCache"))
.in(Scopes.SINGLETON);
}
}

View File

@ -1,58 +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.cache.query.parser.none;
import org.apache.lucene.queryparser.classic.QueryParserSettings;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.cache.query.parser.QueryParserCache;
import org.elasticsearch.index.settings.IndexSettings;
/**
*
*/
public class NoneQueryParserCache extends AbstractIndexComponent implements QueryParserCache {
@Inject
public NoneQueryParserCache(Index index, @IndexSettings Settings indexSettings) {
super(index, indexSettings);
}
@Override
public Query get(QueryParserSettings queryString) {
return null;
}
@Override
public void put(QueryParserSettings queryString, Query query) {
}
@Override
public void clear() {
}
@Override
public void close() throws ElasticsearchException {
}
}

View File

@ -1,90 +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.cache.query.parser.resident;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.lucene.queryparser.classic.QueryParserSettings;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.cache.query.parser.QueryParserCache;
import org.elasticsearch.index.settings.IndexSettings;
import java.util.concurrent.TimeUnit;
/**
* A small (by default) query parser cache mainly to not parse the same query string several times
* if several shards exists on the same node.
*/
public class ResidentQueryParserCache extends AbstractIndexComponent implements QueryParserCache {
private final Cache<QueryParserSettings, Query> cache;
private volatile int maxSize;
private volatile TimeValue expire;
@Inject
public ResidentQueryParserCache(Index index, @IndexSettings Settings indexSettings) {
super(index, indexSettings);
this.maxSize = indexSettings.getAsInt("index.cache.query.parser.resident.max_size", 100);
this.expire = indexSettings.getAsTime("index.cache.query.parser.resident.expire", null);
logger.debug("using [resident] query cache with max_size [{}], expire [{}]", maxSize, expire);
CacheBuilder cacheBuilder = CacheBuilder.newBuilder().maximumSize(maxSize);
if (expire != null) {
cacheBuilder.expireAfterAccess(expire.nanos(), TimeUnit.NANOSECONDS);
}
this.cache = cacheBuilder.build();
}
@Override
public Query get(QueryParserSettings queryString) {
Query value = cache.getIfPresent(queryString);
if (value != null) {
return value.clone();
} else {
return null;
}
}
@Override
public void put(QueryParserSettings queryString, Query query) {
if (queryString.isCacheable()) {
cache.put(queryString, query);
}
}
@Override
public void clear() {
cache.invalidateAll();
}
@Override
public void close() throws ElasticsearchException {
cache.invalidateAll();
}
}

View File

@ -46,14 +46,13 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.index.cache.query.parser.QueryParserCache;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.FieldMappers;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.MapperBuilders;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
import org.elasticsearch.index.query.support.NestedScope;
import org.elasticsearch.index.search.child.CustomQueryWrappingFilter;
@ -64,7 +63,12 @@ import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
@ -182,10 +186,6 @@ public class QueryParseContext {
return indexQueryParser.similarityService != null ? indexQueryParser.similarityService.similarity() : null;
}
public QueryParserCache queryParserCache() {
return indexQueryParser.indexCache.queryParserCache();
}
public String defaultField() {
return indexQueryParser.defaultField();
}

View File

@ -219,18 +219,11 @@ public class QueryStringQueryParser implements QueryParser {
}
qpSettings.queryTypes(parseContext.queryTypes());
Query query = parseContext.queryParserCache().get(qpSettings);
if (query != null) {
if (queryName != null) {
parseContext.addNamedQuery(queryName, query);
}
return query;
}
MapperQueryParser queryParser = parseContext.queryParser(qpSettings);
try {
query = queryParser.parse(qpSettings.queryString());
Query query = queryParser.parse(qpSettings.queryString());
if (query == null) {
return null;
}
@ -241,7 +234,6 @@ public class QueryStringQueryParser implements QueryParser {
if (query instanceof BooleanQuery) {
Queries.applyMinimumShouldMatch((BooleanQuery) query, qpSettings.minimumShouldMatch());
}
parseContext.queryParserCache().put(qpSettings, query);
if (queryName != null) {
parseContext.addNamedQuery(queryName, query);
}

View File

@ -1,54 +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.cache.query.parser.resident;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParserSettings;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.index.Index;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
/**
*/
public class ResidentQueryParserCacheTest extends ElasticsearchTestCase {
@Test
public void testCaching() throws Exception {
ResidentQueryParserCache cache = new ResidentQueryParserCache(new Index("test"), ImmutableSettings.EMPTY);
QueryParserSettings key = new QueryParserSettings();
key.queryString("abc");
key.defaultField("a");
key.boost(2.0f);
Query query = new TermQuery(new Term("a", "abc"));
cache.put(key, query);
assertThat(cache.get(key), not(sameInstance(query)));
assertThat(cache.get(key), equalTo(query));
}
}