Plugins: one single (global) way to register custom query parsers
There are different ways to register custom query parsers through plugins, a couple of them work per index via index settings, which is probably even too flexible. There also three different ways to add a global custom query parser through either IndicesQueriesModule or IndicesQueriesRegistry. This commit consolidates the registration of custom query parsers via IndicesQueriesModule#addQuery(Class<? extends QueryParser>). The complexity of supporting parsers per index is not needed hence it got removed. Also the other ways of registering global custom parsers are dropped in favour of the one mentioned above. Closes #11481
This commit is contained in:
parent
f336cea35e
commit
2ef0fcfd6a
|
@ -1,134 +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.query;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.Scopes;
|
|
||||||
import org.elasticsearch.common.inject.assistedinject.FactoryProvider;
|
|
||||||
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.index.query.support.InnerHitsQueryParserHelper;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IndexQueryParserModule extends AbstractModule {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom processor that can be extended to process and bind custom implementations of
|
|
||||||
* {@link QueryParserFactory}, and {@link FilterParser}.
|
|
||||||
*/
|
|
||||||
public static class QueryParsersProcessor {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension point to bind a custom {@link QueryParserFactory}.
|
|
||||||
*/
|
|
||||||
public void processXContentQueryParsers(XContentQueryParsersBindings bindings) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class XContentQueryParsersBindings {
|
|
||||||
|
|
||||||
private final MapBinder<String, QueryParserFactory> binder;
|
|
||||||
private final Map<String, Settings> groupSettings;
|
|
||||||
|
|
||||||
public XContentQueryParsersBindings(MapBinder<String, QueryParserFactory> binder, Map<String, Settings> groupSettings) {
|
|
||||||
this.binder = binder;
|
|
||||||
this.groupSettings = groupSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapBinder<String, QueryParserFactory> binder() {
|
|
||||||
return binder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Settings> groupSettings() {
|
|
||||||
return groupSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processXContentQueryParser(String name, Class<? extends QueryParser> xcontentQueryParser) {
|
|
||||||
if (!groupSettings.containsKey(name)) {
|
|
||||||
binder.addBinding(name).toProvider(FactoryProvider.newFactory(QueryParserFactory.class, xcontentQueryParser)).in(Scopes.SINGLETON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Settings settings;
|
|
||||||
|
|
||||||
private final LinkedList<QueryParsersProcessor> processors = Lists.newLinkedList();
|
|
||||||
|
|
||||||
private final Map<String, Class<? extends QueryParser>> queries = Maps.newHashMap();
|
|
||||||
|
|
||||||
public IndexQueryParserModule(Settings settings) {
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a custom query parser.
|
|
||||||
*
|
|
||||||
* @param name The name of the query parser
|
|
||||||
* @param queryParser the class of the query parser
|
|
||||||
*/
|
|
||||||
public void addQueryParser(String name, Class<? extends QueryParser> queryParser) {
|
|
||||||
queries.put(name, queryParser);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IndexQueryParserModule addProcessor(QueryParsersProcessor processor) {
|
|
||||||
processors.addFirst(processor);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
|
|
||||||
bind(IndexQueryParserService.class).asEagerSingleton();
|
|
||||||
bind(InnerHitsQueryParserHelper.class).asEagerSingleton();
|
|
||||||
|
|
||||||
// handle XContenQueryParsers
|
|
||||||
MapBinder<String, QueryParserFactory> queryBinder
|
|
||||||
= MapBinder.newMapBinder(binder(), String.class, QueryParserFactory.class);
|
|
||||||
Map<String, Settings> xContentQueryParserGroups = settings.getGroups(IndexQueryParserService.Defaults.QUERY_PREFIX);
|
|
||||||
for (Map.Entry<String, Settings> entry : xContentQueryParserGroups.entrySet()) {
|
|
||||||
String qName = entry.getKey();
|
|
||||||
Settings qSettings = entry.getValue();
|
|
||||||
Class<? extends QueryParser> type = qSettings.getAsClass("type", null);
|
|
||||||
if (type == null) {
|
|
||||||
throw new IllegalArgumentException("Query Parser [" + qName + "] must be provided with a type");
|
|
||||||
}
|
|
||||||
queryBinder.addBinding(qName).toProvider(FactoryProvider.newFactory(QueryParserFactory.class,
|
|
||||||
qSettings.getAsClass("type", null))).in(Scopes.SINGLETON);
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryParsersProcessor.XContentQueryParsersBindings xContentQueryParsersBindings = new QueryParsersProcessor.XContentQueryParsersBindings(queryBinder, xContentQueryParserGroups);
|
|
||||||
for (QueryParsersProcessor processor : processors) {
|
|
||||||
processor.processXContentQueryParsers(xContentQueryParsersBindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, Class<? extends QueryParser>> entry : queries.entrySet()) {
|
|
||||||
queryBinder.addBinding(entry.getKey()).toProvider(FactoryProvider.newFactory(QueryParserFactory.class, entry.getValue())).in(Scopes.SINGLETON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
|
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.util.CloseableThreadLocal;
|
import org.apache.lucene.util.CloseableThreadLocal;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
|
@ -48,23 +46,12 @@ import org.elasticsearch.script.ScriptService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
|
||||||
import static com.google.common.collect.Maps.newHashMap;
|
|
||||||
import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class IndexQueryParserService extends AbstractIndexComponent {
|
public class IndexQueryParserService extends AbstractIndexComponent {
|
||||||
|
|
||||||
public static final class Defaults {
|
|
||||||
public static final String QUERY_PREFIX = "index.queryparser.query";
|
|
||||||
public static final String FILTER_PREFIX = "index.queryparser.filter";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String DEFAULT_FIELD = "index.query.default_field";
|
public static final String DEFAULT_FIELD = "index.query.default_field";
|
||||||
public static final String QUERY_STRING_LENIENT = "index.query_string.lenient";
|
public static final String QUERY_STRING_LENIENT = "index.query_string.lenient";
|
||||||
public static final String PARSE_STRICT = "index.query.parse.strict";
|
public static final String PARSE_STRICT = "index.query.parse.strict";
|
||||||
|
@ -91,7 +78,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
||||||
|
|
||||||
final BitsetFilterCache bitsetFilterCache;
|
final BitsetFilterCache bitsetFilterCache;
|
||||||
|
|
||||||
private final Map<String, QueryParser> queryParsers;
|
private final IndicesQueriesRegistry indicesQueriesRegistry;
|
||||||
|
|
||||||
private String defaultField;
|
private String defaultField;
|
||||||
private boolean queryStringLenient;
|
private boolean queryStringLenient;
|
||||||
|
@ -104,8 +91,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
||||||
ScriptService scriptService, AnalysisService analysisService,
|
ScriptService scriptService, AnalysisService analysisService,
|
||||||
MapperService mapperService, IndexCache indexCache, IndexFieldDataService fieldDataService,
|
MapperService mapperService, IndexCache indexCache, IndexFieldDataService fieldDataService,
|
||||||
BitsetFilterCache bitsetFilterCache,
|
BitsetFilterCache bitsetFilterCache,
|
||||||
@Nullable SimilarityService similarityService,
|
@Nullable SimilarityService similarityService) {
|
||||||
@Nullable Map<String, QueryParserFactory> namedQueryParsers) {
|
|
||||||
super(index, indexSettings);
|
super(index, indexSettings);
|
||||||
this.scriptService = scriptService;
|
this.scriptService = scriptService;
|
||||||
this.analysisService = analysisService;
|
this.analysisService = analysisService;
|
||||||
|
@ -119,29 +105,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
||||||
this.queryStringLenient = indexSettings.getAsBoolean(QUERY_STRING_LENIENT, false);
|
this.queryStringLenient = indexSettings.getAsBoolean(QUERY_STRING_LENIENT, false);
|
||||||
this.strict = indexSettings.getAsBoolean(PARSE_STRICT, false);
|
this.strict = indexSettings.getAsBoolean(PARSE_STRICT, false);
|
||||||
this.defaultAllowUnmappedFields = indexSettings.getAsBoolean(ALLOW_UNMAPPED, true);
|
this.defaultAllowUnmappedFields = indexSettings.getAsBoolean(ALLOW_UNMAPPED, true);
|
||||||
|
this.indicesQueriesRegistry = indicesQueriesRegistry;
|
||||||
List<QueryParser> queryParsers = newArrayList();
|
|
||||||
if (namedQueryParsers != null) {
|
|
||||||
Map<String, Settings> queryParserGroups = indexSettings.getGroups(IndexQueryParserService.Defaults.QUERY_PREFIX);
|
|
||||||
for (Map.Entry<String, QueryParserFactory> entry : namedQueryParsers.entrySet()) {
|
|
||||||
String queryParserName = entry.getKey();
|
|
||||||
QueryParserFactory queryParserFactory = entry.getValue();
|
|
||||||
Settings queryParserSettings = queryParserGroups.get(queryParserName);
|
|
||||||
if (queryParserSettings == null) {
|
|
||||||
queryParserSettings = EMPTY_SETTINGS;
|
|
||||||
}
|
|
||||||
queryParsers.add(queryParserFactory.create(queryParserName, queryParserSettings));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, QueryParser> queryParsersMap = newHashMap();
|
|
||||||
queryParsersMap.putAll(indicesQueriesRegistry.queryParsers());
|
|
||||||
if (queryParsers != null) {
|
|
||||||
for (QueryParser queryParser : queryParsers) {
|
|
||||||
add(queryParsersMap, queryParser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.queryParsers = ImmutableMap.copyOf(queryParsersMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -157,7 +121,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryParser queryParser(String name) {
|
public QueryParser queryParser(String name) {
|
||||||
return queryParsers.get(name);
|
return indicesQueriesRegistry.queryParsers().get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParsedQuery parse(QueryBuilder queryBuilder) {
|
public ParsedQuery parse(QueryBuilder queryBuilder) {
|
||||||
|
@ -349,10 +313,4 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
||||||
parseContext.reset(null);
|
parseContext.reset(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add(Map<String, QueryParser> map, QueryParser queryParser) {
|
|
||||||
for (String name : queryParser.names()) {
|
|
||||||
map.put(name.intern(), queryParser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +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.query;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public interface QueryParserFactory {
|
|
||||||
|
|
||||||
QueryParser create(String name, Settings settings);
|
|
||||||
}
|
|
|
@ -57,7 +57,6 @@ import org.elasticsearch.index.indexing.IndexingStats;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.mapper.MapperServiceModule;
|
import org.elasticsearch.index.mapper.MapperServiceModule;
|
||||||
import org.elasticsearch.index.merge.MergeStats;
|
import org.elasticsearch.index.merge.MergeStats;
|
||||||
import org.elasticsearch.index.query.IndexQueryParserModule;
|
|
||||||
import org.elasticsearch.index.query.IndexQueryParserService;
|
import org.elasticsearch.index.query.IndexQueryParserService;
|
||||||
import org.elasticsearch.index.recovery.RecoveryStats;
|
import org.elasticsearch.index.recovery.RecoveryStats;
|
||||||
import org.elasticsearch.index.refresh.RefreshStats;
|
import org.elasticsearch.index.refresh.RefreshStats;
|
||||||
|
@ -315,7 +314,6 @@ public class IndicesService extends AbstractLifecycleComponent<IndicesService> i
|
||||||
modules.add(new IndexCacheModule(indexSettings));
|
modules.add(new IndexCacheModule(indexSettings));
|
||||||
modules.add(new IndexFieldDataModule(indexSettings));
|
modules.add(new IndexFieldDataModule(indexSettings));
|
||||||
modules.add(new MapperServiceModule());
|
modules.add(new MapperServiceModule());
|
||||||
modules.add(new IndexQueryParserModule(indexSettings));
|
|
||||||
modules.add(new IndexAliasesServiceModule());
|
modules.add(new IndexAliasesServiceModule());
|
||||||
modules.add(new IndexModule(indexSettings));
|
modules.add(new IndexModule(indexSettings));
|
||||||
|
|
||||||
|
|
|
@ -30,30 +30,21 @@ import java.util.Set;
|
||||||
|
|
||||||
public class IndicesQueriesModule extends AbstractModule {
|
public class IndicesQueriesModule extends AbstractModule {
|
||||||
|
|
||||||
private Set<Class<QueryParser>> queryParsersClasses = Sets.newHashSet();
|
private Set<Class<? extends QueryParser>> queryParsersClasses = Sets.newHashSet();
|
||||||
private Set<QueryParser> queryParsers = Sets.newHashSet();
|
|
||||||
|
|
||||||
public synchronized IndicesQueriesModule addQuery(Class<QueryParser> queryParser) {
|
public synchronized IndicesQueriesModule addQuery(Class<? extends QueryParser> queryParser) {
|
||||||
queryParsersClasses.add(queryParser);
|
queryParsersClasses.add(queryParser);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized IndicesQueriesModule addQuery(QueryParser queryParser) {
|
|
||||||
queryParsers.add(queryParser);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(IndicesQueriesRegistry.class).asEagerSingleton();
|
bind(IndicesQueriesRegistry.class).asEagerSingleton();
|
||||||
|
|
||||||
Multibinder<QueryParser> qpBinders = Multibinder.newSetBinder(binder(), QueryParser.class);
|
Multibinder<QueryParser> qpBinders = Multibinder.newSetBinder(binder(), QueryParser.class);
|
||||||
for (Class<QueryParser> queryParser : queryParsersClasses) {
|
for (Class<? extends QueryParser> queryParser : queryParsersClasses) {
|
||||||
qpBinders.addBinding().to(queryParser).asEagerSingleton();
|
qpBinders.addBinding().to(queryParser).asEagerSingleton();
|
||||||
}
|
}
|
||||||
for (QueryParser queryParser : queryParsers) {
|
|
||||||
qpBinders.addBinding().toInstance(queryParser);
|
|
||||||
}
|
|
||||||
qpBinders.addBinding().to(MatchQueryParser.class).asEagerSingleton();
|
qpBinders.addBinding().to(MatchQueryParser.class).asEagerSingleton();
|
||||||
qpBinders.addBinding().to(MultiMatchQueryParser.class).asEagerSingleton();
|
qpBinders.addBinding().to(MultiMatchQueryParser.class).asEagerSingleton();
|
||||||
qpBinders.addBinding().to(NestedQueryParser.class).asEagerSingleton();
|
qpBinders.addBinding().to(NestedQueryParser.class).asEagerSingleton();
|
||||||
|
|
|
@ -30,9 +30,6 @@ import org.elasticsearch.index.query.QueryParser;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IndicesQueriesRegistry extends AbstractComponent {
|
public class IndicesQueriesRegistry extends AbstractComponent {
|
||||||
|
|
||||||
private ImmutableMap<String, QueryParser> queryParsers;
|
private ImmutableMap<String, QueryParser> queryParsers;
|
||||||
|
@ -42,27 +39,17 @@ public class IndicesQueriesRegistry extends AbstractComponent {
|
||||||
super(settings);
|
super(settings);
|
||||||
Map<String, QueryParser> queryParsers = Maps.newHashMap();
|
Map<String, QueryParser> queryParsers = Maps.newHashMap();
|
||||||
for (QueryParser queryParser : injectedQueryParsers) {
|
for (QueryParser queryParser : injectedQueryParsers) {
|
||||||
addQueryParser(queryParsers, queryParser);
|
for (String name : queryParser.names()) {
|
||||||
|
queryParsers.put(name, queryParser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.queryParsers = ImmutableMap.copyOf(queryParsers);
|
this.queryParsers = ImmutableMap.copyOf(queryParsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a global query parser.
|
* Returns all the registered query parsers
|
||||||
*/
|
*/
|
||||||
public synchronized void addQueryParser(QueryParser queryParser) {
|
|
||||||
Map<String, QueryParser> queryParsers = Maps.newHashMap(this.queryParsers);
|
|
||||||
addQueryParser(queryParsers, queryParser);
|
|
||||||
this.queryParsers = ImmutableMap.copyOf(queryParsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImmutableMap<String, QueryParser> queryParsers() {
|
public ImmutableMap<String, QueryParser> queryParsers() {
|
||||||
return queryParsers;
|
return queryParsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addQueryParser(Map<String, QueryParser> queryParsers, QueryParser queryParser) {
|
|
||||||
for (String name : queryParser.names()) {
|
|
||||||
queryParsers.put(name, queryParser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -41,7 +41,6 @@ import org.elasticsearch.action.termvectors.*;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
import org.elasticsearch.common.compress.CompressedXContent;
|
import org.elasticsearch.common.compress.CompressedXContent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.lucene.search.MoreLikeThisQuery;
|
import org.elasticsearch.common.lucene.search.MoreLikeThisQuery;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
import org.elasticsearch.common.lucene.search.function.BoostScoreFunction;
|
import org.elasticsearch.common.lucene.search.function.BoostScoreFunction;
|
||||||
|
@ -50,12 +49,9 @@ import org.elasticsearch.common.lucene.search.function.WeightFactorFunction;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.AbstractIndexComponent;
|
|
||||||
import org.elasticsearch.index.Index;
|
|
||||||
import org.elasticsearch.index.IndexService;
|
import org.elasticsearch.index.IndexService;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.mapper.ParsedDocument;
|
import org.elasticsearch.index.mapper.ParsedDocument;
|
||||||
|
@ -71,7 +67,6 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -83,61 +78,13 @@ import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||||
|
|
||||||
private IndexQueryParserService queryParser;
|
private IndexQueryParserService queryParser;
|
||||||
|
|
||||||
private static class DummyQuery extends Query {
|
|
||||||
|
|
||||||
public boolean isFilter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(String field) {
|
|
||||||
return getClass().getSimpleName();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DummyQueryParser extends AbstractIndexComponent implements QueryParser {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DummyQueryParser(Index index, Settings indexSettings) {
|
|
||||||
super(index, indexSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] names() {
|
|
||||||
return new String[] {"dummy"};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
|
||||||
assertEquals(XContentParser.Token.END_OBJECT, parseContext.parser().nextToken());
|
|
||||||
DummyQuery query = new DummyQuery();
|
|
||||||
query.isFilter = parseContext.isFilter();
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DummyQueryBuilder extends QueryBuilder {
|
|
||||||
@Override
|
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
|
||||||
builder.startObject("dummy").endObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DummyQueryBuilder dummyQuery() {
|
|
||||||
return new DummyQueryBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
Settings settings = Settings.settingsBuilder()
|
Settings settings = Settings.settingsBuilder()
|
||||||
.put("index.queryparser.query.dummy.type", DummyQueryParser.class)
|
|
||||||
.put("index.cache.filter.type", "none")
|
.put("index.cache.filter.type", "none")
|
||||||
.put("name", "SimpleIndexQueryParserTests")
|
.put("name", "SimpleIndexQueryParserTests")
|
||||||
.build();
|
.build();
|
||||||
|
@ -1063,7 +1010,6 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||||
assertThat(clauses[3].getOccur(), equalTo(BooleanClause.Occur.SHOULD));
|
assertThat(clauses[3].getOccur(), equalTo(BooleanClause.Occur.SHOULD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoolQuery() throws IOException {
|
public void testBoolQuery() throws IOException {
|
||||||
IndexQueryParserService queryParser = queryParser();
|
IndexQueryParserService queryParser = queryParser();
|
||||||
|
@ -1964,7 +1910,6 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||||
assertThat(filter.bottomRight().lon(), closeTo(-80, 0.00001));
|
assertThat(filter.bottomRight().lon(), closeTo(-80, 0.00001));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGeoBoundingBoxFilter1() throws IOException {
|
public void testGeoBoundingBoxFilter1() throws IOException {
|
||||||
IndexQueryParserService queryParser = queryParser();
|
IndexQueryParserService queryParser = queryParser();
|
||||||
|
@ -2464,72 +2409,11 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||||
public void testTermsQueryFilter() throws Exception {
|
public void testTermsQueryFilter() throws Exception {
|
||||||
// TermsQuery is tricky in that it parses differently as a query or a filter
|
// TermsQuery is tricky in that it parses differently as a query or a filter
|
||||||
IndexQueryParserService queryParser = queryParser();
|
IndexQueryParserService queryParser = queryParser();
|
||||||
Query q = queryParser.parse(termsQuery("foo", Arrays.asList("bar"))).query();
|
Query q = queryParser.parse(termsQuery("foo", "bar")).query();
|
||||||
assertThat(q, instanceOf(BooleanQuery.class));
|
assertThat(q, instanceOf(BooleanQuery.class));
|
||||||
|
|
||||||
ConstantScoreQuery csq = (ConstantScoreQuery) queryParser.parse(constantScoreQuery(termsQuery("foo", Arrays.asList("bar")))).query();
|
ConstantScoreQuery csq = (ConstantScoreQuery) queryParser.parse(constantScoreQuery(termsQuery("foo", "bar"))).query();
|
||||||
q = csq.getQuery();
|
q = csq.getQuery();
|
||||||
assertThat(q, instanceOf(TermsQuery.class));
|
assertThat(q, instanceOf(TermsQuery.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConstantScoreParsesFilter() throws Exception {
|
|
||||||
IndexQueryParserService queryParser = queryParser();
|
|
||||||
Query q = queryParser.parse(constantScoreQuery(dummyQuery())).query();
|
|
||||||
Query inner = ((ConstantScoreQuery) q).getQuery();
|
|
||||||
assertThat(inner, instanceOf(DummyQuery.class));
|
|
||||||
assertEquals(true, ((DummyQuery) inner).isFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testBooleanParsesFilter() throws Exception {
|
|
||||||
IndexQueryParserService queryParser = queryParser();
|
|
||||||
// single clause, serialized as inner object
|
|
||||||
Query q = queryParser.parse(boolQuery()
|
|
||||||
.should(dummyQuery())
|
|
||||||
.must(dummyQuery())
|
|
||||||
.filter(dummyQuery())
|
|
||||||
.mustNot(dummyQuery())).query();
|
|
||||||
assertThat(q, instanceOf(BooleanQuery.class));
|
|
||||||
BooleanQuery bq = (BooleanQuery) q;
|
|
||||||
assertEquals(4, bq.clauses().size());
|
|
||||||
for (BooleanClause clause : bq.clauses()) {
|
|
||||||
DummyQuery dummy = (DummyQuery) clause.getQuery();
|
|
||||||
switch (clause.getOccur()) {
|
|
||||||
case FILTER:
|
|
||||||
case MUST_NOT:
|
|
||||||
assertEquals(true, dummy.isFilter);
|
|
||||||
break;
|
|
||||||
case MUST:
|
|
||||||
case SHOULD:
|
|
||||||
assertEquals(false, dummy.isFilter);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiple clauses, serialized as inner arrays
|
|
||||||
q = queryParser.parse(boolQuery()
|
|
||||||
.should(dummyQuery()).should(dummyQuery())
|
|
||||||
.must(dummyQuery()).must(dummyQuery())
|
|
||||||
.filter(dummyQuery()).filter(dummyQuery())
|
|
||||||
.mustNot(dummyQuery()).mustNot(dummyQuery())).query();
|
|
||||||
assertThat(q, instanceOf(BooleanQuery.class));
|
|
||||||
bq = (BooleanQuery) q;
|
|
||||||
assertEquals(8, bq.clauses().size());
|
|
||||||
for (BooleanClause clause : bq.clauses()) {
|
|
||||||
DummyQuery dummy = (DummyQuery) clause.getQuery();
|
|
||||||
switch (clause.getOccur()) {
|
|
||||||
case FILTER:
|
|
||||||
case MUST_NOT:
|
|
||||||
assertEquals(true, dummy.isFilter);
|
|
||||||
break;
|
|
||||||
case MUST:
|
|
||||||
case SHOULD:
|
|
||||||
assertEquals(false, dummy.isFilter);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,6 @@ public class TemplateQueryParserTest extends ElasticsearchTestCase {
|
||||||
new AnalysisModule(settings),
|
new AnalysisModule(settings),
|
||||||
new SimilarityModule(settings),
|
new SimilarityModule(settings),
|
||||||
new IndexNameModule(index),
|
new IndexNameModule(index),
|
||||||
new IndexQueryParserModule(settings),
|
|
||||||
new FunctionScoreModule(),
|
new FunctionScoreModule(),
|
||||||
new AbstractModule() {
|
new AbstractModule() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,51 +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.query.guice;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.index.query.IndexQueryParserService;
|
|
||||||
import org.elasticsearch.test.ElasticsearchSingleNodeTest;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IndexQueryParserModuleTests extends ElasticsearchSingleNodeTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCustomInjection() {
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put("index.queryparser.query.my.type", MyJsonQueryParser.class)
|
|
||||||
.put("index.queryparser.query.my.param1", "value1")
|
|
||||||
.put("index.cache.filter.type", "none")
|
|
||||||
.put("name", "IndexQueryParserModuleTests")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
IndexQueryParserService indexQueryParserService = createIndex("test", settings).queryParserService();
|
|
||||||
|
|
||||||
MyJsonQueryParser myJsonQueryParser = (MyJsonQueryParser) indexQueryParserService.queryParser("my");
|
|
||||||
|
|
||||||
assertThat(myJsonQueryParser.names()[0], equalTo("my"));
|
|
||||||
assertThat(myJsonQueryParser.settings().get("param1"), equalTo("value1"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +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.query.guice;
|
|
||||||
|
|
||||||
import org.apache.lucene.search.Query;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.inject.assistedinject.Assisted;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.index.AbstractIndexComponent;
|
|
||||||
import org.elasticsearch.index.Index;
|
|
||||||
import org.elasticsearch.index.query.QueryParseContext;
|
|
||||||
import org.elasticsearch.index.query.QueryParser;
|
|
||||||
import org.elasticsearch.index.query.QueryParsingException;
|
|
||||||
import org.elasticsearch.index.settings.IndexSettings;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class MyJsonQueryParser extends AbstractIndexComponent implements QueryParser {
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private final Settings settings;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public MyJsonQueryParser(Index index, @IndexSettings Settings indexSettings, @Assisted String name, @Assisted Settings settings) {
|
|
||||||
super(index, indexSettings);
|
|
||||||
this.name = name;
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] names() {
|
|
||||||
return new String[]{this.name};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Settings settings() {
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +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.query.plugin;
|
|
||||||
|
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.cluster.ClusterService;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.Injector;
|
|
||||||
import org.elasticsearch.common.inject.ModulesBuilder;
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.settings.SettingsModule;
|
|
||||||
import org.elasticsearch.env.Environment;
|
|
||||||
import org.elasticsearch.env.EnvironmentModule;
|
|
||||||
import org.elasticsearch.index.Index;
|
|
||||||
import org.elasticsearch.index.IndexNameModule;
|
|
||||||
import org.elasticsearch.index.analysis.AnalysisModule;
|
|
||||||
import org.elasticsearch.index.cache.IndexCacheModule;
|
|
||||||
import org.elasticsearch.index.query.IndexQueryParserModule;
|
|
||||||
import org.elasticsearch.index.query.IndexQueryParserService;
|
|
||||||
import org.elasticsearch.index.query.functionscore.FunctionScoreModule;
|
|
||||||
import org.elasticsearch.index.settings.IndexSettingsModule;
|
|
||||||
import org.elasticsearch.index.similarity.SimilarityModule;
|
|
||||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
|
||||||
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
|
||||||
import org.elasticsearch.indices.query.IndicesQueriesModule;
|
|
||||||
import org.elasticsearch.script.ScriptModule;
|
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPoolModule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IndexQueryParserPlugin2Tests extends ElasticsearchTestCase {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCustomInjection() throws InterruptedException {
|
|
||||||
Settings settings = Settings.builder()
|
|
||||||
.put("name", "testCustomInjection")
|
|
||||||
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
|
|
||||||
.put("path.home", createTempDir()).build();
|
|
||||||
|
|
||||||
IndexQueryParserModule queryParserModule = new IndexQueryParserModule(settings);
|
|
||||||
queryParserModule.addQueryParser("my", PluginJsonQueryParser.class);
|
|
||||||
|
|
||||||
Index index = new Index("test");
|
|
||||||
Injector injector = new ModulesBuilder().add(
|
|
||||||
new EnvironmentModule(new Environment(settings)),
|
|
||||||
new SettingsModule(settings),
|
|
||||||
new ThreadPoolModule(new ThreadPool(settings)),
|
|
||||||
new IndicesQueriesModule(),
|
|
||||||
new ScriptModule(settings),
|
|
||||||
new IndexSettingsModule(index, settings),
|
|
||||||
new IndexCacheModule(settings),
|
|
||||||
new AnalysisModule(settings),
|
|
||||||
new SimilarityModule(settings),
|
|
||||||
queryParserModule,
|
|
||||||
new IndexNameModule(index),
|
|
||||||
new FunctionScoreModule(),
|
|
||||||
new AbstractModule() {
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
bind(ClusterService.class).toProvider(Providers.of((ClusterService) null));
|
|
||||||
bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).createInjector();
|
|
||||||
|
|
||||||
IndexQueryParserService indexQueryParserService = injector.getInstance(IndexQueryParserService.class);
|
|
||||||
|
|
||||||
PluginJsonQueryParser myJsonQueryParser = (PluginJsonQueryParser) indexQueryParserService.queryParser("my");
|
|
||||||
|
|
||||||
assertThat(myJsonQueryParser.names()[0], equalTo("my"));
|
|
||||||
|
|
||||||
terminate(injector.getInstance(ThreadPool.class));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +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.query.plugin;
|
|
||||||
|
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.cluster.ClusterService;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.Injector;
|
|
||||||
import org.elasticsearch.common.inject.ModulesBuilder;
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.settings.SettingsModule;
|
|
||||||
import org.elasticsearch.env.Environment;
|
|
||||||
import org.elasticsearch.env.EnvironmentModule;
|
|
||||||
import org.elasticsearch.index.Index;
|
|
||||||
import org.elasticsearch.index.IndexNameModule;
|
|
||||||
import org.elasticsearch.index.analysis.AnalysisModule;
|
|
||||||
import org.elasticsearch.index.cache.IndexCacheModule;
|
|
||||||
import org.elasticsearch.index.query.IndexQueryParserModule;
|
|
||||||
import org.elasticsearch.index.query.IndexQueryParserService;
|
|
||||||
import org.elasticsearch.index.query.functionscore.FunctionScoreModule;
|
|
||||||
import org.elasticsearch.index.settings.IndexSettingsModule;
|
|
||||||
import org.elasticsearch.index.similarity.SimilarityModule;
|
|
||||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
|
||||||
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
|
||||||
import org.elasticsearch.indices.query.IndicesQueriesModule;
|
|
||||||
import org.elasticsearch.script.ScriptModule;
|
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPoolModule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IndexQueryParserPluginTests extends ElasticsearchTestCase {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCustomInjection() throws InterruptedException {
|
|
||||||
Settings settings = Settings.builder()
|
|
||||||
.put("name", "testCustomInjection")
|
|
||||||
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
|
|
||||||
.put("path.home", createTempDir()).build();
|
|
||||||
|
|
||||||
IndexQueryParserModule queryParserModule = new IndexQueryParserModule(settings);
|
|
||||||
queryParserModule.addProcessor(new IndexQueryParserModule.QueryParsersProcessor() {
|
|
||||||
@Override
|
|
||||||
public void processXContentQueryParsers(XContentQueryParsersBindings bindings) {
|
|
||||||
bindings.processXContentQueryParser("my", PluginJsonQueryParser.class);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Index index = new Index("test");
|
|
||||||
Injector injector = new ModulesBuilder().add(
|
|
||||||
new EnvironmentModule(new Environment(settings)),
|
|
||||||
new SettingsModule(settings),
|
|
||||||
new ThreadPoolModule(new ThreadPool(settings)),
|
|
||||||
new IndicesQueriesModule(),
|
|
||||||
new ScriptModule(settings),
|
|
||||||
new IndexSettingsModule(index, settings),
|
|
||||||
new IndexCacheModule(settings),
|
|
||||||
new AnalysisModule(settings),
|
|
||||||
new SimilarityModule(settings),
|
|
||||||
queryParserModule,
|
|
||||||
new IndexNameModule(index),
|
|
||||||
new FunctionScoreModule(),
|
|
||||||
new AbstractModule() {
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
bind(ClusterService.class).toProvider(Providers.of((ClusterService) null));
|
|
||||||
bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).createInjector();
|
|
||||||
|
|
||||||
IndexQueryParserService indexQueryParserService = injector.getInstance(IndexQueryParserService.class);
|
|
||||||
|
|
||||||
PluginJsonQueryParser myJsonQueryParser = (PluginJsonQueryParser) indexQueryParserService.queryParser("my");
|
|
||||||
|
|
||||||
assertThat(myJsonQueryParser.names()[0], equalTo("my"));
|
|
||||||
|
|
||||||
terminate(injector.getInstance(ThreadPool.class));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +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.query.plugin;
|
|
||||||
|
|
||||||
import org.apache.lucene.search.Query;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.inject.assistedinject.Assisted;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.index.AbstractIndexComponent;
|
|
||||||
import org.elasticsearch.index.Index;
|
|
||||||
import org.elasticsearch.index.query.QueryParseContext;
|
|
||||||
import org.elasticsearch.index.query.QueryParser;
|
|
||||||
import org.elasticsearch.index.query.QueryParsingException;
|
|
||||||
import org.elasticsearch.index.settings.IndexSettings;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PluginJsonQueryParser extends AbstractIndexComponent implements QueryParser {
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private final Settings settings;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public PluginJsonQueryParser(Index index, @IndexSettings Settings indexSettings, @Assisted String name, @Assisted Settings settings) {
|
|
||||||
super(index, indexSettings);
|
|
||||||
this.name = name;
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] names() {
|
|
||||||
return new String[]{this.name};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Settings settings() {
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -490,6 +490,10 @@ ignored. Instead filters are always used as their own cache key and elasticsearc
|
||||||
makes decisions by itself about whether it should cache filters based on how
|
makes decisions by itself about whether it should cache filters based on how
|
||||||
often they are used.
|
often they are used.
|
||||||
|
|
||||||
|
Java plugins that register custom queries can do so by using the
|
||||||
|
`IndicesQueriesModule#addQuery(Class<? extends QueryParser>)` method. Other
|
||||||
|
ways to register custom queries are not supported anymore.
|
||||||
|
|
||||||
==== Query/filter merge
|
==== Query/filter merge
|
||||||
|
|
||||||
Elasticsearch no longer makes a difference between queries and filters in the
|
Elasticsearch no longer makes a difference between queries and filters in the
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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.query.plugin;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.BooleanClause;
|
||||||
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
|
import org.apache.lucene.search.ConstantScoreQuery;
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.IndexQueryParserService;
|
||||||
|
import org.elasticsearch.indices.IndicesService;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
|
||||||
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||||
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
|
|
||||||
|
public class CustomQueryParserTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
|
||||||
|
.put("plugin.types", DummyQueryParserPlugin.class.getName()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
createIndex("test");
|
||||||
|
ensureGreen();
|
||||||
|
client().prepareIndex("index", "type", "1").setSource("field", "value").get();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int numberOfShards() {
|
||||||
|
return cluster().numDataNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomDummyQuery() {
|
||||||
|
assertHitCount(client().prepareSearch("index").setQuery(new DummyQueryParserPlugin.DummyQueryBuilder()).get(), 1l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomDummyQueryWithinBooleanQuery() {
|
||||||
|
assertHitCount(client().prepareSearch("index").setQuery(new BoolQueryBuilder().must(new DummyQueryParserPlugin.DummyQueryBuilder())).get(), 1l);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IndexQueryParserService queryParser() {
|
||||||
|
IndicesService indicesService = internalCluster().getDataNodeInstance(IndicesService.class);
|
||||||
|
return indicesService.indexServiceSafe("index").queryParserService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test //see #11120
|
||||||
|
public void testConstantScoreParsesFilter() throws Exception {
|
||||||
|
IndexQueryParserService queryParser = queryParser();
|
||||||
|
Query q = queryParser.parse(constantScoreQuery(new DummyQueryParserPlugin.DummyQueryBuilder())).query();
|
||||||
|
Query inner = ((ConstantScoreQuery) q).getQuery();
|
||||||
|
assertThat(inner, instanceOf(DummyQueryParserPlugin.DummyQuery.class));
|
||||||
|
assertEquals(true, ((DummyQueryParserPlugin.DummyQuery) inner).isFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test //see #11120
|
||||||
|
public void testBooleanParsesFilter() throws Exception {
|
||||||
|
IndexQueryParserService queryParser = queryParser();
|
||||||
|
// single clause, serialized as inner object
|
||||||
|
Query q = queryParser.parse(boolQuery()
|
||||||
|
.should(new DummyQueryParserPlugin.DummyQueryBuilder())
|
||||||
|
.must(new DummyQueryParserPlugin.DummyQueryBuilder())
|
||||||
|
.filter(new DummyQueryParserPlugin.DummyQueryBuilder())
|
||||||
|
.mustNot(new DummyQueryParserPlugin.DummyQueryBuilder())).query();
|
||||||
|
assertThat(q, instanceOf(BooleanQuery.class));
|
||||||
|
BooleanQuery bq = (BooleanQuery) q;
|
||||||
|
assertEquals(4, bq.clauses().size());
|
||||||
|
for (BooleanClause clause : bq.clauses()) {
|
||||||
|
DummyQueryParserPlugin.DummyQuery dummy = (DummyQueryParserPlugin.DummyQuery) clause.getQuery();
|
||||||
|
switch (clause.getOccur()) {
|
||||||
|
case FILTER:
|
||||||
|
case MUST_NOT:
|
||||||
|
assertEquals(true, dummy.isFilter);
|
||||||
|
break;
|
||||||
|
case MUST:
|
||||||
|
case SHOULD:
|
||||||
|
assertEquals(false, dummy.isFilter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiple clauses, serialized as inner arrays
|
||||||
|
q = queryParser.parse(boolQuery()
|
||||||
|
.should(new DummyQueryParserPlugin.DummyQueryBuilder()).should(new DummyQueryParserPlugin.DummyQueryBuilder())
|
||||||
|
.must(new DummyQueryParserPlugin.DummyQueryBuilder()).must(new DummyQueryParserPlugin.DummyQueryBuilder())
|
||||||
|
.filter(new DummyQueryParserPlugin.DummyQueryBuilder()).filter(new DummyQueryParserPlugin.DummyQueryBuilder())
|
||||||
|
.mustNot(new DummyQueryParserPlugin.DummyQueryBuilder()).mustNot(new DummyQueryParserPlugin.DummyQueryBuilder())).query();
|
||||||
|
assertThat(q, instanceOf(BooleanQuery.class));
|
||||||
|
bq = (BooleanQuery) q;
|
||||||
|
assertEquals(8, bq.clauses().size());
|
||||||
|
for (BooleanClause clause : bq.clauses()) {
|
||||||
|
DummyQueryParserPlugin.DummyQuery dummy = (DummyQueryParserPlugin.DummyQuery) clause.getQuery();
|
||||||
|
switch (clause.getOccur()) {
|
||||||
|
case FILTER:
|
||||||
|
case MUST_NOT:
|
||||||
|
assertEquals(true, dummy.isFilter);
|
||||||
|
break;
|
||||||
|
case MUST:
|
||||||
|
case SHOULD:
|
||||||
|
assertEquals(false, dummy.isFilter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* 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.query.plugin;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.IndexSearcher;
|
||||||
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.Weight;
|
||||||
|
import org.elasticsearch.common.inject.Module;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.QueryParseContext;
|
||||||
|
import org.elasticsearch.index.query.QueryParser;
|
||||||
|
import org.elasticsearch.index.query.QueryParsingException;
|
||||||
|
import org.elasticsearch.indices.query.IndicesQueriesModule;
|
||||||
|
import org.elasticsearch.plugins.AbstractPlugin;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DummyQueryParserPlugin extends AbstractPlugin {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "dummy";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String description() {
|
||||||
|
return "dummy query";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processModule(Module module) {
|
||||||
|
if (module instanceof IndicesQueriesModule) {
|
||||||
|
IndicesQueriesModule indicesQueriesModule = (IndicesQueriesModule) module;
|
||||||
|
indicesQueriesModule.addQuery(DummyQueryParserPlugin.DummyQueryParser.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Settings settings() {
|
||||||
|
return Settings.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyQueryBuilder extends QueryBuilder {
|
||||||
|
@Override
|
||||||
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject("dummy").endObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyQueryParser implements QueryParser {
|
||||||
|
@Override
|
||||||
|
public String[] names() {
|
||||||
|
return new String[]{"dummy"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||||
|
XContentParser.Token token = parseContext.parser().nextToken();
|
||||||
|
assert token == XContentParser.Token.END_OBJECT;
|
||||||
|
return new DummyQuery(parseContext.isFilter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyQuery extends Query {
|
||||||
|
public final boolean isFilter;
|
||||||
|
private final Query matchAllDocsQuery = new MatchAllDocsQuery();
|
||||||
|
|
||||||
|
private DummyQuery(boolean isFilter) {
|
||||||
|
this.isFilter = isFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(String field) {
|
||||||
|
return getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
|
||||||
|
return matchAllDocsQuery.createWeight(searcher, needsScores);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue