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;
}
if (propVal == null && placeholderResolver.shouldIgnoreMissing(placeholder)) {
if (placeholderResolver.shouldRemoveMissingPlaceholder(placeholder)) {
propVal = "";
} else {
return strVal;
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
@ -170,5 +174,13 @@ public class PropertyPlaceholder {
String resolvePlaceholder(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
* 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.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() {
@Override
@ -1268,26 +1268,22 @@ public final class Settings implements ToXContent {
@Override
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 (placeholderName.startsWith("env.")) {
if (placeholderName.startsWith("env.") || placeholderName.startsWith("prompt.")) {
return true;
}
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()) {
String possiblePlaceholder = entry.getValue();
boolean ignored = false;
for (String ignoredValue : ignoredValues) {
if (ignoredValue.equals(possiblePlaceholder)) {
ignored = true;
break;
}
}
if (ignored) {
continue;
}
String value = propertyPlaceholder.replacePlaceholders(possiblePlaceholder, placeholderResolver);
String value = propertyPlaceholder.replacePlaceholders(entry.getValue(), placeholderResolver);
// if the values exists and has length, we should maintain it in the map
// otherwise, the replace process resolved into removing it
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;
import com.google.common.collect.ImmutableMap;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.CloseableThreadLocal;
import org.elasticsearch.Version;
@ -48,23 +46,12 @@ import org.elasticsearch.script.ScriptService;
import java.io.IOException;
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 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 QUERY_STRING_LENIENT = "index.query_string.lenient";
public static final String PARSE_STRICT = "index.query.parse.strict";
@ -91,7 +78,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
final BitsetFilterCache bitsetFilterCache;
private final Map<String, QueryParser> queryParsers;
private final IndicesQueriesRegistry indicesQueriesRegistry;
private String defaultField;
private boolean queryStringLenient;
@ -104,8 +91,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
ScriptService scriptService, AnalysisService analysisService,
MapperService mapperService, IndexCache indexCache, IndexFieldDataService fieldDataService,
BitsetFilterCache bitsetFilterCache,
@Nullable SimilarityService similarityService,
@Nullable Map<String, QueryParserFactory> namedQueryParsers) {
@Nullable SimilarityService similarityService) {
super(index, indexSettings);
this.scriptService = scriptService;
this.analysisService = analysisService;
@ -119,29 +105,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
this.queryStringLenient = indexSettings.getAsBoolean(QUERY_STRING_LENIENT, false);
this.strict = indexSettings.getAsBoolean(PARSE_STRICT, false);
this.defaultAllowUnmappedFields = indexSettings.getAsBoolean(ALLOW_UNMAPPED, true);
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);
this.indicesQueriesRegistry = indicesQueriesRegistry;
}
public void close() {
@ -157,7 +121,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
}
public QueryParser queryParser(String name) {
return queryParsers.get(name);
return indicesQueriesRegistry.queryParsers().get(name);
}
public ParsedQuery parse(QueryBuilder queryBuilder) {
@ -349,10 +313,4 @@ public class IndexQueryParserService extends AbstractIndexComponent {
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.MapperServiceModule;
import org.elasticsearch.index.merge.MergeStats;
import org.elasticsearch.index.query.IndexQueryParserModule;
import org.elasticsearch.index.query.IndexQueryParserService;
import org.elasticsearch.index.recovery.RecoveryStats;
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 IndexFieldDataModule(indexSettings));
modules.add(new MapperServiceModule());
modules.add(new IndexQueryParserModule(indexSettings));
modules.add(new IndexAliasesServiceModule());
modules.add(new IndexModule(indexSettings));

View File

@ -30,30 +30,21 @@ import java.util.Set;
public class IndicesQueriesModule extends AbstractModule {
private Set<Class<QueryParser>> queryParsersClasses = Sets.newHashSet();
private Set<QueryParser> queryParsers = Sets.newHashSet();
private Set<Class<? extends QueryParser>> queryParsersClasses = Sets.newHashSet();
public synchronized IndicesQueriesModule addQuery(Class<QueryParser> queryParser) {
public synchronized IndicesQueriesModule addQuery(Class<? extends QueryParser> queryParser) {
queryParsersClasses.add(queryParser);
return this;
}
public synchronized IndicesQueriesModule addQuery(QueryParser queryParser) {
queryParsers.add(queryParser);
return this;
}
@Override
protected void configure() {
bind(IndicesQueriesRegistry.class).asEagerSingleton();
Multibinder<QueryParser> qpBinders = Multibinder.newSetBinder(binder(), QueryParser.class);
for (Class<QueryParser> queryParser : queryParsersClasses) {
for (Class<? extends QueryParser> queryParser : queryParsersClasses) {
qpBinders.addBinding().to(queryParser).asEagerSingleton();
}
for (QueryParser queryParser : queryParsers) {
qpBinders.addBinding().toInstance(queryParser);
}
qpBinders.addBinding().to(MatchQueryParser.class).asEagerSingleton();
qpBinders.addBinding().to(MultiMatchQueryParser.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.Set;
/**
*
*/
public class IndicesQueriesRegistry extends AbstractComponent {
private ImmutableMap<String, QueryParser> queryParsers;
@ -42,27 +39,17 @@ public class IndicesQueriesRegistry extends AbstractComponent {
super(settings);
Map<String, QueryParser> queryParsers = Maps.newHashMap();
for (QueryParser queryParser : injectedQueryParsers) {
addQueryParser(queryParsers, queryParser);
for (String name : queryParser.names()) {
queryParsers.put(name, queryParser);
}
}
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() {
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");
public static final String SECRET_PROMPT_VALUE = "${prompt::secret}";
public static final String TEXT_PROMPT_VALUE = "${prompt::text}";
public static final String SECRET_PROMPT_VALUE = "${prompt.secret}";
public static final String TEXT_PROMPT_VALUE = "${prompt.text}";
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) {
// ignore this prefixes when getting properties from es. and elasticsearch.
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);
// just create enough settings to build the environment
Settings.Builder settingsBuilder = settingsBuilder().put(pSettings);
@ -84,7 +81,7 @@ public class InternalSettingsPreparer {
.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes)
.putProperties("es.", System.getProperties(), ignorePrefixes);
}
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders);
settingsBuilder.replacePropertyPlaceholders();
Environment environment = new Environment(settingsBuilder.build());
@ -122,7 +119,7 @@ public class InternalSettingsPreparer {
settingsBuilder.putProperties("elasticsearch.", 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
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.replacePropertyPlaceholders(ignoredPlaceholders);
settingsBuilder.replacePropertyPlaceholders();
// generate the name
if (settingsBuilder.get("name") == null) {

View File

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

View File

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

View File

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

View File

@ -113,7 +113,6 @@ public abstract class BaseQueryTestCase<QB extends QueryBuilder<QB>> extends Ela
new AnalysisModule(settings),
new SimilarityModule(settings),
new IndexNameModule(index),
new IndexQueryParserModule(settings),
new FunctionScoreModule(),
new AbstractModule() {
@Override

View File

@ -41,7 +41,6 @@ import org.elasticsearch.action.termvectors.*;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
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.Queries;
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.unit.DistanceUnit;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
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.mapper.MapperService;
import org.elasticsearch.index.mapper.ParsedDocument;
@ -71,7 +67,6 @@ import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.EnumSet;
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.hamcrest.Matchers.*;
/**
*
*/
public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
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
public void setup() throws IOException {
Settings settings = Settings.settingsBuilder()
.put("index.queryparser.query.dummy.type", DummyQueryParser.class)
.put("index.cache.filter.type", "none")
.put("name", "SimpleIndexQueryParserTests")
.build();
@ -1088,7 +1010,6 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
assertThat(clauses[3].getOccur(), equalTo(BooleanClause.Occur.SHOULD));
}
@Test
public void testBoolQuery() throws IOException {
IndexQueryParserService queryParser = queryParser();
@ -1989,7 +1910,6 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
assertThat(filter.bottomRight().lon(), closeTo(-80, 0.00001));
}
@Test
public void testGeoBoundingBoxFilter1() throws IOException {
IndexQueryParserService queryParser = queryParser();
@ -2489,72 +2409,11 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
public void testTermsQueryFilter() throws Exception {
// TermsQuery is tricky in that it parses differently as a query or a filter
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));
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();
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 SimilarityModule(settings),
new IndexNameModule(index),
new IndexQueryParserModule(settings),
new FunctionScoreModule(),
new AbstractModule() {
@Override
@ -118,6 +117,35 @@ public class TemplateQueryParserTest extends ElasticsearchTestCase {
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
public void testParserCanExtractTemplateNames() throws Exception {
String templateString = "{ \"file\": \"storedTemplate\" ,\"params\":{\"template\":\"all\" } } ";

View File

@ -232,6 +232,67 @@ public class TemplateQueryTest extends ElasticsearchIntegrationTest {
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)
public void testIndexedTemplateClient() throws Exception {
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
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
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
file, you can use the value `${prompt::text}` or `${prompt::secret}` and start
Elasticsearch in the foreground. `${prompt::secret}` has echoing disabled so
that the value entered will not be shown in your terminal; `${prompt::text}`
file, you can use the value `${prompt.text}` or `${prompt.secret}` and start
Elasticsearch in the foreground. `${prompt.secret}` has echoing disabled so
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:
[source,yaml]
--------------------------------------------------
node:
name: ${prompt::text}
name: ${prompt.text}
--------------------------------------------------
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]:
--------------------------------------------------
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.
The location of the configuration file can be set externally using a

View File

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

View File

@ -3,10 +3,14 @@
- do:
indices.create:
index: testing
body:
settings:
index:
number_of_replicas: 0
- do:
cluster.health:
wait_for_status: yellow
wait_for_status: green
- do:
indices.flush_synced:
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);
}
}
}