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:
Christoph Büscher 2015-08-05 19:19:45 +02:00
parent 32e98aa377
commit a3c294d4e9
16 changed files with 67 additions and 37 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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