Merge branch 'master' into feature/query-refactoring

Conflicts:
	core/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java
	core/src/test/java/org/elasticsearch/index/query/guice/MyJsonQueryParser.java
	core/src/test/java/org/elasticsearch/index/query/plugin/PluginJsonQueryParser.java
This commit is contained in:
javanna 2015-06-08 15:14:13 +02:00 committed by Luca Cavanna
commit 7f673fbdfd
27 changed files with 433 additions and 850 deletions

View File

@ -109,7 +109,11 @@ public class PropertyPlaceholder {
propVal = defaultValue; propVal = defaultValue;
} }
if (propVal == null && placeholderResolver.shouldIgnoreMissing(placeholder)) { if (propVal == null && placeholderResolver.shouldIgnoreMissing(placeholder)) {
propVal = ""; if (placeholderResolver.shouldRemoveMissingPlaceholder(placeholder)) {
propVal = "";
} else {
return strVal;
}
} }
if (propVal != null) { if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the // Recursive invocation, parsing placeholders contained in the
@ -170,5 +174,13 @@ public class PropertyPlaceholder {
String resolvePlaceholder(String placeholderName); String resolvePlaceholder(String placeholderName);
boolean shouldIgnoreMissing(String placeholderName); boolean shouldIgnoreMissing(String placeholderName);
/**
* Allows for special handling for ignored missing placeholders that may be resolved elsewhere
*
* @param placeholderName the name of the placeholder to resolve.
* @return true if the placeholder should be replaced with a empty string
*/
boolean shouldRemoveMissingPlaceholder(String placeholderName);
} }
} }

View File

@ -1245,7 +1245,7 @@ public final class Settings implements ToXContent {
* tries and resolve it against an environment variable ({@link System#getenv(String)}), and last, tries * tries and resolve it against an environment variable ({@link System#getenv(String)}), and last, tries
* and replace it with another setting already set on this builder. * and replace it with another setting already set on this builder.
*/ */
public Builder replacePropertyPlaceholders(String... ignoredValues) { public Builder replacePropertyPlaceholders() {
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() { PropertyPlaceholder.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() {
@Override @Override
@ -1268,26 +1268,22 @@ public final class Settings implements ToXContent {
@Override @Override
public boolean shouldIgnoreMissing(String placeholderName) { public boolean shouldIgnoreMissing(String placeholderName) {
// if its an explicit env var, we are ok with not having a value for it and treat it as optional // if its an explicit env var, we are ok with not having a value for it and treat it as optional
if (placeholderName.startsWith("env.")) { if (placeholderName.startsWith("env.") || placeholderName.startsWith("prompt.")) {
return true; return true;
} }
return false; return false;
} }
@Override
public boolean shouldRemoveMissingPlaceholder(String placeholderName) {
if (placeholderName.startsWith("prompt.")) {
return false;
}
return true;
}
}; };
for (Map.Entry<String, String> entry : Maps.newHashMap(map).entrySet()) { for (Map.Entry<String, String> entry : Maps.newHashMap(map).entrySet()) {
String possiblePlaceholder = entry.getValue(); String value = propertyPlaceholder.replacePlaceholders(entry.getValue(), placeholderResolver);
boolean ignored = false;
for (String ignoredValue : ignoredValues) {
if (ignoredValue.equals(possiblePlaceholder)) {
ignored = true;
break;
}
}
if (ignored) {
continue;
}
String value = propertyPlaceholder.replacePlaceholders(possiblePlaceholder, placeholderResolver);
// if the values exists and has length, we should maintain it in the map // if the values exists and has length, we should maintain it in the map
// otherwise, the replace process resolved into removing it // otherwise, the replace process resolved into removing it
if (Strings.hasLength(value)) { if (Strings.hasLength(value)) {

View File

@ -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);
}
}
}

View File

@ -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);
}
}
} }

View File

@ -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);
}

View File

@ -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));

View File

@ -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();

View File

@ -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);
}
}
} }

View File

@ -44,8 +44,8 @@ public class InternalSettingsPreparer {
static final List<String> ALLOWED_SUFFIXES = ImmutableList.of(".yml", ".yaml", ".json", ".properties"); static final List<String> ALLOWED_SUFFIXES = ImmutableList.of(".yml", ".yaml", ".json", ".properties");
public static final String SECRET_PROMPT_VALUE = "${prompt::secret}"; public static final String SECRET_PROMPT_VALUE = "${prompt.secret}";
public static final String TEXT_PROMPT_VALUE = "${prompt::text}"; public static final String TEXT_PROMPT_VALUE = "${prompt.text}";
public static final String IGNORE_SYSTEM_PROPERTIES_SETTING = "config.ignore_system_properties"; public static final String IGNORE_SYSTEM_PROPERTIES_SETTING = "config.ignore_system_properties";
/** /**
@ -72,9 +72,6 @@ public class InternalSettingsPreparer {
public static Tuple<Settings, Environment> prepareSettings(Settings pSettings, boolean loadConfigSettings, Terminal terminal) { public static Tuple<Settings, Environment> prepareSettings(Settings pSettings, boolean loadConfigSettings, Terminal terminal) {
// ignore this prefixes when getting properties from es. and elasticsearch. // ignore this prefixes when getting properties from es. and elasticsearch.
String[] ignorePrefixes = new String[]{"es.default.", "elasticsearch.default."}; String[] ignorePrefixes = new String[]{"es.default.", "elasticsearch.default."};
// ignore the special prompt placeholders since they have the same format as property placeholders and will be resolved
// as having a default value because of the ':' in the format
String[] ignoredPlaceholders = new String[] { SECRET_PROMPT_VALUE, TEXT_PROMPT_VALUE };
boolean useSystemProperties = !pSettings.getAsBoolean(IGNORE_SYSTEM_PROPERTIES_SETTING, false); boolean useSystemProperties = !pSettings.getAsBoolean(IGNORE_SYSTEM_PROPERTIES_SETTING, false);
// just create enough settings to build the environment // just create enough settings to build the environment
Settings.Builder settingsBuilder = settingsBuilder().put(pSettings); Settings.Builder settingsBuilder = settingsBuilder().put(pSettings);
@ -84,7 +81,7 @@ public class InternalSettingsPreparer {
.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes) .putProperties("elasticsearch.", System.getProperties(), ignorePrefixes)
.putProperties("es.", System.getProperties(), ignorePrefixes); .putProperties("es.", System.getProperties(), ignorePrefixes);
} }
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders); settingsBuilder.replacePropertyPlaceholders();
Environment environment = new Environment(settingsBuilder.build()); Environment environment = new Environment(settingsBuilder.build());
@ -122,7 +119,7 @@ public class InternalSettingsPreparer {
settingsBuilder.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes) settingsBuilder.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes)
.putProperties("es.", System.getProperties(), ignorePrefixes); .putProperties("es.", System.getProperties(), ignorePrefixes);
} }
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders); settingsBuilder.replacePropertyPlaceholders();
// allow to force set properties based on configuration of the settings provided // allow to force set properties based on configuration of the settings provided
for (Map.Entry<String, String> entry : pSettings.getAsMap().entrySet()) { for (Map.Entry<String, String> entry : pSettings.getAsMap().entrySet()) {
@ -132,7 +129,7 @@ public class InternalSettingsPreparer {
settingsBuilder.put(setting.substring("force.".length()), entry.getValue()); settingsBuilder.put(setting.substring("force.".length()), entry.getValue());
} }
} }
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders); settingsBuilder.replacePropertyPlaceholders();
// generate the name // generate the name
if (settingsBuilder.get("name") == null) { if (settingsBuilder.get("name") == null) {

View File

@ -22,7 +22,6 @@ package org.elasticsearch.search;
import com.carrotsearch.hppc.ObjectHashSet; import com.carrotsearch.hppc.ObjectHashSet;
import com.carrotsearch.hppc.ObjectSet; import com.carrotsearch.hppc.ObjectSet;
import com.carrotsearch.hppc.cursors.ObjectCursor; import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexOptions;
@ -682,9 +681,10 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
private void parseTemplate(ShardSearchRequest request) { private void parseTemplate(ShardSearchRequest request) {
final ExecutableScript executable; BytesReference processedQuery;
if (request.template() != null) { if (request.template() != null) {
executable = this.scriptService.executable(request.template(), ScriptContext.Standard.SEARCH); ExecutableScript executable = this.scriptService.executable(request.template(), ScriptContext.Standard.SEARCH);
processedQuery = (BytesReference) executable.run();
} else { } else {
if (!hasLength(request.templateSource())) { if (!hasLength(request.templateSource())) {
return; return;
@ -700,13 +700,16 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
//Try to double parse for nested template id/file //Try to double parse for nested template id/file
parser = null; parser = null;
try { try {
byte[] templateBytes = template.getScript().getBytes(Charsets.UTF_8); ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH);
parser = XContentFactory.xContent(templateBytes).createParser(templateBytes); processedQuery = (BytesReference) executable.run();
parser = XContentFactory.xContent(processedQuery).createParser(processedQuery);
} catch (ElasticsearchParseException epe) { } catch (ElasticsearchParseException epe) {
//This was an non-nested template, the parse failure was due to this, it is safe to assume this refers to a file //This was an non-nested template, the parse failure was due to this, it is safe to assume this refers to a file
//for backwards compatibility and keep going //for backwards compatibility and keep going
template = new Template(template.getScript(), ScriptService.ScriptType.FILE, MustacheScriptEngineService.NAME, template = new Template(template.getScript(), ScriptService.ScriptType.FILE, MustacheScriptEngineService.NAME,
null, template.getParams()); null, template.getParams());
ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH);
processedQuery = (BytesReference) executable.run();
} }
if (parser != null) { if (parser != null) {
try { try {
@ -715,11 +718,16 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
//An inner template referring to a filename or id //An inner template referring to a filename or id
template = new Template(innerTemplate.getScript(), innerTemplate.getType(), template = new Template(innerTemplate.getScript(), innerTemplate.getType(),
MustacheScriptEngineService.NAME, null, template.getParams()); MustacheScriptEngineService.NAME, null, template.getParams());
ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH);
processedQuery = (BytesReference) executable.run();
} }
} catch (ScriptParseException e) { } catch (ScriptParseException e) {
// No inner template found, use original template from above // No inner template found, use original template from above
} }
} }
} else {
ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH);
processedQuery = (BytesReference) executable.run();
} }
} catch (IOException e) { } catch (IOException e) {
throw new ElasticsearchParseException("Failed to parse template", e); throw new ElasticsearchParseException("Failed to parse template", e);
@ -730,10 +738,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
if (!hasLength(template.getScript())) { if (!hasLength(template.getScript())) {
throw new ElasticsearchParseException("Template must have [template] field configured"); throw new ElasticsearchParseException("Template must have [template] field configured");
} }
executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH);
} }
BytesReference processedQuery = (BytesReference) executable.run();
request.source(processedQuery); request.source(processedQuery);
} }

View File

@ -33,7 +33,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
map.put("foo1", "bar1"); map.put("foo1", "bar1");
map.put("foo2", "bar2"); map.put("foo2", "bar2");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("bar1", propertyPlaceholder.replacePlaceholders("{foo1}", placeholderResolver)); assertEquals("bar1", propertyPlaceholder.replacePlaceholders("{foo1}", placeholderResolver));
assertEquals("a bar1b", propertyPlaceholder.replacePlaceholders("a {foo1}b", placeholderResolver)); assertEquals("a bar1b", propertyPlaceholder.replacePlaceholders("a {foo1}b", placeholderResolver));
assertEquals("bar1bar2", propertyPlaceholder.replacePlaceholders("{foo1}{foo2}", placeholderResolver)); assertEquals("bar1bar2", propertyPlaceholder.replacePlaceholders("{foo1}{foo2}", placeholderResolver));
@ -48,7 +48,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
PropertyPlaceholder ppShorterPrefix = new PropertyPlaceholder("{", "}}", false); PropertyPlaceholder ppShorterPrefix = new PropertyPlaceholder("{", "}}", false);
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
map.put("foo", "bar"); map.put("foo", "bar");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("bar", ppEqualsPrefix.replacePlaceholders("{foo}", placeholderResolver)); assertEquals("bar", ppEqualsPrefix.replacePlaceholders("{foo}", placeholderResolver));
assertEquals("bar", ppLongerPrefix.replacePlaceholders("${foo}", placeholderResolver)); assertEquals("bar", ppLongerPrefix.replacePlaceholders("${foo}", placeholderResolver));
assertEquals("bar", ppShorterPrefix.replacePlaceholders("{foo}}", placeholderResolver)); assertEquals("bar", ppShorterPrefix.replacePlaceholders("{foo}}", placeholderResolver));
@ -58,7 +58,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
public void testDefaultValue() { public void testDefaultValue() {
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("bar", propertyPlaceholder.replacePlaceholders("${foo:bar}", placeholderResolver)); assertEquals("bar", propertyPlaceholder.replacePlaceholders("${foo:bar}", placeholderResolver));
assertEquals("", propertyPlaceholder.replacePlaceholders("${foo:}", placeholderResolver)); assertEquals("", propertyPlaceholder.replacePlaceholders("${foo:}", placeholderResolver));
} }
@ -67,7 +67,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
public void testIgnoredUnresolvedPlaceholder() { public void testIgnoredUnresolvedPlaceholder() {
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", true); PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", true);
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("${foo}", propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver)); assertEquals("${foo}", propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver));
} }
@ -75,7 +75,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
public void testNotIgnoredUnresolvedPlaceholder() { public void testNotIgnoredUnresolvedPlaceholder() {
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver); propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver);
} }
@ -83,7 +83,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
public void testShouldIgnoreMissing() { public void testShouldIgnoreMissing() {
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, true); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, true, true);
assertEquals("bar", propertyPlaceholder.replacePlaceholders("bar${foo}", placeholderResolver)); assertEquals("bar", propertyPlaceholder.replacePlaceholders("bar${foo}", placeholderResolver));
} }
@ -94,7 +94,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
map.put("foo", "${foo1}"); map.put("foo", "${foo1}");
map.put("foo1", "${foo2}"); map.put("foo1", "${foo2}");
map.put("foo2", "bar"); map.put("foo2", "bar");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("bar", propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver)); assertEquals("bar", propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver));
assertEquals("abarb", propertyPlaceholder.replacePlaceholders("a${foo}b", placeholderResolver)); assertEquals("abarb", propertyPlaceholder.replacePlaceholders("a${foo}b", placeholderResolver));
} }
@ -107,7 +107,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
map.put("foo1", "${foo2}"); map.put("foo1", "${foo2}");
map.put("foo2", "bar"); map.put("foo2", "bar");
map.put("barbar", "baz"); map.put("barbar", "baz");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("baz", propertyPlaceholder.replacePlaceholders("${bar${foo}}", placeholderResolver)); assertEquals("baz", propertyPlaceholder.replacePlaceholders("${bar${foo}}", placeholderResolver));
} }
@ -119,7 +119,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
map.put("foo1", "{foo2}"); map.put("foo1", "{foo2}");
map.put("foo2", "bar"); map.put("foo2", "bar");
map.put("barbar", "baz"); map.put("barbar", "baz");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("baz", propertyPlaceholder.replacePlaceholders("{bar{foo}}", placeholderResolver)); assertEquals("baz", propertyPlaceholder.replacePlaceholders("{bar{foo}}", placeholderResolver));
} }
@ -131,7 +131,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
map.put("foo1", "{foo2}}"); map.put("foo1", "{foo2}}");
map.put("foo2", "bar"); map.put("foo2", "bar");
map.put("barbar", "baz"); map.put("barbar", "baz");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
assertEquals("baz", propertyPlaceholder.replacePlaceholders("{bar{foo}}}}", placeholderResolver)); assertEquals("baz", propertyPlaceholder.replacePlaceholders("{bar{foo}}}}", placeholderResolver));
} }
@ -141,17 +141,27 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
Map<String, String> map = new LinkedHashMap<>(); Map<String, String> map = new LinkedHashMap<>();
map.put("foo", "${bar}"); map.put("foo", "${bar}");
map.put("bar", "${foo}"); map.put("bar", "${foo}");
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true);
propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver); propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver);
} }
@Test
public void testShouldRemoveMissing() {
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
Map<String, String> map = new LinkedHashMap<>();
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, true, false);
assertEquals("bar${foo}", propertyPlaceholder.replacePlaceholders("bar${foo}", placeholderResolver));
}
private class SimplePlaceholderResolver implements PropertyPlaceholder.PlaceholderResolver { private class SimplePlaceholderResolver implements PropertyPlaceholder.PlaceholderResolver {
private Map<String, String> map; private Map<String, String> map;
private boolean shouldIgnoreMissing; private boolean shouldIgnoreMissing;
private boolean shouldRemoveMissing;
SimplePlaceholderResolver(Map<String, String> map, boolean shouldIgnoreMissing) { SimplePlaceholderResolver(Map<String, String> map, boolean shouldIgnoreMissing, boolean shouldRemoveMissing) {
this.map = map; this.map = map;
this.shouldIgnoreMissing = shouldIgnoreMissing; this.shouldIgnoreMissing = shouldIgnoreMissing;
this.shouldRemoveMissing = shouldRemoveMissing;
} }
@Override @Override
@ -163,5 +173,10 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase {
public boolean shouldIgnoreMissing(String placeholderName) { public boolean shouldIgnoreMissing(String placeholderName) {
return shouldIgnoreMissing; return shouldIgnoreMissing;
} }
@Override
public boolean shouldRemoveMissingPlaceholder(String placeholderName) {
return shouldRemoveMissing;
}
} }
} }

View File

@ -138,14 +138,14 @@ public class SettingsTests extends ElasticsearchTestCase {
} }
@Test @Test
public void testReplacePropertiesPlaceholderIgnores() { public void testReplacePropertiesPlaceholderIgnoresPrompt() {
Settings settings = settingsBuilder() Settings settings = settingsBuilder()
.put("setting1", "${foo.bar}") .put("setting1", "${prompt.text}")
.put("setting2", "${foo.bar1}") .put("setting2", "${prompt.secret}")
.replacePropertyPlaceholders("${foo.bar}", "${foo.bar1}") .replacePropertyPlaceholders()
.build(); .build();
assertThat(settings.get("setting1"), is("${foo.bar}")); assertThat(settings.get("setting1"), is("${prompt.text}"));
assertThat(settings.get("setting2"), is("${foo.bar1}")); assertThat(settings.get("setting2"), is("${prompt.secret}"));
} }
@Test @Test

View File

@ -113,7 +113,6 @@ public abstract class BaseQueryTestCase<QB extends QueryBuilder<QB>> extends Ela
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

View File

@ -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,86 +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[] {DummyQueryBuilder.NAME};
}
@Override
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
return fromXContent(parseContext).toQuery(parseContext);
}
@Override
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
assertEquals(XContentParser.Token.END_OBJECT, parseContext.parser().nextToken());
return new DummyQueryBuilder();
}
@Override
public DummyQueryBuilder getBuilderPrototype() {
return new DummyQueryBuilder();
}
}
private static class DummyQueryBuilder extends QueryBuilder {
public static final String NAME = "dummy";
@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject("dummy").endObject();
}
@Override
public Query toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException {
DummyQuery query = new DummyQuery();
query.isFilter = parseContext.isFilter();
return query;
}
@Override
public String queryId() {
return NAME;
}
}
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();
@ -1088,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();
@ -1989,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();
@ -2489,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();
}
}
}
} }

View File

@ -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
@ -118,6 +117,35 @@ public class TemplateQueryParserTest extends ElasticsearchTestCase {
assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery); assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery);
} }
@Test
public void testParseTemplateAsSingleStringWithConditionalClause() throws IOException {
String templateString = "{" + " \"inline\" : \"{ \\\"match_{{#use_it}}{{template}}{{/use_it}}\\\":{} }\"," + " \"params\":{"
+ " \"template\":\"all\"," + " \"use_it\": true" + " }" + "}";
XContentParser templateSourceParser = XContentFactory.xContent(templateString).createParser(templateString);
context.reset(templateSourceParser);
TemplateQueryParser parser = injector.getInstance(TemplateQueryParser.class);
Query query = parser.parse(context);
assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery);
}
/**
* Test that the template query parser can parse and evaluate template
* expressed as a single string but still it expects only the query
* specification (thus this test should fail with specific exception).
*/
@Test(expected = QueryParsingException.class)
public void testParseTemplateFailsToParseCompleteQueryAsSingleString() throws IOException {
String templateString = "{" + " \"inline\" : \"{ \\\"size\\\": \\\"{{size}}\\\", \\\"query\\\":{\\\"match_all\\\":{}}}\","
+ " \"params\":{" + " \"size\":2" + " }\n" + "}";
XContentParser templateSourceParser = XContentFactory.xContent(templateString).createParser(templateString);
context.reset(templateSourceParser);
TemplateQueryParser parser = injector.getInstance(TemplateQueryParser.class);
parser.parse(context);
}
@Test @Test
public void testParserCanExtractTemplateNames() throws Exception { public void testParserCanExtractTemplateNames() throws Exception {
String templateString = "{ \"file\": \"storedTemplate\" ,\"params\":{\"template\":\"all\" } } "; String templateString = "{ \"file\": \"storedTemplate\" ,\"params\":{\"template\":\"all\" } } ";

View File

@ -232,6 +232,67 @@ public class TemplateQueryTest extends ElasticsearchIntegrationTest {
assertHitCount(searchResponse, 1); assertHitCount(searchResponse, 1);
} }
@Test
public void testSearchTemplateQueryFromFile() throws Exception {
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("_all");
String templateString = "{" + " \"file\": \"full-query-template\"," + " \"params\":{" + " \"mySize\": 2,"
+ " \"myField\": \"text\"," + " \"myValue\": \"value1\"" + " }" + "}";
BytesReference bytesRef = new BytesArray(templateString);
searchRequest.templateSource(bytesRef);
SearchResponse searchResponse = client().search(searchRequest).get();
assertThat(searchResponse.getHits().hits().length, equalTo(1));
}
/**
* Test that template can be expressed as a single escaped string.
*/
@Test
public void testTemplateQueryAsEscapedString() throws Exception {
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("_all");
String templateString = "{" + " \"template\" : \"{ \\\"size\\\": \\\"{{size}}\\\", \\\"query\\\":{\\\"match_all\\\":{}}}\","
+ " \"params\":{" + " \"size\": 1" + " }" + "}";
BytesReference bytesRef = new BytesArray(templateString);
searchRequest.templateSource(bytesRef);
SearchResponse searchResponse = client().search(searchRequest).get();
assertThat(searchResponse.getHits().hits().length, equalTo(1));
}
/**
* Test that template can contain conditional clause. In this case it is at
* the beginning of the string.
*/
@Test
public void testTemplateQueryAsEscapedStringStartingWithConditionalClause() throws Exception {
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("_all");
String templateString = "{"
+ " \"template\" : \"{ {{#use_size}} \\\"size\\\": \\\"{{size}}\\\", {{/use_size}} \\\"query\\\":{\\\"match_all\\\":{}}}\","
+ " \"params\":{" + " \"size\": 1," + " \"use_size\": true" + " }" + "}";
BytesReference bytesRef = new BytesArray(templateString);
searchRequest.templateSource(bytesRef);
SearchResponse searchResponse = client().search(searchRequest).get();
assertThat(searchResponse.getHits().hits().length, equalTo(1));
}
/**
* Test that template can contain conditional clause. In this case it is at
* the end of the string.
*/
@Test
public void testTemplateQueryAsEscapedStringWithConditionalClauseAtEnd() throws Exception {
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("_all");
String templateString = "{"
+ " \"inline\" : \"{ \\\"query\\\":{\\\"match_all\\\":{}} {{#use_size}}, \\\"size\\\": \\\"{{size}}\\\" {{/use_size}} }\","
+ " \"params\":{" + " \"size\": 1," + " \"use_size\": true" + " }" + "}";
BytesReference bytesRef = new BytesArray(templateString);
searchRequest.templateSource(bytesRef);
SearchResponse searchResponse = client().search(searchRequest).get();
assertThat(searchResponse.getHits().hits().length, equalTo(1));
}
@Test(expected = SearchPhaseExecutionException.class) @Test(expected = SearchPhaseExecutionException.class)
public void testIndexedTemplateClient() throws Exception { public void testIndexedTemplateClient() throws Exception {
createIndex(ScriptService.SCRIPT_INDEX); createIndex(ScriptService.SCRIPT_INDEX);

View File

@ -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"));
}
}

View File

@ -1,77 +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.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryParser;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.QueryWrappingQueryBuilder;
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;
}
@Override
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
Query query = parse(parseContext);
return new QueryWrappingQueryBuilder(query);
}
@Override
public QueryBuilder getBuilderPrototype() {
throw new UnsupportedOperationException("Not implemented in test class");
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -1,77 +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.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryParser;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.QueryWrappingQueryBuilder;
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;
}
@Override
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
Query query = parse(parseContext);
return new QueryWrappingQueryBuilder(query);
}
@Override
public QueryBuilder getBuilderPrototype() {
throw new UnsupportedOperationException("Not implemented in test class");
}
}

View File

@ -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

View File

@ -271,15 +271,15 @@ file which will resolve to an environment setting, for example:
-------------------------------------------------- --------------------------------------------------
Additionally, for settings that you do not wish to store in the configuration Additionally, for settings that you do not wish to store in the configuration
file, you can use the value `${prompt::text}` or `${prompt::secret}` and start file, you can use the value `${prompt.text}` or `${prompt.secret}` and start
Elasticsearch in the foreground. `${prompt::secret}` has echoing disabled so Elasticsearch in the foreground. `${prompt.secret}` has echoing disabled so
that the value entered will not be shown in your terminal; `${prompt::text}` that the value entered will not be shown in your terminal; `${prompt.text}`
will allow you to see the value as you type it in. For example: will allow you to see the value as you type it in. For example:
[source,yaml] [source,yaml]
-------------------------------------------------- --------------------------------------------------
node: node:
name: ${prompt::text} name: ${prompt.text}
-------------------------------------------------- --------------------------------------------------
On execution of the `elasticsearch` command, you will be prompted to enter On execution of the `elasticsearch` command, you will be prompted to enter
@ -290,7 +290,7 @@ the actual value like so:
Enter value for [node.name]: Enter value for [node.name]:
-------------------------------------------------- --------------------------------------------------
NOTE: Elasticsearch will not start if `${prompt::text}` or `${prompt::secret}` NOTE: Elasticsearch will not start if `${prompt.text}` or `${prompt.secret}`
is used in the settings and the process is run as a service or in the background. is used in the settings and the process is run as a service or in the background.
The location of the configuration file can be set externally using a The location of the configuration file can be set externally using a

View File

@ -60,6 +60,7 @@ public class AzureTwoStartedNodesTest extends AbstractAzureComputeServiceTest {
} }
@Test @Test
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/11533")
public void two_nodes_should_run_using_public_ip() { public void two_nodes_should_run_using_public_ip() {
Settings.Builder settings = Settings.settingsBuilder() Settings.Builder settings = Settings.settingsBuilder()
.put(Management.SERVICE_NAME, "dummy") .put(Management.SERVICE_NAME, "dummy")

View File

@ -3,10 +3,14 @@
- do: - do:
indices.create: indices.create:
index: testing index: testing
body:
settings:
index:
number_of_replicas: 0
- do: - do:
cluster.health: cluster.health:
wait_for_status: yellow wait_for_status: green
- do: - do:
indices.flush_synced: indices.flush_synced:
index: testing index: testing

View File

@ -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();
}
}
}
}

View File

@ -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);
}
}
}