Move flag to track filter context to QueryShardContext
Currently there is a flag in the QueryParseContext that keeps track of whether an inner query sits inside a filter and should therefore produce an unscored lucene query. This is done in the parseInnerFilter...() methods that are called in the fromXContent() methods or the parse() methods we haven't refactored yet. This needs to move to the toQuery() method in the refactored builders, since the query builders themselves have no information about the parent query they might be nested in. This PR moves the isFilter flag from the QueryParseContext to the re- cently introduces QueryShardContext. The parseInnerFilter... methods need to stay in the QueryParseContext for now, but they already delegate to the flag that is kept in QueryShardContext. For refactored queries (like BoolQueryBuilder) references to isFilter() are moved from the parser to the corresponding builder. Builders where the inner query was previously parsed using parseInnerFilter...() now use a newly introduces toFilter(shardContext) method that produces the nested lucene query with the filter context flag switched on. Closes #12731
This commit is contained in:
parent
32e98aa377
commit
a3c294d4e9
|
@ -79,6 +79,19 @@ public abstract class AbstractQueryBuilder<QB extends AbstractQueryBuilder> exte
|
|||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Query toFilter(QueryShardContext context) throws IOException {
|
||||
Query result = null;
|
||||
final boolean originalIsFilter = context.isFilter;
|
||||
try {
|
||||
context.isFilter = true;
|
||||
result = toQuery(context);
|
||||
} finally {
|
||||
context.isFilter = originalIsFilter;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//norelease to be made abstract once all query builders override doToQuery providing their own specific implementation.
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
return context.indexQueryParserService().queryParser(getName()).parse(context);
|
||||
|
|
|
@ -92,7 +92,7 @@ public class AndQueryBuilder extends AbstractQueryBuilder<AndQueryBuilder> {
|
|||
|
||||
BooleanQuery query = new BooleanQuery();
|
||||
for (QueryBuilder f : filters) {
|
||||
Query innerQuery = f.toQuery(context);
|
||||
Query innerQuery = f.toFilter(context);
|
||||
// ignore queries that are null
|
||||
if (innerQuery != null) {
|
||||
query.add(innerQuery, Occur.MUST);
|
||||
|
|
|
@ -279,9 +279,23 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> {
|
|||
return validationException;
|
||||
}
|
||||
|
||||
private static void addBooleanClauses(QueryShardContext context, BooleanQuery booleanQuery, List<QueryBuilder> clauses, Occur occurs) throws IOException {
|
||||
private void addBooleanClauses(QueryShardContext context, BooleanQuery booleanQuery, List<QueryBuilder> clauses, Occur occurs) throws IOException {
|
||||
for (QueryBuilder query : clauses) {
|
||||
Query luceneQuery = query.toQuery(context);
|
||||
Query luceneQuery = null;
|
||||
switch (occurs) {
|
||||
case SHOULD:
|
||||
if (context.isFilter() && minimumShouldMatch == null) {
|
||||
minimumShouldMatch = "1";
|
||||
}
|
||||
luceneQuery = query.toQuery(context);
|
||||
break;
|
||||
case FILTER:
|
||||
case MUST_NOT:
|
||||
luceneQuery = query.toFilter(context);
|
||||
break;
|
||||
case MUST:
|
||||
luceneQuery = query.toQuery(context);
|
||||
}
|
||||
if (luceneQuery != null) {
|
||||
booleanQuery.add(new BooleanClause(luceneQuery, occurs));
|
||||
}
|
||||
|
|
|
@ -76,12 +76,6 @@ public class BoolQueryParser extends BaseQueryParser {
|
|||
case "should":
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
shouldClauses.add(query);
|
||||
// EmptyQueryBuilder does not add lucene query later, skip setting minuminShouldMatch
|
||||
if (query != EmptyQueryBuilder.PROTOTYPE) {
|
||||
if (parseContext.isFilter() && minimumShouldMatch == null) {
|
||||
minimumShouldMatch = "1";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "filter":
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
|
@ -105,12 +99,6 @@ public class BoolQueryParser extends BaseQueryParser {
|
|||
case "should":
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
shouldClauses.add(query);
|
||||
// EmptyQueryBuilder does not add lucene query later, skip setting minuminShouldMatch
|
||||
if (query != EmptyQueryBuilder.PROTOTYPE) {
|
||||
if (parseContext.isFilter() && minimumShouldMatch == null) {
|
||||
minimumShouldMatch = "1";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "filter":
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
|
|
|
@ -68,12 +68,12 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
Query innerFilter = filterBuilder.toQuery(context);
|
||||
Query innerFilter = filterBuilder.toFilter(context);
|
||||
if (innerFilter == null ) {
|
||||
// return null so that parent queries (e.g. bool) also ignore this
|
||||
return null;
|
||||
}
|
||||
return new ConstantScoreQuery(filterBuilder.toQuery(context));
|
||||
return new ConstantScoreQuery(innerFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -72,6 +72,13 @@ public class EmptyQueryBuilder extends ToXContentToBytes implements QueryBuilder
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query toFilter(QueryShardContext context) throws IOException {
|
||||
// empty
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public QueryValidationException validate() {
|
||||
// nothing to validate
|
||||
|
|
|
@ -70,7 +70,6 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
// inner query builder can potentially be `null`, in that case we ignore it
|
||||
Query innerQuery = this.queryBuilder.toQuery(context);
|
||||
if (innerQuery == null) {
|
||||
return null;
|
||||
|
|
|
@ -97,7 +97,7 @@ public class FilteredQueryBuilder extends AbstractQueryBuilder<FilteredQueryBuil
|
|||
@Override
|
||||
public Query doToQuery(QueryShardContext context) throws QueryShardException, IOException {
|
||||
Query query = queryBuilder.toQuery(context);
|
||||
Query filter = filterBuilder.toQuery(context);
|
||||
Query filter = filterBuilder.toFilter(context);
|
||||
|
||||
if (query == null) {
|
||||
// Most likely this query was generated from the JSON query DSL - it parsed to an EmptyQueryBuilder so we ignore
|
||||
|
|
|
@ -70,7 +70,7 @@ public class FuzzyQueryParser extends BaseQueryParserTemp {
|
|||
boolean transpositions = FuzzyQuery.defaultTranspositions;
|
||||
String queryName = null;
|
||||
MultiTermQuery.RewriteMethod rewriteMethod = null;
|
||||
if (parseContext.isFilter()) {
|
||||
if (context.isFilter()) {
|
||||
rewriteMethod = MultiTermQuery.CONSTANT_SCORE_REWRITE;
|
||||
}
|
||||
token = parser.nextToken();
|
||||
|
|
|
@ -61,7 +61,7 @@ public class NotQueryBuilder extends AbstractQueryBuilder<NotQueryBuilder> {
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
Query luceneQuery = filter.toQuery(context);
|
||||
Query luceneQuery = filter.toFilter(context);
|
||||
if (luceneQuery == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ public class OrQueryBuilder extends AbstractQueryBuilder<OrQueryBuilder> {
|
|||
|
||||
BooleanQuery query = new BooleanQuery();
|
||||
for (QueryBuilder f : filters) {
|
||||
Query innerQuery = f.toQuery(context);
|
||||
Query innerQuery = f.toFilter(context);
|
||||
// ignore queries that are null
|
||||
if (innerQuery != null) {
|
||||
query.add(innerQuery, Occur.SHOULD);
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|||
import java.io.IOException;
|
||||
|
||||
public interface QueryBuilder<QB extends QueryBuilder> extends NamedWriteable<QB>, ToXContent {
|
||||
|
||||
|
||||
/**
|
||||
* Validate the query.
|
||||
* @return a {@link QueryValidationException} containing error messages, {@code null} if query is valid.
|
||||
|
@ -49,6 +49,18 @@ public interface QueryBuilder<QB extends QueryBuilder> extends NamedWriteable<QB
|
|||
*/
|
||||
Query toQuery(QueryShardContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Converts this QueryBuilder to an unscored lucene {@link Query} that acts as a filter.
|
||||
* Returns <tt>null</tt> if this query should be ignored in the context of
|
||||
* parent queries.
|
||||
*
|
||||
* @param context additional information needed to construct the queries
|
||||
* @return the {@link Query} or <tt>null</tt> if this query should be ignored upstream
|
||||
* @throws QueryShardException
|
||||
* @throws IOException
|
||||
*/
|
||||
Query toFilter(QueryShardContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a {@link org.elasticsearch.common.bytes.BytesReference}
|
||||
* containing the {@link ToXContent} output in binary format.
|
||||
|
|
|
@ -37,7 +37,6 @@ public class QueryParseContext {
|
|||
private XContentParser parser;
|
||||
private final Index index;
|
||||
//norelease this flag is also used in the QueryShardContext, we need to make sure we set it there correctly in doToQuery()
|
||||
private boolean isFilter;
|
||||
private ParseFieldMatcher parseFieldMatcher;
|
||||
|
||||
//norelease this can eventually be deleted when context() method goes away
|
||||
|
@ -172,34 +171,32 @@ public class QueryParseContext {
|
|||
* @throws IOException
|
||||
*/
|
||||
@Nullable
|
||||
//norelease setting and checking the isFilter Flag should completely be moved to toQuery/toFilter after query refactoring
|
||||
public QueryBuilder parseInnerFilterToQueryBuilder() throws IOException {
|
||||
final boolean originalIsFilter = isFilter;
|
||||
final boolean originalIsFilter = this.shardContext.isFilter;
|
||||
try {
|
||||
isFilter = true;
|
||||
this.shardContext.isFilter = true;
|
||||
return parseInnerQueryBuilder();
|
||||
} finally {
|
||||
isFilter = originalIsFilter;
|
||||
this.shardContext.isFilter = originalIsFilter;
|
||||
}
|
||||
}
|
||||
|
||||
//norelease setting and checking the isFilter Flag should completely be moved to toQuery/toFilter after query refactoring
|
||||
QueryBuilder parseInnerFilterToQueryBuilder(String queryName) throws IOException, QueryParsingException {
|
||||
final boolean originalIsFilter = isFilter;
|
||||
final boolean originalIsFilter = this.shardContext.isFilter;
|
||||
try {
|
||||
isFilter = true;
|
||||
this.shardContext.isFilter = true;
|
||||
QueryParser queryParser = queryParser(queryName);
|
||||
if (queryParser == null) {
|
||||
throw new QueryParsingException(this, "No query registered for [" + queryName + "]");
|
||||
}
|
||||
return queryParser.fromXContent(this);
|
||||
} finally {
|
||||
isFilter = originalIsFilter;
|
||||
this.shardContext.isFilter = originalIsFilter;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFilter() {
|
||||
return this.isFilter;
|
||||
}
|
||||
|
||||
public ParseFieldMatcher parseFieldMatcher() {
|
||||
return parseFieldMatcher;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ public class QueryShardContext {
|
|||
//norelease this should be possible to remove once query context are completely separated
|
||||
private QueryParseContext parseContext;
|
||||
|
||||
private boolean isFilter;
|
||||
boolean isFilter;
|
||||
|
||||
public QueryShardContext(Index index, IndexQueryParserService indexQueryParser) {
|
||||
this.index = index;
|
||||
|
|
|
@ -180,7 +180,7 @@ public class TermsQueryParser extends BaseQueryParserTemp {
|
|||
}
|
||||
|
||||
Query query;
|
||||
if (parseContext.isFilter()) {
|
||||
if (context.isFilter()) {
|
||||
if (fieldType != null) {
|
||||
query = fieldType.termsQuery(terms, context);
|
||||
} else {
|
||||
|
|
|
@ -81,7 +81,7 @@ public class DummyQueryParserPlugin extends AbstractPlugin {
|
|||
public Query parse(QueryShardContext context) throws IOException, QueryShardException {
|
||||
XContentParser.Token token = context.parseContext().parser().nextToken();
|
||||
assert token == XContentParser.Token.END_OBJECT;
|
||||
return new DummyQuery(context.parseContext().isFilter());
|
||||
return new DummyQuery(context.isFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue