Merge pull request #10856 from jpountz/fix/remove_qparser_cache

Internal: Remove the query parser cache.
This commit is contained in:
Adrien Grand 2015-04-29 09:45:51 +02:00
commit c23d550823
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));
}
}