summaryrefslogtreecommitdiff
path: root/core/src/main/java/org/elasticsearch/search
diff options
context:
space:
mode:
authorNik Everett <nik9000@gmail.com>2016-12-20 11:05:24 -0500
committerGitHub <noreply@github.com>2016-12-20 11:05:24 -0500
commita04dcfb95b1defb954c7be5016ad5865e9099c97 (patch)
tree4b6b4414013c422ef5543311a4844a47aba116fe /core/src/main/java/org/elasticsearch/search
parent73320566c1e6c6cfd6b3f40c1a70b23ff2cbdf29 (diff)
Introduce XContentParser#namedObject (#22003)
Introduces `XContentParser#namedObject which works a little like `StreamInput#readNamedWriteable`: on startup components register parsers under names and a superclass. At runtime we look up the parser and call it to parse the object. Right now the parsers take a context object they use to help with the parsing but I hope to be able to eliminate the need for this context as most what it is used for at this point is to move around parser registries which should be replaced by this method eventually. I make no effort to do so in this PR because it is big enough already. This is meant to the a start down a road that allows us to remove classes like `QueryParseContext`, `AggregatorParsers`, `IndicesQueriesRegistry`, and `ParseFieldRegistry`. The goal here is to reduce the amount of plumbing required to allow parsing pluggable things. With this you don't have to pass registries all over the place. Instead you must pass a super registry to fewer places and use it to wrap the reader. This is the same tradeoff that we use for NamedWriteable and it allows much, much simpler binary serialization. We think we want that same thing for xcontent serialization. The only parsing actually converted to this method is parsing `ScoreFunctions` inside of `FunctionScoreQuery`. I chose this because it is relatively self contained.
Diffstat (limited to 'core/src/main/java/org/elasticsearch/search')
-rw-r--r--core/src/main/java/org/elasticsearch/search/SearchModule.java25
-rw-r--r--core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java11
-rw-r--r--core/src/main/java/org/elasticsearch/search/internal/ShardSearchRequest.java40
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java9
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java3
5 files changed, 52 insertions, 36 deletions
diff --git a/core/src/main/java/org/elasticsearch/search/SearchModule.java b/core/src/main/java/org/elasticsearch/search/SearchModule.java
index cdfcaeab90..a5ea15c670 100644
--- a/core/src/main/java/org/elasticsearch/search/SearchModule.java
+++ b/core/src/main/java/org/elasticsearch/search/SearchModule.java
@@ -23,11 +23,14 @@ import org.apache.lucene.search.BooleanQuery;
import org.elasticsearch.common.NamedRegistry;
import org.elasticsearch.common.geo.ShapesAvailability;
import org.elasticsearch.common.geo.builders.ShapeBuilders;
+import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ParseFieldRegistry;
+import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.CommonTermsQueryBuilder;
@@ -54,6 +57,7 @@ import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.ParentIdQueryBuilder;
import org.elasticsearch.index.query.PrefixQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.RegexpQueryBuilder;
@@ -79,7 +83,6 @@ import org.elasticsearch.index.query.functionscore.GaussDecayFunctionBuilder;
import org.elasticsearch.index.query.functionscore.LinearDecayFunctionBuilder;
import org.elasticsearch.index.query.functionscore.RandomScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
-import org.elasticsearch.index.query.functionscore.ScoreFunctionParser;
import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.WeightBuilder;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
@@ -266,7 +269,6 @@ public class SearchModule {
private final boolean transportClient;
private final Map<String, Highlighter> highlighters;
private final Map<String, Suggester<?>> suggesters;
- private final ParseFieldRegistry<ScoreFunctionParser<?>> scoreFunctionParserRegistry = new ParseFieldRegistry<>("score_function");
private final IndicesQueriesRegistry queryParserRegistry = new IndicesQueriesRegistry();
private final ParseFieldRegistry<Aggregator.Parser> aggregationParserRegistry = new ParseFieldRegistry<>("aggregation");
private final ParseFieldRegistry<PipelineAggregator.Parser> pipelineAggregationParserRegistry = new ParseFieldRegistry<>(
@@ -281,7 +283,8 @@ public class SearchModule {
private final SearchExtRegistry searchExtParserRegistry = new SearchExtRegistry();
private final Settings settings;
- private final List<Entry> namedWriteables = new ArrayList<>();
+ private final List<NamedWriteableRegistry.Entry> namedWriteables = new ArrayList<>();
+ private final List<NamedXContentRegistry.Entry> namedXContents = new ArrayList<>();
private final SearchRequestParsers searchRequestParsers;
public SearchModule(Settings settings, boolean transportClient, List<SearchPlugin> plugins) {
@@ -304,10 +307,14 @@ public class SearchModule {
searchRequestParsers = new SearchRequestParsers(queryParserRegistry, aggregatorParsers, getSuggesters(), searchExtParserRegistry);
}
- public List<Entry> getNamedWriteables() {
+ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
return namedWriteables;
}
+ public List<NamedXContentRegistry.Entry> getNamedXContents() {
+ return namedXContents;
+ }
+
public Suggesters getSuggesters() {
return new Suggesters(suggesters);
}
@@ -618,8 +625,12 @@ public class SearchModule {
}
private void registerScoreFunction(ScoreFunctionSpec<?> scoreFunction) {
- scoreFunctionParserRegistry.register(scoreFunction.getParser(), scoreFunction.getName());
- namedWriteables.add(new Entry(ScoreFunctionBuilder.class, scoreFunction.getName().getPreferredName(), scoreFunction.getReader()));
+ namedWriteables.add(new NamedWriteableRegistry.Entry(
+ ScoreFunctionBuilder.class, scoreFunction.getName().getPreferredName(), scoreFunction.getReader()));
+ // TODO remove funky contexts
+ namedXContents.add(new NamedXContentRegistry.Entry(
+ ScoreFunctionBuilder.class, scoreFunction.getName(),
+ (XContentParser p, Object c) -> scoreFunction.getParser().fromXContent((QueryParseContext) c)));
}
private void registerValueFormats() {
@@ -742,7 +753,7 @@ public class SearchModule {
registerQuery(
new QuerySpec<>(SpanMultiTermQueryBuilder.NAME, SpanMultiTermQueryBuilder::new, SpanMultiTermQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(FunctionScoreQueryBuilder.NAME, FunctionScoreQueryBuilder::new,
- c -> FunctionScoreQueryBuilder.fromXContent(scoreFunctionParserRegistry, c)));
+ FunctionScoreQueryBuilder::fromXContent));
registerQuery(
new QuerySpec<>(SimpleQueryStringBuilder.NAME, SimpleQueryStringBuilder::new, SimpleQueryStringBuilder::fromXContent));
registerQuery(new QuerySpec<>(TypeQueryBuilder.NAME, TypeQueryBuilder::new, TypeQueryBuilder::fromXContent));
diff --git a/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java b/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java
index fd68438052..8d55dfbab0 100644
--- a/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java
+++ b/core/src/main/java/org/elasticsearch/search/internal/AliasFilter.java
@@ -25,6 +25,8 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryRewriteContext;
@@ -62,7 +64,14 @@ public final class AliasFilter implements Writeable {
if (reparseAliases) {
// we are processing a filter received from a 5.0 node - we need to reparse this on the executing node
final IndexMetaData indexMetaData = context.getIndexSettings().getIndexMetaData();
- return ShardSearchRequest.parseAliasFilter(context::newParseContext, indexMetaData, aliases);
+ /* Being static, parseAliasFilter doesn't have access to whatever guts it needs to parse a query. Instead of passing in a bunch
+ * of dependencies we pass in a function that can perform the parsing. */
+ ShardSearchRequest.FilterParser filterParser = bytes -> {
+ try (XContentParser parser = XContentFactory.xContent(bytes).createParser(context.getXContentRegistry(), bytes)) {
+ return context.newParseContext(parser).parseInnerQueryBuilder();
+ }
+ };
+ return ShardSearchRequest.parseAliasFilter(filterParser, indexMetaData, aliases);
}
return filter;
}
diff --git a/core/src/main/java/org/elasticsearch/search/internal/ShardSearchRequest.java b/core/src/main/java/org/elasticsearch/search/internal/ShardSearchRequest.java
index cc7dc3eb5f..f021d7730c 100644
--- a/core/src/main/java/org/elasticsearch/search/internal/ShardSearchRequest.java
+++ b/core/src/main/java/org/elasticsearch/search/internal/ShardSearchRequest.java
@@ -24,12 +24,9 @@ import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableOpenMap;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.indices.AliasFilterParsingException;
@@ -91,13 +88,17 @@ public interface ShardSearchRequest {
*/
void rewrite(QueryShardContext context) throws IOException;
+ @FunctionalInterface
+ public interface FilterParser {
+ QueryBuilder parse(byte[] bytes) throws IOException;
+ }
/**
* Returns the filter associated with listed filtering aliases.
* <p>
* The list of filtering aliases should be obtained by calling MetaData.filteringAliases.
* Returns <tt>null</tt> if no filtering is required.</p>
*/
- static QueryBuilder parseAliasFilter(Function<XContentParser, QueryParseContext> contextFactory,
+ static QueryBuilder parseAliasFilter(FilterParser filterParser,
IndexMetaData metaData, String... aliasNames) {
if (aliasNames == null || aliasNames.length == 0) {
return null;
@@ -109,10 +110,7 @@ public interface ShardSearchRequest {
return null;
}
try {
- byte[] filterSource = alias.filter().uncompressed();
- try (XContentParser parser = XContentFactory.xContent(filterSource).createParser(filterSource)) {
- return contextFactory.apply(parser).parseInnerQueryBuilder();
- }
+ return filterParser.parse(alias.filter().uncompressed());
} catch (IOException ex) {
throw new AliasFilterParsingException(index, alias.getAlias(), "Invalid alias filter", ex);
}
@@ -128,19 +126,19 @@ public interface ShardSearchRequest {
// we need to bench here a bit, to see maybe it makes sense to use OrFilter
BoolQueryBuilder combined = new BoolQueryBuilder();
for (String aliasName : aliasNames) {
- AliasMetaData alias = aliases.get(aliasName);
- if (alias == null) {
- // This shouldn't happen unless alias disappeared after filteringAliases was called.
- throw new InvalidAliasNameException(index, aliasNames[0],
- "Unknown alias name was passed to alias Filter");
- }
- QueryBuilder parsedFilter = parserFunction.apply(alias);
- if (parsedFilter != null) {
- combined.should(parsedFilter);
- } else {
- // The filter might be null only if filter was removed after filteringAliases was called
- return null;
- }
+ AliasMetaData alias = aliases.get(aliasName);
+ if (alias == null) {
+ // This shouldn't happen unless alias disappeared after filteringAliases was called.
+ throw new InvalidAliasNameException(index, aliasNames[0],
+ "Unknown alias name was passed to alias Filter");
+ }
+ QueryBuilder parsedFilter = parserFunction.apply(alias);
+ if (parsedFilter != null) {
+ combined.should(parsedFilter);
+ } else {
+ // The filter might be null only if filter was removed after filteringAliases was called
+ return null;
+ }
}
return combined;
}
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java
index 09382d9aaf..0fd3726384 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java
@@ -42,7 +42,6 @@ import org.elasticsearch.search.suggest.completion.context.ContextMapping;
import org.elasticsearch.search.suggest.completion.context.ContextMappings;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -233,10 +232,7 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder<CompletionSug
regexOptions.toXContent(builder, params);
}
if (contextBytes != null) {
- try (XContentParser contextParser = XContentFactory.xContent(XContentType.JSON).createParser(contextBytes)) {
- builder.field(CONTEXTS_FIELD.getPreferredName());
- builder.copyCurrentStructure(contextParser);
- }
+ builder.rawField(CONTEXTS_FIELD.getPreferredName(), contextBytes);
}
return builder;
}
@@ -270,7 +266,8 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder<CompletionSug
CompletionFieldMapper.CompletionFieldType type = (CompletionFieldMapper.CompletionFieldType) mappedFieldType;
suggestionContext.setFieldType(type);
if (type.hasContextMappings() && contextBytes != null) {
- try (XContentParser contextParser = XContentFactory.xContent(contextBytes).createParser(contextBytes)) {
+ try (XContentParser contextParser = XContentFactory.xContent(contextBytes).createParser(context.getXContentRegistry(),
+ contextBytes)) {
if (type.hasContextMappings() && contextParser != null) {
ContextMappings contextMappings = type.getContextMappings();
contextParser.nextToken();
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java
index 8eb0aa0529..88648395e6 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java
@@ -120,7 +120,8 @@ public final class PhraseSuggester extends Suggester<PhraseSuggestionContext> {
QueryShardContext shardContext = suggestion.getShardContext();
final ExecutableScript executable = collateScript.apply(vars);
final BytesReference querySource = (BytesReference) executable.run();
- try (XContentParser parser = XContentFactory.xContent(querySource).createParser(querySource)) {
+ try (XContentParser parser = XContentFactory.xContent(querySource).createParser(shardContext.getXContentRegistry(),
+ querySource)) {
QueryBuilder innerQueryBuilder = shardContext.newParseContext(parser).parseInnerQueryBuilder();
final ParsedQuery parsedQuery = shardContext.toQuery(innerQueryBuilder);
collateMatch = Lucene.exists(searcher, parsedQuery.query());