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;
|
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.
|
//norelease to be made abstract once all query builders override doToQuery providing their own specific implementation.
|
||||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||||
return context.indexQueryParserService().queryParser(getName()).parse(context);
|
return context.indexQueryParserService().queryParser(getName()).parse(context);
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class AndQueryBuilder extends AbstractQueryBuilder<AndQueryBuilder> {
|
||||||
|
|
||||||
BooleanQuery query = new BooleanQuery();
|
BooleanQuery query = new BooleanQuery();
|
||||||
for (QueryBuilder f : filters) {
|
for (QueryBuilder f : filters) {
|
||||||
Query innerQuery = f.toQuery(context);
|
Query innerQuery = f.toFilter(context);
|
||||||
// ignore queries that are null
|
// ignore queries that are null
|
||||||
if (innerQuery != null) {
|
if (innerQuery != null) {
|
||||||
query.add(innerQuery, Occur.MUST);
|
query.add(innerQuery, Occur.MUST);
|
||||||
|
|
|
@ -279,9 +279,23 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> {
|
||||||
return validationException;
|
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) {
|
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) {
|
if (luceneQuery != null) {
|
||||||
booleanQuery.add(new BooleanClause(luceneQuery, occurs));
|
booleanQuery.add(new BooleanClause(luceneQuery, occurs));
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,12 +76,6 @@ public class BoolQueryParser extends BaseQueryParser {
|
||||||
case "should":
|
case "should":
|
||||||
query = parseContext.parseInnerQueryBuilder();
|
query = parseContext.parseInnerQueryBuilder();
|
||||||
shouldClauses.add(query);
|
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;
|
break;
|
||||||
case "filter":
|
case "filter":
|
||||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
|
@ -105,12 +99,6 @@ public class BoolQueryParser extends BaseQueryParser {
|
||||||
case "should":
|
case "should":
|
||||||
query = parseContext.parseInnerQueryBuilder();
|
query = parseContext.parseInnerQueryBuilder();
|
||||||
shouldClauses.add(query);
|
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;
|
break;
|
||||||
case "filter":
|
case "filter":
|
||||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
|
|
|
@ -68,12 +68,12 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||||
Query innerFilter = filterBuilder.toQuery(context);
|
Query innerFilter = filterBuilder.toFilter(context);
|
||||||
if (innerFilter == null ) {
|
if (innerFilter == null ) {
|
||||||
// return null so that parent queries (e.g. bool) also ignore this
|
// return null so that parent queries (e.g. bool) also ignore this
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new ConstantScoreQuery(filterBuilder.toQuery(context));
|
return new ConstantScoreQuery(innerFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -72,6 +72,13 @@ public class EmptyQueryBuilder extends ToXContentToBytes implements QueryBuilder
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Query toFilter(QueryShardContext context) throws IOException {
|
||||||
|
// empty
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryValidationException validate() {
|
public QueryValidationException validate() {
|
||||||
// nothing to validate
|
// nothing to validate
|
||||||
|
|
|
@ -70,7 +70,6 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
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);
|
Query innerQuery = this.queryBuilder.toQuery(context);
|
||||||
if (innerQuery == null) {
|
if (innerQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class FilteredQueryBuilder extends AbstractQueryBuilder<FilteredQueryBuil
|
||||||
@Override
|
@Override
|
||||||
public Query doToQuery(QueryShardContext context) throws QueryShardException, IOException {
|
public Query doToQuery(QueryShardContext context) throws QueryShardException, IOException {
|
||||||
Query query = queryBuilder.toQuery(context);
|
Query query = queryBuilder.toQuery(context);
|
||||||
Query filter = filterBuilder.toQuery(context);
|
Query filter = filterBuilder.toFilter(context);
|
||||||
|
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
// Most likely this query was generated from the JSON query DSL - it parsed to an EmptyQueryBuilder so we ignore
|
// 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;
|
boolean transpositions = FuzzyQuery.defaultTranspositions;
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
MultiTermQuery.RewriteMethod rewriteMethod = null;
|
MultiTermQuery.RewriteMethod rewriteMethod = null;
|
||||||
if (parseContext.isFilter()) {
|
if (context.isFilter()) {
|
||||||
rewriteMethod = MultiTermQuery.CONSTANT_SCORE_REWRITE;
|
rewriteMethod = MultiTermQuery.CONSTANT_SCORE_REWRITE;
|
||||||
}
|
}
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class NotQueryBuilder extends AbstractQueryBuilder<NotQueryBuilder> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||||
Query luceneQuery = filter.toQuery(context);
|
Query luceneQuery = filter.toFilter(context);
|
||||||
if (luceneQuery == null) {
|
if (luceneQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class OrQueryBuilder extends AbstractQueryBuilder<OrQueryBuilder> {
|
||||||
|
|
||||||
BooleanQuery query = new BooleanQuery();
|
BooleanQuery query = new BooleanQuery();
|
||||||
for (QueryBuilder f : filters) {
|
for (QueryBuilder f : filters) {
|
||||||
Query innerQuery = f.toQuery(context);
|
Query innerQuery = f.toFilter(context);
|
||||||
// ignore queries that are null
|
// ignore queries that are null
|
||||||
if (innerQuery != null) {
|
if (innerQuery != null) {
|
||||||
query.add(innerQuery, Occur.SHOULD);
|
query.add(innerQuery, Occur.SHOULD);
|
||||||
|
|
|
@ -49,6 +49,18 @@ public interface QueryBuilder<QB extends QueryBuilder> extends NamedWriteable<QB
|
||||||
*/
|
*/
|
||||||
Query toQuery(QueryShardContext context) throws IOException;
|
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}
|
* Returns a {@link org.elasticsearch.common.bytes.BytesReference}
|
||||||
* containing the {@link ToXContent} output in binary format.
|
* containing the {@link ToXContent} output in binary format.
|
||||||
|
|
|
@ -37,7 +37,6 @@ public class QueryParseContext {
|
||||||
private XContentParser parser;
|
private XContentParser parser;
|
||||||
private final Index index;
|
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()
|
//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;
|
private ParseFieldMatcher parseFieldMatcher;
|
||||||
|
|
||||||
//norelease this can eventually be deleted when context() method goes away
|
//norelease this can eventually be deleted when context() method goes away
|
||||||
|
@ -172,34 +171,32 @@ public class QueryParseContext {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
//norelease setting and checking the isFilter Flag should completely be moved to toQuery/toFilter after query refactoring
|
||||||
public QueryBuilder parseInnerFilterToQueryBuilder() throws IOException {
|
public QueryBuilder parseInnerFilterToQueryBuilder() throws IOException {
|
||||||
final boolean originalIsFilter = isFilter;
|
final boolean originalIsFilter = this.shardContext.isFilter;
|
||||||
try {
|
try {
|
||||||
isFilter = true;
|
this.shardContext.isFilter = true;
|
||||||
return parseInnerQueryBuilder();
|
return parseInnerQueryBuilder();
|
||||||
} finally {
|
} 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 {
|
QueryBuilder parseInnerFilterToQueryBuilder(String queryName) throws IOException, QueryParsingException {
|
||||||
final boolean originalIsFilter = isFilter;
|
final boolean originalIsFilter = this.shardContext.isFilter;
|
||||||
try {
|
try {
|
||||||
isFilter = true;
|
this.shardContext.isFilter = true;
|
||||||
QueryParser queryParser = queryParser(queryName);
|
QueryParser queryParser = queryParser(queryName);
|
||||||
if (queryParser == null) {
|
if (queryParser == null) {
|
||||||
throw new QueryParsingException(this, "No query registered for [" + queryName + "]");
|
throw new QueryParsingException(this, "No query registered for [" + queryName + "]");
|
||||||
}
|
}
|
||||||
return queryParser.fromXContent(this);
|
return queryParser.fromXContent(this);
|
||||||
} finally {
|
} finally {
|
||||||
isFilter = originalIsFilter;
|
this.shardContext.isFilter = originalIsFilter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFilter() {
|
|
||||||
return this.isFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ParseFieldMatcher parseFieldMatcher() {
|
public ParseFieldMatcher parseFieldMatcher() {
|
||||||
return parseFieldMatcher;
|
return parseFieldMatcher;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class QueryShardContext {
|
||||||
//norelease this should be possible to remove once query context are completely separated
|
//norelease this should be possible to remove once query context are completely separated
|
||||||
private QueryParseContext parseContext;
|
private QueryParseContext parseContext;
|
||||||
|
|
||||||
private boolean isFilter;
|
boolean isFilter;
|
||||||
|
|
||||||
public QueryShardContext(Index index, IndexQueryParserService indexQueryParser) {
|
public QueryShardContext(Index index, IndexQueryParserService indexQueryParser) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
|
|
@ -180,7 +180,7 @@ public class TermsQueryParser extends BaseQueryParserTemp {
|
||||||
}
|
}
|
||||||
|
|
||||||
Query query;
|
Query query;
|
||||||
if (parseContext.isFilter()) {
|
if (context.isFilter()) {
|
||||||
if (fieldType != null) {
|
if (fieldType != null) {
|
||||||
query = fieldType.termsQuery(terms, context);
|
query = fieldType.termsQuery(terms, context);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class DummyQueryParserPlugin extends AbstractPlugin {
|
||||||
public Query parse(QueryShardContext context) throws IOException, QueryShardException {
|
public Query parse(QueryShardContext context) throws IOException, QueryShardException {
|
||||||
XContentParser.Token token = context.parseContext().parser().nextToken();
|
XContentParser.Token token = context.parseContext().parser().nextToken();
|
||||||
assert token == XContentParser.Token.END_OBJECT;
|
assert token == XContentParser.Token.END_OBJECT;
|
||||||
return new DummyQuery(context.parseContext().isFilter());
|
return new DummyQuery(context.isFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue