Merge pull request #11915 from cbuescher/feature/query-refactoring-emptyquerybuilder
Query Refactoring: Make parsing nested queries always return query builder
This commit is contained in:
commit
faa4e98aa5
|
@ -233,22 +233,6 @@ public abstract class AbstractQueryBuilder<QB extends AbstractQueryBuilder> exte
|
|||
return queries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method that converts inner query builders to xContent and
|
||||
* checks for null values, rendering out empty object in this case.
|
||||
*/
|
||||
protected static void doXContentInnerBuilder(XContentBuilder xContentBuilder, String fieldName,
|
||||
QueryBuilder queryBuilder, Params params) throws IOException {
|
||||
xContentBuilder.field(fieldName);
|
||||
if (queryBuilder != null) {
|
||||
queryBuilder.toXContent(xContentBuilder, params);
|
||||
} else {
|
||||
// we output an empty object, QueryParseContext#parseInnerQueryBuilder will parse this back to `null` value
|
||||
xContentBuilder.startObject();
|
||||
xContentBuilder.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
protected static QueryValidationException validateInnerQueries(List<QueryBuilder> queryBuilders, QueryValidationException initialValidationException) {
|
||||
QueryValidationException validationException = initialValidationException;
|
||||
for (QueryBuilder queryBuilder : queryBuilders) {
|
||||
|
|
|
@ -98,6 +98,10 @@ public class AndQueryBuilder extends AbstractQueryBuilder<AndQueryBuilder> {
|
|||
query.add(innerQuery, Occur.MUST);
|
||||
}
|
||||
}
|
||||
if (query.clauses().isEmpty()) {
|
||||
// no inner lucene query exists, ignore upstream
|
||||
return null;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,7 @@ public class AndQueryParser extends BaseQueryParser {
|
|||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
queriesFound = true;
|
||||
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (filter != null) {
|
||||
queries.add(filter);
|
||||
}
|
||||
queries.add(filter);
|
||||
}
|
||||
} else {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
|
@ -69,17 +67,13 @@ public class AndQueryParser extends BaseQueryParser {
|
|||
queriesFound = true;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (filter != null) {
|
||||
queries.add(filter);
|
||||
}
|
||||
queries.add(filter);
|
||||
}
|
||||
} else {
|
||||
queriesFound = true;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (filter != null) {
|
||||
queries.add(filter);
|
||||
}
|
||||
queries.add(filter);
|
||||
}
|
||||
}
|
||||
} else if (token.isValue()) {
|
||||
|
|
|
@ -255,16 +255,16 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> {
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
if (!hasClauses()) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
BooleanQuery booleanQuery = new BooleanQuery(disableCoord);
|
||||
addBooleanClauses(parseContext, booleanQuery, mustClauses, BooleanClause.Occur.MUST);
|
||||
addBooleanClauses(parseContext, booleanQuery, mustNotClauses, BooleanClause.Occur.MUST_NOT);
|
||||
addBooleanClauses(parseContext, booleanQuery, shouldClauses, BooleanClause.Occur.SHOULD);
|
||||
addBooleanClauses(parseContext, booleanQuery, filterClauses, BooleanClause.Occur.FILTER);
|
||||
|
||||
if (booleanQuery.clauses().isEmpty()) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
Queries.applyMinimumShouldMatch(booleanQuery, minimumShouldMatch);
|
||||
return adjustPureNegative ? fixNegativeQueryIfNeeded(booleanQuery) : booleanQuery;
|
||||
}
|
||||
|
|
|
@ -71,14 +71,13 @@ public class BoolQueryParser extends BaseQueryParser {
|
|||
switch (currentFieldName) {
|
||||
case "must":
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
mustClauses.add(query);
|
||||
}
|
||||
mustClauses.add(query);
|
||||
break;
|
||||
case "should":
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
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";
|
||||
}
|
||||
|
@ -86,16 +85,12 @@ public class BoolQueryParser extends BaseQueryParser {
|
|||
break;
|
||||
case "filter":
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
filterClauses.add(query);
|
||||
}
|
||||
filterClauses.add(query);
|
||||
break;
|
||||
case "must_not":
|
||||
case "mustNot":
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
mustNotClauses.add(query);
|
||||
}
|
||||
mustNotClauses.add(query);
|
||||
break;
|
||||
default:
|
||||
throw new QueryParsingException(parseContext, "[bool] query does not support [" + currentFieldName + "]");
|
||||
|
@ -105,14 +100,13 @@ public class BoolQueryParser extends BaseQueryParser {
|
|||
switch (currentFieldName) {
|
||||
case "must":
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
mustClauses.add(query);
|
||||
}
|
||||
mustClauses.add(query);
|
||||
break;
|
||||
case "should":
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
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";
|
||||
}
|
||||
|
@ -120,16 +114,12 @@ public class BoolQueryParser extends BaseQueryParser {
|
|||
break;
|
||||
case "filter":
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
filterClauses.add(query);
|
||||
}
|
||||
filterClauses.add(query);
|
||||
break;
|
||||
case "must_not":
|
||||
case "mustNot":
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
mustNotClauses.add(query);
|
||||
}
|
||||
mustNotClauses.add(query);
|
||||
break;
|
||||
default:
|
||||
throw new QueryParsingException(parseContext, "bool query does not support [" + currentFieldName + "]");
|
||||
|
|
|
@ -44,23 +44,31 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
|||
|
||||
public static final String NAME = "boosting";
|
||||
|
||||
private QueryBuilder positiveQuery;
|
||||
private final QueryBuilder positiveQuery;
|
||||
|
||||
private QueryBuilder negativeQuery;
|
||||
private final QueryBuilder negativeQuery;
|
||||
|
||||
private float negativeBoost = -1;
|
||||
|
||||
static final BoostingQueryBuilder PROTOTYPE = new BoostingQueryBuilder();
|
||||
|
||||
public BoostingQueryBuilder() {
|
||||
/**
|
||||
* this constructor only used for prototype
|
||||
*/
|
||||
private BoostingQueryBuilder() {
|
||||
this.positiveQuery = null;
|
||||
this.negativeQuery = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the positive query for this boosting query.
|
||||
* Create a new {@link BoostingQueryBuilder}
|
||||
*
|
||||
* @param positiveQuery the positive query for this boosting query.
|
||||
* @param negativeQuery the negative query for this boosting query.
|
||||
*/
|
||||
public BoostingQueryBuilder positive(QueryBuilder positiveQuery) {
|
||||
this.positiveQuery = positiveQuery;
|
||||
return this;
|
||||
public BoostingQueryBuilder(QueryBuilder positiveQuery, QueryBuilder negativeQuery) {
|
||||
this.positiveQuery = Objects.requireNonNull(positiveQuery);
|
||||
this.negativeQuery = Objects.requireNonNull(negativeQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,14 +78,6 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
|||
return this.positiveQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the negative query for this boosting query.
|
||||
*/
|
||||
public BoostingQueryBuilder negative(QueryBuilder negativeQuery) {
|
||||
this.negativeQuery = negativeQuery;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the negative query for this boosting query.
|
||||
*/
|
||||
|
@ -103,8 +103,10 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
|||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(NAME);
|
||||
doXContentInnerBuilder(builder, "positive", positiveQuery, params);
|
||||
doXContentInnerBuilder(builder, "negative", negativeQuery, params);
|
||||
builder.field("positive");
|
||||
positiveQuery.toXContent(builder, params);
|
||||
builder.field("negative");
|
||||
negativeQuery.toXContent(builder, params);
|
||||
builder.field("negative_boost", negativeBoost);
|
||||
printBoostAndQueryName(builder);
|
||||
builder.endObject();
|
||||
|
@ -128,13 +130,10 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
// make upstream queries ignore this query by returning `null`
|
||||
// if either inner query builder is null or returns null-Query
|
||||
if (positiveQuery == null || negativeQuery == null) {
|
||||
return null;
|
||||
}
|
||||
Query positive = positiveQuery.toQuery(parseContext);
|
||||
Query negative = negativeQuery.toQuery(parseContext);
|
||||
// make upstream queries ignore this query by returning `null`
|
||||
// if either inner query builder returns null
|
||||
if (positive == null || negative == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -158,9 +157,7 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
|||
protected BoostingQueryBuilder doReadFrom(StreamInput in) throws IOException {
|
||||
QueryBuilder positiveQuery = in.readNamedWriteable();
|
||||
QueryBuilder negativeQuery = in.readNamedWriteable();
|
||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
|
||||
boostingQuery.positive(positiveQuery);
|
||||
boostingQuery.negative(negativeQuery);
|
||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positiveQuery, negativeQuery);
|
||||
boostingQuery.negativeBoost = in.readFloat();
|
||||
return boostingQuery;
|
||||
}
|
||||
|
|
|
@ -88,9 +88,7 @@ public class BoostingQueryParser extends BaseQueryParser {
|
|||
throw new QueryParsingException(parseContext, "[boosting] query requires 'negative_boost' to be set to be a positive value'");
|
||||
}
|
||||
|
||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
|
||||
boostingQuery.positive(positiveQuery);
|
||||
boostingQuery.negative(negativeQuery);
|
||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positiveQuery, negativeQuery);
|
||||
boostingQuery.negativeBoost(negativeBoost);
|
||||
boostingQuery.boost(boost);
|
||||
boostingQuery.queryName(queryName);
|
||||
|
|
|
@ -38,7 +38,12 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
|||
|
||||
private final QueryBuilder filterBuilder;
|
||||
|
||||
static final ConstantScoreQueryBuilder PROTOTYPE = new ConstantScoreQueryBuilder(null);
|
||||
static final ConstantScoreQueryBuilder PROTOTYPE = new ConstantScoreQueryBuilder();
|
||||
|
||||
// only used for prototype
|
||||
private ConstantScoreQueryBuilder() {
|
||||
this.filterBuilder = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A query that wraps another query and simply returns a constant score equal to the
|
||||
|
@ -47,7 +52,7 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
|||
* @param filterBuilder The query to wrap in a constant score query
|
||||
*/
|
||||
public ConstantScoreQueryBuilder(QueryBuilder filterBuilder) {
|
||||
this.filterBuilder = filterBuilder;
|
||||
this.filterBuilder = Objects.requireNonNull(filterBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,24 +65,19 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
|||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(NAME);
|
||||
doXContentInnerBuilder(builder, "filter", filterBuilder, params);
|
||||
builder.field("filter");
|
||||
filterBuilder.toXContent(builder, params);
|
||||
printBoostAndQueryName(builder);
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
// current DSL allows empty inner filter clauses, we ignore them
|
||||
if (filterBuilder == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Query innerFilter = filterBuilder.toQuery(parseContext);
|
||||
if (innerFilter == null ) {
|
||||
// return null so that parent queries (e.g. bool) also ignore this
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ConstantScoreQuery(filterBuilder.toQuery(parseContext));
|
||||
}
|
||||
|
||||
|
|
|
@ -62,9 +62,7 @@ public class DisMaxQueryParser extends BaseQueryParser {
|
|||
if ("queries".equals(currentFieldName)) {
|
||||
queriesFound = true;
|
||||
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
queries.add(query);
|
||||
}
|
||||
queries.add(query);
|
||||
} else {
|
||||
throw new QueryParsingException(parseContext, "[dis_max] query does not support [" + currentFieldName + "]");
|
||||
}
|
||||
|
@ -73,9 +71,7 @@ public class DisMaxQueryParser extends BaseQueryParser {
|
|||
queriesFound = true;
|
||||
while (token != XContentParser.Token.END_ARRAY) {
|
||||
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
queries.add(query);
|
||||
}
|
||||
queries.add(query);
|
||||
token = parser.nextToken();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A {@link QueryBuilder} that is a stand in replacement for an empty query clause in the DSL.
|
||||
* The current DSL allows parsing inner queries / filters like "{ }", in order to have a
|
||||
* valid non-null representation of these clauses that actually do nothing we can use this class.
|
||||
*
|
||||
* This builder has no corresponding parser and it is not registered under the query name. It is
|
||||
* intended to be used internally as a stand-in for nested queries that are left empty and should
|
||||
* be ignored upstream.
|
||||
*/
|
||||
public class EmptyQueryBuilder extends AbstractQueryBuilder<EmptyQueryBuilder> {
|
||||
|
||||
public static final String NAME = "empty_query";
|
||||
|
||||
/** the one and only empty query builder */
|
||||
public static final EmptyQueryBuilder PROTOTYPE = new EmptyQueryBuilder();
|
||||
|
||||
private EmptyQueryBuilder() {
|
||||
// prevent other constructors
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns <tt>null</tt> to signal to caller that this query should be ignored
|
||||
* in the context of the DSL.
|
||||
*/
|
||||
@Override
|
||||
public Query doToQuery(QueryParseContext parseContext) throws QueryParsingException, IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryValidationException validate() {
|
||||
// nothing to validate
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyQueryBuilder doReadFrom(StreamInput in) throws IOException {
|
||||
return EmptyQueryBuilder.PROTOTYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWriteTo(StreamOutput out) throws IOException {
|
||||
// nothing to serialize
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
|||
|
||||
public static final String NAME = "fquery";
|
||||
|
||||
static final FQueryFilterBuilder PROTOTYPE = new FQueryFilterBuilder(null);
|
||||
static final FQueryFilterBuilder PROTOTYPE = new FQueryFilterBuilder();
|
||||
|
||||
private final QueryBuilder queryBuilder;
|
||||
|
||||
|
@ -49,7 +49,11 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
|||
* @param queryBuilder The query to wrap as a filter
|
||||
*/
|
||||
public FQueryFilterBuilder(QueryBuilder queryBuilder) {
|
||||
this.queryBuilder = queryBuilder;
|
||||
this.queryBuilder = Objects.requireNonNull(queryBuilder);
|
||||
}
|
||||
|
||||
private FQueryFilterBuilder() {
|
||||
this.queryBuilder = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,7 +66,8 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
|||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(FQueryFilterBuilder.NAME);
|
||||
doXContentInnerBuilder(builder, "query", queryBuilder, params);
|
||||
builder.field("query");
|
||||
queryBuilder.toXContent(builder, params);
|
||||
printBoostAndQueryName(builder);
|
||||
builder.endObject();
|
||||
}
|
||||
|
@ -70,9 +75,6 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
|||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
// inner query builder can potentially be `null`, in that case we ignore it
|
||||
if (this.queryBuilder == null) {
|
||||
return null;
|
||||
}
|
||||
Query innerQuery = this.queryBuilder.toQuery(parseContext);
|
||||
if (innerQuery == null) {
|
||||
return null;
|
||||
|
|
|
@ -76,9 +76,6 @@ public class FQueryFilterParser extends BaseQueryParser {
|
|||
if (!queryFound) {
|
||||
throw new QueryParsingException(parseContext, "[fquery] requires 'query' element");
|
||||
}
|
||||
if (wrappedQuery == null) {
|
||||
return null;
|
||||
}
|
||||
FQueryFilterBuilder queryBuilder = new FQueryFilterBuilder(wrappedQuery);
|
||||
queryBuilder.queryName(queryName);
|
||||
queryBuilder.boost(boost);
|
||||
|
|
|
@ -40,6 +40,7 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
|
||||
static final FieldMaskingSpanQueryBuilder PROTOTYPE = new FieldMaskingSpanQueryBuilder();
|
||||
|
||||
// only used for prototype
|
||||
private FieldMaskingSpanQueryBuilder() {
|
||||
this.queryBuilder = null;
|
||||
this.fieldName = null;
|
||||
|
@ -53,7 +54,7 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
*/
|
||||
public FieldMaskingSpanQueryBuilder(SpanQueryBuilder queryBuilder, String fieldName) {
|
||||
this.queryBuilder = Objects.requireNonNull(queryBuilder);
|
||||
this.fieldName = fieldName;
|
||||
this.fieldName = Objects.requireNonNull(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,7 +74,8 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(NAME);
|
||||
doXContentInnerBuilder(builder, "query", queryBuilder, params);
|
||||
builder.field("query");
|
||||
queryBuilder.toXContent(builder, params);
|
||||
builder.field("field", fieldName);
|
||||
printBoostAndQueryName(builder);
|
||||
builder.endObject();
|
||||
|
|
|
@ -37,10 +37,14 @@ public class NotQueryBuilder extends AbstractQueryBuilder<NotQueryBuilder> {
|
|||
|
||||
private final QueryBuilder filter;
|
||||
|
||||
static final NotQueryBuilder PROTOTYPE = new NotQueryBuilder(null);
|
||||
static final NotQueryBuilder PROTOTYPE = new NotQueryBuilder();
|
||||
|
||||
public NotQueryBuilder(QueryBuilder filter) {
|
||||
this.filter = filter;
|
||||
this.filter = Objects.requireNonNull(filter);
|
||||
}
|
||||
|
||||
private NotQueryBuilder() {
|
||||
this.filter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,16 +57,14 @@ public class NotQueryBuilder extends AbstractQueryBuilder<NotQueryBuilder> {
|
|||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(NAME);
|
||||
doXContentInnerBuilder(builder, "query", filter, params);
|
||||
builder.field("query");
|
||||
filter.toXContent(builder, params);
|
||||
printBoostAndQueryName(builder);
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
if (filter == null) {
|
||||
return null;
|
||||
}
|
||||
Query luceneQuery = filter.toQuery(parseContext);
|
||||
if (luceneQuery == null) {
|
||||
return null;
|
||||
|
|
|
@ -95,6 +95,10 @@ public class OrQueryBuilder extends AbstractQueryBuilder<OrQueryBuilder> {
|
|||
query.add(innerQuery, Occur.SHOULD);
|
||||
}
|
||||
}
|
||||
if (query.clauses().isEmpty()) {
|
||||
// no inner lucene query exists, ignore upstream
|
||||
return null;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
|
|
|
@ -277,8 +277,8 @@ public abstract class QueryBuilders {
|
|||
* Unlike the "NOT" clause, this still selects documents that contain undesirable terms,
|
||||
* but reduces their overall score:
|
||||
*/
|
||||
public static BoostingQueryBuilder boostingQuery() {
|
||||
return new BoostingQueryBuilder();
|
||||
public static BoostingQueryBuilder boostingQuery(QueryBuilder positiveQuery, QueryBuilder negativeQuery) {
|
||||
return new BoostingQueryBuilder(positiveQuery, negativeQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,7 +40,7 @@ public class QueryFilterBuilder extends AbstractQueryBuilder<QueryFilterBuilder>
|
|||
|
||||
private final QueryBuilder queryBuilder;
|
||||
|
||||
static final QueryFilterBuilder PROTOTYPE = new QueryFilterBuilder(null);
|
||||
static final QueryFilterBuilder PROTOTYPE = new QueryFilterBuilder();
|
||||
|
||||
/**
|
||||
* A filter that simply wraps a query.
|
||||
|
@ -48,7 +48,11 @@ public class QueryFilterBuilder extends AbstractQueryBuilder<QueryFilterBuilder>
|
|||
* @param queryBuilder The query to wrap as a filter
|
||||
*/
|
||||
public QueryFilterBuilder(QueryBuilder queryBuilder) {
|
||||
this.queryBuilder = queryBuilder;
|
||||
this.queryBuilder = Objects.requireNonNull(queryBuilder);
|
||||
}
|
||||
|
||||
private QueryFilterBuilder() {
|
||||
this.queryBuilder = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,15 +76,13 @@ public class QueryFilterBuilder extends AbstractQueryBuilder<QueryFilterBuilder>
|
|||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
doXContentInnerBuilder(builder, NAME, queryBuilder, params);
|
||||
builder.field(NAME);
|
||||
queryBuilder.toXContent(builder, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
// inner query builder can potentially be `null`, in that case we ignore it
|
||||
if (this.queryBuilder == null) {
|
||||
return null;
|
||||
}
|
||||
Query innerQuery = this.queryBuilder.toQuery(parseContext);
|
||||
if (innerQuery == null) {
|
||||
return null;
|
||||
|
|
|
@ -232,7 +232,7 @@ public class QueryParseContext {
|
|||
token = parser.nextToken();
|
||||
if (token == XContentParser.Token.END_OBJECT) {
|
||||
// empty query
|
||||
return null;
|
||||
return EmptyQueryBuilder.PROTOTYPE;
|
||||
}
|
||||
if (token != XContentParser.Token.FIELD_NAME) {
|
||||
throw new QueryParsingException(this, "[_na] query malformed, no field after start_object");
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.elasticsearch.common.component.AbstractComponent;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.query.EmptyQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryParser;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -45,6 +46,9 @@ public class IndicesQueriesRegistry extends AbstractComponent {
|
|||
}
|
||||
namedWriteableRegistry.registerPrototype(queryParser.getBuilderPrototype());
|
||||
}
|
||||
// EmptyQueryBuilder is not registered as query parser but used internally.
|
||||
// We need to register it with the NamedWriteableRegistry in order to serialize it
|
||||
namedWriteableRegistry.registerPrototype(EmptyQueryBuilder.PROTOTYPE);
|
||||
this.queryParsers = ImmutableMap.copyOf(queryParsers);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,9 @@ public class AndQueryBuilderTest extends BaseQueryTestCase<AndQueryBuilder> {
|
|||
query.add(innerQuery, Occur.MUST);
|
||||
}
|
||||
}
|
||||
if (query.clauses().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
|
@ -78,6 +81,16 @@ public class AndQueryBuilderTest extends BaseQueryTestCase<AndQueryBuilder> {
|
|||
context.indexQueryParserService().queryParser(AndQueryBuilder.PROTOTYPE.getName()).fromXContent(context);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullConstructor() {
|
||||
new AndQueryBuilder(EmptyQueryBuilder.PROTOTYPE, null);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNull() {
|
||||
new AndQueryBuilder(EmptyQueryBuilder.PROTOTYPE).add(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate() {
|
||||
AndQueryBuilder andQuery = new AndQueryBuilder();
|
||||
|
|
|
@ -234,14 +234,22 @@ public abstract class BaseQueryTestCase<QB extends AbstractQueryBuilder<QB>> ext
|
|||
|
||||
Query expectedQuery = createExpectedQuery(testQuery, context);
|
||||
Query actualQuery = testQuery.toQuery(context);
|
||||
assertThat(actualQuery, instanceOf(expectedQuery.getClass()));
|
||||
assertThat(actualQuery, equalTo(expectedQuery));
|
||||
assertLuceneQuery(testQuery, actualQuery, context);
|
||||
// expectedQuery can be null, e.g. in case of BoostingQueryBuilder
|
||||
// with inner clause that returns null itself
|
||||
if (expectedQuery == null) {
|
||||
assertNull("Expected a null query, saw some object.", actualQuery);
|
||||
} else {
|
||||
assertThat(actualQuery, instanceOf(expectedQuery.getClass()));
|
||||
assertThat(actualQuery, equalTo(expectedQuery));
|
||||
assertLuceneQuery(testQuery, actualQuery, context);
|
||||
}
|
||||
}
|
||||
|
||||
protected final Query createExpectedQuery(QB queryBuilder, QueryParseContext context) throws IOException {
|
||||
Query expectedQuery = doCreateExpectedQuery(queryBuilder, context);
|
||||
expectedQuery.setBoost(queryBuilder.boost());
|
||||
if (expectedQuery != null) {
|
||||
expectedQuery.setBoost(queryBuilder.boost());
|
||||
}
|
||||
return expectedQuery;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,12 +72,14 @@ public class BoolQueryBuilderTest extends BaseQueryTestCase<BoolQueryBuilder> {
|
|||
}
|
||||
|
||||
BooleanQuery boolQuery = new BooleanQuery(queryBuilder.disableCoord());
|
||||
boolQuery.setBoost(queryBuilder.boost());
|
||||
addBooleanClauses(context, boolQuery, queryBuilder.must(), BooleanClause.Occur.MUST);
|
||||
addBooleanClauses(context, boolQuery, queryBuilder.mustNot(), BooleanClause.Occur.MUST_NOT);
|
||||
addBooleanClauses(context, boolQuery, queryBuilder.should(), BooleanClause.Occur.SHOULD);
|
||||
addBooleanClauses(context, boolQuery, queryBuilder.filter(), BooleanClause.Occur.FILTER);
|
||||
|
||||
if (boolQuery.clauses().isEmpty()) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
Queries.applyMinimumShouldMatch(boolQuery, queryBuilder.minimumNumberShouldMatch());
|
||||
return queryBuilder.adjustPureNegative() ? fixNegativeQueryIfNeeded(boolQuery) : boolQuery;
|
||||
}
|
||||
|
@ -85,7 +87,10 @@ public class BoolQueryBuilderTest extends BaseQueryTestCase<BoolQueryBuilder> {
|
|||
private static void addBooleanClauses(QueryParseContext parseContext, BooleanQuery booleanQuery, List<QueryBuilder> clauses, Occur occurs)
|
||||
throws IOException {
|
||||
for (QueryBuilder query : clauses) {
|
||||
booleanQuery.add(new BooleanClause(query.toQuery(parseContext), occurs));
|
||||
Query innerQuery = query.toQuery(parseContext);
|
||||
if (innerQuery != null) {
|
||||
booleanQuery.add(new BooleanClause(innerQuery, occurs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,4 +134,24 @@ public class BoolQueryBuilderTest extends BaseQueryTestCase<BoolQueryBuilder> {
|
|||
}
|
||||
assertValidate(booleanQuery, totalExpectedErrors);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNullMust() {
|
||||
new BoolQueryBuilder().must(null);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNullMustNot() {
|
||||
new BoolQueryBuilder().mustNot(null);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNullShould() {
|
||||
new BoolQueryBuilder().should(null);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNullFilter() {
|
||||
new BoolQueryBuilder().filter(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,6 @@ package org.elasticsearch.index.query;
|
|||
|
||||
import org.apache.lucene.queries.BoostingQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -32,9 +29,7 @@ public class BoostingQueryBuilderTest extends BaseQueryTestCase<BoostingQueryBui
|
|||
|
||||
@Override
|
||||
protected BoostingQueryBuilder doCreateTestQueryBuilder() {
|
||||
BoostingQueryBuilder query = new BoostingQueryBuilder();
|
||||
query.positive(RandomQueryBuilder.createQuery(random()));
|
||||
query.negative(RandomQueryBuilder.createQuery(random()));
|
||||
BoostingQueryBuilder query = new BoostingQueryBuilder(RandomQueryBuilder.createQuery(random()), RandomQueryBuilder.createQuery(random()));
|
||||
query.negativeBoost(2.0f / randomIntBetween(1, 20));
|
||||
return query;
|
||||
}
|
||||
|
@ -43,89 +38,30 @@ public class BoostingQueryBuilderTest extends BaseQueryTestCase<BoostingQueryBui
|
|||
protected Query doCreateExpectedQuery(BoostingQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
|
||||
Query positive = queryBuilder.positive().toQuery(context);
|
||||
Query negative = queryBuilder.negative().toQuery(context);
|
||||
if (positive == null || negative == null) {
|
||||
return null;
|
||||
}
|
||||
return new BoostingQuery(positive, negative, queryBuilder.negativeBoost());
|
||||
}
|
||||
|
||||
/**
|
||||
* test that setting a null negative/positive clause renders a parseable query
|
||||
*/
|
||||
@Test
|
||||
public void testInnerClauseNull() throws IOException {
|
||||
BoostingQueryBuilder boostingQueryBuilder = new BoostingQueryBuilder().negativeBoost(0.1f);
|
||||
if (randomBoolean()) {
|
||||
boostingQueryBuilder.positive(new MatchAllQueryBuilder());
|
||||
} else {
|
||||
boostingQueryBuilder.negative(new MatchAllQueryBuilder());
|
||||
}
|
||||
String contentString = boostingQueryBuilder.toString();
|
||||
XContentParser parser = XContentFactory.xContent(contentString).createParser(contentString);
|
||||
QueryParseContext context = createContext();
|
||||
context.reset(parser);
|
||||
assertQueryHeader(parser, boostingQueryBuilder.getName());
|
||||
QueryBuilder parsedBuilder = context.indexQueryParserService().queryParser(boostingQueryBuilder.getName()).fromXContent(context);
|
||||
assertNotNull(parsedBuilder);
|
||||
assertNotSame(parsedBuilder, boostingQueryBuilder);
|
||||
assertEquals(parsedBuilder, boostingQueryBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* tests that we signal upstream queries to ignore this query by returning <tt>null</tt>
|
||||
* if any of the inner query builder is not set
|
||||
*/
|
||||
@Test
|
||||
public void testInnerQueryBuilderNull() throws IOException {
|
||||
BoostingQueryBuilder boostingQueryBuilder = new BoostingQueryBuilder();
|
||||
if (randomBoolean()) {
|
||||
boostingQueryBuilder.positive(new MatchAllQueryBuilder()).negative(null);
|
||||
} else {
|
||||
boostingQueryBuilder.positive(null).negative(new MatchAllQueryBuilder());
|
||||
}
|
||||
assertNull(boostingQueryBuilder.toQuery(createContext()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInnerQueryBuilderReturnsNull() throws IOException {
|
||||
QueryBuilder noOpBuilder = new AbstractQueryBuilder() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "dummy";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
BoostingQueryBuilder boostingQueryBuilder;
|
||||
if (randomBoolean()) {
|
||||
boostingQueryBuilder = new BoostingQueryBuilder().positive(new MatchAllQueryBuilder()).negative(noOpBuilder);
|
||||
} else {
|
||||
boostingQueryBuilder = new BoostingQueryBuilder().positive(noOpBuilder).negative(new MatchAllQueryBuilder());
|
||||
}
|
||||
assertNull(boostingQueryBuilder.toQuery(createContext()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate() {
|
||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
|
||||
int totalExpectedErrors = 0;
|
||||
if (randomBoolean()) {
|
||||
boostingQuery.negative(RandomQueryBuilder.createInvalidQuery(random()));
|
||||
QueryBuilder positive;
|
||||
QueryBuilder negative;
|
||||
if (frequently()) {
|
||||
negative = RandomQueryBuilder.createInvalidQuery(random());
|
||||
totalExpectedErrors++;
|
||||
} else if(rarely()) {
|
||||
boostingQuery.negative(RandomQueryBuilder.createQuery(random()));
|
||||
} else {
|
||||
negative = RandomQueryBuilder.createQuery(random());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
boostingQuery.positive(RandomQueryBuilder.createInvalidQuery(random()));
|
||||
if (frequently()) {
|
||||
positive = RandomQueryBuilder.createInvalidQuery(random());
|
||||
totalExpectedErrors++;
|
||||
} else if(rarely()) {
|
||||
boostingQuery.positive(RandomQueryBuilder.createQuery(random()));
|
||||
} else {
|
||||
positive = RandomQueryBuilder.createQuery(random());
|
||||
}
|
||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positive, negative);
|
||||
if (frequently()) {
|
||||
boostingQuery.negativeBoost(0.5f);
|
||||
} else {
|
||||
|
@ -134,4 +70,13 @@ public class BoostingQueryBuilderTest extends BaseQueryTestCase<BoostingQueryBui
|
|||
}
|
||||
assertValidate(boostingQuery, totalExpectedErrors);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullConstructorArgument() {
|
||||
if (randomBoolean()) {
|
||||
new BoostingQueryBuilder(null, RandomQueryBuilder.createQuery(random()));
|
||||
} else {
|
||||
new BoostingQueryBuilder(RandomQueryBuilder.createQuery(random()), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,11 @@ public class ConstantScoreQueryBuilderTest extends BaseQueryTestCase<ConstantSco
|
|||
|
||||
@Override
|
||||
protected Query doCreateExpectedQuery(ConstantScoreQueryBuilder testBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
||||
return new ConstantScoreQuery(testBuilder.query().toQuery(context));
|
||||
Query innerQuery = testBuilder.query().toQuery(context);
|
||||
if (innerQuery != null) {
|
||||
return new ConstantScoreQuery(innerQuery);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +50,7 @@ public class ConstantScoreQueryBuilderTest extends BaseQueryTestCase<ConstantSco
|
|||
* test that missing "filter" element causes {@link QueryParsingException}
|
||||
*/
|
||||
@Test(expected=QueryParsingException.class)
|
||||
public void testNoFilterElement() throws IOException {
|
||||
public void testFilterElement() throws IOException {
|
||||
QueryParseContext context = createContext();
|
||||
String queryId = ConstantScoreQueryBuilder.PROTOTYPE.getName();
|
||||
String queryString = "{ \""+queryId+"\" : {}";
|
||||
|
@ -56,24 +60,6 @@ public class ConstantScoreQueryBuilderTest extends BaseQueryTestCase<ConstantSco
|
|||
context.indexQueryParserService().queryParser(queryId).fromXContent(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test empty "filter" element.
|
||||
* Current DSL allows inner filter element to be empty, returning a `null` inner filter builder
|
||||
*/
|
||||
@Test
|
||||
public void testEmptyFilterElement() throws IOException {
|
||||
QueryParseContext context = createContext();
|
||||
String queryId = ConstantScoreQueryBuilder.PROTOTYPE.getName();
|
||||
String queryString = "{ \""+queryId+"\" : { \"filter\" : { } }";
|
||||
XContentParser parser = XContentFactory.xContent(queryString).createParser(queryString);
|
||||
context.reset(parser);
|
||||
assertQueryHeader(parser, queryId);
|
||||
ConstantScoreQueryBuilder queryBuilder = (ConstantScoreQueryBuilder) context.indexQueryParserService()
|
||||
.queryParser(queryId).fromXContent(context);
|
||||
assertNull(queryBuilder.query());
|
||||
assertNull(queryBuilder.toQuery(createContext()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate() {
|
||||
QueryBuilder innerQuery;
|
||||
|
@ -87,4 +73,9 @@ public class ConstantScoreQueryBuilderTest extends BaseQueryTestCase<ConstantSco
|
|||
ConstantScoreQueryBuilder constantScoreQuery = new ConstantScoreQueryBuilder(innerQuery);
|
||||
assertValidate(constantScoreQuery, totalExpectedErrors);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullConstructor() {
|
||||
new ConstantScoreQueryBuilder(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,17 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class DisMaxQueryBuilderTest extends BaseQueryTestCase<DisMaxQueryBuilder> {
|
||||
|
||||
@Override
|
||||
protected Query doCreateExpectedQuery(DisMaxQueryBuilder testBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
||||
return new DisjunctionMaxQuery(AbstractQueryBuilder.toQueries(testBuilder.queries(), context), testBuilder.tieBreaker());
|
||||
Collection<Query> queries = AbstractQueryBuilder.toQueries(testBuilder.queries(), context);
|
||||
if (queries.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new DisjunctionMaxQuery(queries, testBuilder.tieBreaker());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,6 +87,11 @@ public class DisMaxQueryBuilderTest extends BaseQueryTestCase<DisMaxQueryBuilder
|
|||
assertNull(disMaxBuilder.toQuery(context));
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNull() {
|
||||
new DisMaxQueryBuilder().add(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate() {
|
||||
DisMaxQueryBuilder disMaxQuery = new DisMaxQueryBuilder();
|
||||
|
|
|
@ -32,11 +32,15 @@ public class FQueryFilterBuilderTest extends BaseQueryTestCase<FQueryFilterBuild
|
|||
|
||||
@Override
|
||||
protected Query doCreateExpectedQuery(FQueryFilterBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
||||
return new ConstantScoreQuery(queryBuilder.innerQuery().toQuery(context));
|
||||
Query query = queryBuilder.innerQuery().toQuery(context);
|
||||
if (query != null) {
|
||||
return new ConstantScoreQuery(query);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a AndQueryBuilder with random limit between 0 and 20
|
||||
* @return a FQueryFilterBuilder with random inner query
|
||||
*/
|
||||
@Override
|
||||
protected FQueryFilterBuilder doCreateTestQueryBuilder() {
|
||||
|
@ -49,7 +53,7 @@ public class FQueryFilterBuilderTest extends BaseQueryTestCase<FQueryFilterBuild
|
|||
*/
|
||||
@Test
|
||||
public void testNoInnerQuery() throws QueryParsingException, IOException {
|
||||
FQueryFilterBuilder queryFilterQuery = new FQueryFilterBuilder(null);
|
||||
FQueryFilterBuilder queryFilterQuery = new FQueryFilterBuilder(EmptyQueryBuilder.PROTOTYPE);
|
||||
assertNull(queryFilterQuery.toQuery(createContext()));
|
||||
}
|
||||
|
||||
|
@ -85,4 +89,9 @@ public class FQueryFilterBuilderTest extends BaseQueryTestCase<FQueryFilterBuild
|
|||
FQueryFilterBuilder fQueryFilter = new FQueryFilterBuilder(innerQuery);
|
||||
assertValidate(fQueryFilter, totalExpectedErrors);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullConstructo() {
|
||||
new FQueryFilterBuilder(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class FieldMaskingSpanQueryBuilderTest extends BaseQueryTestCase<FieldMas
|
|||
if (randomBoolean()) {
|
||||
fieldName = "fieldName";
|
||||
} else {
|
||||
fieldName = randomBoolean() ? "" : null;
|
||||
fieldName = "";
|
||||
totalExpectedErrors++;
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
|
@ -73,4 +73,14 @@ public class FieldMaskingSpanQueryBuilderTest extends BaseQueryTestCase<FieldMas
|
|||
FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(spanQueryBuilder, fieldName);
|
||||
assertValidate(queryBuilder, totalExpectedErrors);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullFieldName() {
|
||||
new FieldMaskingSpanQueryBuilder(new SpanTermQueryBuilder("name", "value"), null);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullInnerQuery() {
|
||||
new FieldMaskingSpanQueryBuilder(null, "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class NotQueryBuilderTest extends BaseQueryTestCase<NotQueryBuilder> {
|
|||
|
||||
@Override
|
||||
protected Query doCreateExpectedQuery(NotQueryBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
||||
if (queryBuilder.filter() == null) {
|
||||
if (queryBuilder.filter().toQuery(context) == null) {
|
||||
return null;
|
||||
}
|
||||
return Queries.not(queryBuilder.filter().toQuery(context));
|
||||
|
@ -45,25 +45,9 @@ public class NotQueryBuilderTest extends BaseQueryTestCase<NotQueryBuilder> {
|
|||
return new NotQueryBuilder(RandomQueryBuilder.createQuery(random()));
|
||||
}
|
||||
|
||||
/**
|
||||
* test corner case where no inner query exist
|
||||
*/
|
||||
@Test
|
||||
public void testNoInnerQuerry() throws QueryParsingException, IOException {
|
||||
NotQueryBuilder notQuery = new NotQueryBuilder(null);
|
||||
assertNull(notQuery.toQuery(createContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test corner case where inner queries returns null.
|
||||
* This is legal, e.g. here {@link ConstantScoreQueryBuilder} can wrap a filter
|
||||
* element that itself parses to <tt>null</tt>, e.g.
|
||||
* '{ "constant_score" : "filter {} }'
|
||||
*/
|
||||
@Test
|
||||
public void testInnerQuery() throws QueryParsingException, IOException {
|
||||
NotQueryBuilder notQuery = new NotQueryBuilder(new ConstantScoreQueryBuilder(null));
|
||||
assertNull(notQuery.toQuery(createContext()));
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNotQueryBuilderNull() {
|
||||
new NotQueryBuilder(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,6 +44,9 @@ public class OrQueryBuilderTest extends BaseQueryTestCase<OrQueryBuilder> {
|
|||
query.add(innerQuery, Occur.SHOULD);
|
||||
}
|
||||
}
|
||||
if (query.clauses().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
|
@ -94,4 +97,14 @@ public class OrQueryBuilderTest extends BaseQueryTestCase<OrQueryBuilder> {
|
|||
}
|
||||
assertValidate(orQuery, totalExpectedErrors);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNullConstructor() {
|
||||
new OrQueryBuilder(EmptyQueryBuilder.PROTOTYPE, null);
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testAddNull() {
|
||||
new OrQueryBuilder().add(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ package org.elasticsearch.index.query;
|
|||
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -32,11 +30,12 @@ public class QueryFilterBuilderTest extends BaseQueryTestCase<QueryFilterBuilder
|
|||
|
||||
@Override
|
||||
protected Query doCreateExpectedQuery(QueryFilterBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
||||
return new ConstantScoreQuery(queryBuilder.innerQuery().toQuery(context));
|
||||
Query query = queryBuilder.innerQuery().toQuery(context);
|
||||
return query != null ? new ConstantScoreQuery(query) : query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a AndQueryBuilder with random limit between 0 and 20
|
||||
* @return a QueryFilterBuilder with random inner query
|
||||
*/
|
||||
@Override
|
||||
protected QueryFilterBuilder doCreateTestQueryBuilder() {
|
||||
|
@ -44,32 +43,9 @@ public class QueryFilterBuilderTest extends BaseQueryTestCase<QueryFilterBuilder
|
|||
return new QueryFilterBuilder(innerQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* test corner case where no inner query exist
|
||||
*/
|
||||
@Test
|
||||
public void testNoInnerQuery() throws QueryParsingException, IOException {
|
||||
QueryFilterBuilder queryFilterQuery = new QueryFilterBuilder(null);
|
||||
assertNull(queryFilterQuery.toQuery(createContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* test wrapping an inner filter that returns null also returns <tt>null</null> to pass on upwards
|
||||
*/
|
||||
@Test
|
||||
public void testInnerQueryReturnsNull() throws IOException {
|
||||
QueryParseContext context = createContext();
|
||||
|
||||
// create inner filter
|
||||
String queryString = "{ \"constant_score\" : { \"filter\" : {} }";
|
||||
XContentParser parser = XContentFactory.xContent(queryString).createParser(queryString);
|
||||
context.reset(parser);
|
||||
assertQueryHeader(parser, ConstantScoreQueryBuilder.PROTOTYPE.getName());
|
||||
QueryBuilder innerQuery = context.indexQueryParserService().queryParser(ConstantScoreQueryBuilder.PROTOTYPE.getName()).fromXContent(context);
|
||||
|
||||
// check that when wrapping this filter, toQuery() returns null
|
||||
QueryFilterBuilder queryFilterQuery = new QueryFilterBuilder(innerQuery);
|
||||
assertNull(queryFilterQuery.toQuery(createContext()));
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testQueryFilterBuilderNull() {
|
||||
new QueryFilterBuilder(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -36,13 +36,15 @@ public class RandomQueryBuilder {
|
|||
* @return a random {@link QueryBuilder}
|
||||
*/
|
||||
public static QueryBuilder createQuery(Random r) {
|
||||
switch (RandomInts.randomIntBetween(r, 0, 2)) {
|
||||
switch (RandomInts.randomIntBetween(r, 0, 3)) {
|
||||
case 0:
|
||||
return new MatchAllQueryBuilderTest().createTestQueryBuilder();
|
||||
case 1:
|
||||
return new TermQueryBuilderTest().createTestQueryBuilder();
|
||||
case 2:
|
||||
return new IdsQueryBuilderTest().createTestQueryBuilder();
|
||||
case 3:
|
||||
return EmptyQueryBuilder.PROTOTYPE;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -59,7 +61,7 @@ public class RandomQueryBuilder {
|
|||
case 0:
|
||||
return new TermQueryBuilder("", "test");
|
||||
case 1:
|
||||
return new BoostingQueryBuilder().negativeBoost(-1f);
|
||||
return new BoostingQueryBuilder(new MatchAllQueryBuilder(), new MatchAllQueryBuilder()).negativeBoost(-1f);
|
||||
case 2:
|
||||
return new CommonTermsQueryBuilder("", "text");
|
||||
case 3:
|
||||
|
|
|
@ -964,7 +964,7 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
|||
@Test
|
||||
public void testBoostingQueryBuilder() throws IOException {
|
||||
IndexQueryParserService queryParser = queryParser();
|
||||
Query parsedQuery = queryParser.parse(boostingQuery().positive(termQuery("field1", "value1")).negative(termQuery("field1", "value2")).negativeBoost(0.2f)).query();
|
||||
Query parsedQuery = queryParser.parse(boostingQuery(termQuery("field1", "value1"), termQuery("field1", "value2")).negativeBoost(0.2f)).query();
|
||||
assertThat(parsedQuery, instanceOf(BoostingQuery.class));
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ import static org.elasticsearch.index.query.QueryBuilders.*;
|
|||
import static org.elasticsearch.search.builder.SearchSourceBuilder.highlight;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.elasticsearch.test.hamcrest.RegexMatcher.matches;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
|
@ -1368,7 +1367,7 @@ public class HighlighterSearchTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
logger.info("--> highlighting and searching on field1");
|
||||
SearchSourceBuilder source = searchSource()
|
||||
.query(boostingQuery().positive(termQuery("field2", "brown")).negative(termQuery("field2", "foobar")).negativeBoost(0.5f))
|
||||
.query(boostingQuery(termQuery("field2", "brown"), termQuery("field2", "foobar")).negativeBoost(0.5f))
|
||||
.highlight(highlight().field("field2").order("score").preTags("<x>").postTags("</x>"));
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test").setSource(source.buildAsBytes()).get();
|
||||
|
@ -1386,7 +1385,7 @@ public class HighlighterSearchTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
logger.info("--> highlighting and searching on field1");
|
||||
SearchSourceBuilder source = searchSource()
|
||||
.query(boostingQuery().positive(termQuery("field2", "brown")).negative(termQuery("field2", "foobar")).negativeBoost(0.5f))
|
||||
.query(boostingQuery(termQuery("field2", "brown"), termQuery("field2", "foobar")).negativeBoost(0.5f))
|
||||
.highlight(highlight().field("field2").order("score").preTags("<x>").postTags("</x>"));
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test").setSource(source.buildAsBytes()).get();
|
||||
|
@ -2300,7 +2299,7 @@ public class HighlighterSearchTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
logger.info("--> highlighting and searching on field1");
|
||||
SearchSourceBuilder source = searchSource()
|
||||
.query(boostingQuery().positive(termQuery("field2", "brown")).negative(termQuery("field2", "foobar")).negativeBoost(0.5f))
|
||||
.query(boostingQuery(termQuery("field2", "brown"), termQuery("field2", "foobar")).negativeBoost(0.5f))
|
||||
.highlight(highlight().field("field2").preTags("<x>").postTags("</x>"));
|
||||
SearchResponse searchResponse = client().search(searchRequest("test").source(source)).actionGet();
|
||||
|
||||
|
@ -2603,10 +2602,10 @@ public class HighlighterSearchTests extends ElasticsearchIntegrationTest {
|
|||
assertHighlight(response, 0, "field1", 0, 1, highlightedMatcher);
|
||||
phrase.boost(1);
|
||||
// Try with a boosting query
|
||||
response = search.setQuery(boostingQuery().positive(phrase).negative(terms).boost(boost).negativeBoost(1)).get();
|
||||
response = search.setQuery(boostingQuery(phrase, terms).boost(boost).negativeBoost(1)).get();
|
||||
assertHighlight(response, 0, "field1", 0, 1, highlightedMatcher);
|
||||
// Try with a boosting query using a negative boost
|
||||
response = search.setQuery(boostingQuery().positive(phrase).negative(terms).boost(1).negativeBoost(1/boost)).get();
|
||||
response = search.setQuery(boostingQuery(phrase, terms).boost(1).negativeBoost(1/boost)).get();
|
||||
assertHighlight(response, 0, "field1", 0, 1, highlightedMatcher);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ on the query-refactoring feature branch.
|
|||
|
||||
=== Java-API
|
||||
|
||||
==== BoostingQueryBuilder
|
||||
|
||||
Removed setters for mandatory positive/negative query. Both arguments now have
|
||||
to be supplied at construction time already and have to be non-null.
|
||||
|
||||
==== QueryFilterBuilder
|
||||
|
||||
Removed the setter `queryName(String queryName)` since this field is not supported
|
||||
|
|
Loading…
Reference in New Issue