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;
|
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) {
|
protected static QueryValidationException validateInnerQueries(List<QueryBuilder> queryBuilders, QueryValidationException initialValidationException) {
|
||||||
QueryValidationException validationException = initialValidationException;
|
QueryValidationException validationException = initialValidationException;
|
||||||
for (QueryBuilder queryBuilder : queryBuilders) {
|
for (QueryBuilder queryBuilder : queryBuilders) {
|
||||||
|
|
|
@ -98,6 +98,10 @@ public class AndQueryBuilder extends AbstractQueryBuilder<AndQueryBuilder> {
|
||||||
query.add(innerQuery, Occur.MUST);
|
query.add(innerQuery, Occur.MUST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (query.clauses().isEmpty()) {
|
||||||
|
// no inner lucene query exists, ignore upstream
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,7 @@ public class AndQueryParser extends BaseQueryParser {
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||||
queriesFound = true;
|
queriesFound = true;
|
||||||
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (filter != null) {
|
queries.add(filter);
|
||||||
queries.add(filter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
@ -69,17 +67,13 @@ public class AndQueryParser extends BaseQueryParser {
|
||||||
queriesFound = true;
|
queriesFound = true;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||||
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (filter != null) {
|
queries.add(filter);
|
||||||
queries.add(filter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
queriesFound = true;
|
queriesFound = true;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||||
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
QueryBuilder filter = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (filter != null) {
|
queries.add(filter);
|
||||||
queries.add(filter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (token.isValue()) {
|
} else if (token.isValue()) {
|
||||||
|
|
|
@ -255,16 +255,16 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||||
if (!hasClauses()) {
|
|
||||||
return new MatchAllDocsQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
BooleanQuery booleanQuery = new BooleanQuery(disableCoord);
|
BooleanQuery booleanQuery = new BooleanQuery(disableCoord);
|
||||||
addBooleanClauses(parseContext, booleanQuery, mustClauses, BooleanClause.Occur.MUST);
|
addBooleanClauses(parseContext, booleanQuery, mustClauses, BooleanClause.Occur.MUST);
|
||||||
addBooleanClauses(parseContext, booleanQuery, mustNotClauses, BooleanClause.Occur.MUST_NOT);
|
addBooleanClauses(parseContext, booleanQuery, mustNotClauses, BooleanClause.Occur.MUST_NOT);
|
||||||
addBooleanClauses(parseContext, booleanQuery, shouldClauses, BooleanClause.Occur.SHOULD);
|
addBooleanClauses(parseContext, booleanQuery, shouldClauses, BooleanClause.Occur.SHOULD);
|
||||||
addBooleanClauses(parseContext, booleanQuery, filterClauses, BooleanClause.Occur.FILTER);
|
addBooleanClauses(parseContext, booleanQuery, filterClauses, BooleanClause.Occur.FILTER);
|
||||||
|
|
||||||
|
if (booleanQuery.clauses().isEmpty()) {
|
||||||
|
return new MatchAllDocsQuery();
|
||||||
|
}
|
||||||
|
|
||||||
Queries.applyMinimumShouldMatch(booleanQuery, minimumShouldMatch);
|
Queries.applyMinimumShouldMatch(booleanQuery, minimumShouldMatch);
|
||||||
return adjustPureNegative ? fixNegativeQueryIfNeeded(booleanQuery) : booleanQuery;
|
return adjustPureNegative ? fixNegativeQueryIfNeeded(booleanQuery) : booleanQuery;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,14 +71,13 @@ public class BoolQueryParser extends BaseQueryParser {
|
||||||
switch (currentFieldName) {
|
switch (currentFieldName) {
|
||||||
case "must":
|
case "must":
|
||||||
query = parseContext.parseInnerQueryBuilder();
|
query = parseContext.parseInnerQueryBuilder();
|
||||||
if (query != null) {
|
mustClauses.add(query);
|
||||||
mustClauses.add(query);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "should":
|
case "should":
|
||||||
query = parseContext.parseInnerQueryBuilder();
|
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) {
|
if (parseContext.isFilter() && minimumShouldMatch == null) {
|
||||||
minimumShouldMatch = "1";
|
minimumShouldMatch = "1";
|
||||||
}
|
}
|
||||||
|
@ -86,16 +85,12 @@ public class BoolQueryParser extends BaseQueryParser {
|
||||||
break;
|
break;
|
||||||
case "filter":
|
case "filter":
|
||||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (query != null) {
|
filterClauses.add(query);
|
||||||
filterClauses.add(query);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "must_not":
|
case "must_not":
|
||||||
case "mustNot":
|
case "mustNot":
|
||||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (query != null) {
|
mustNotClauses.add(query);
|
||||||
mustNotClauses.add(query);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new QueryParsingException(parseContext, "[bool] query does not support [" + currentFieldName + "]");
|
throw new QueryParsingException(parseContext, "[bool] query does not support [" + currentFieldName + "]");
|
||||||
|
@ -105,14 +100,13 @@ public class BoolQueryParser extends BaseQueryParser {
|
||||||
switch (currentFieldName) {
|
switch (currentFieldName) {
|
||||||
case "must":
|
case "must":
|
||||||
query = parseContext.parseInnerQueryBuilder();
|
query = parseContext.parseInnerQueryBuilder();
|
||||||
if (query != null) {
|
mustClauses.add(query);
|
||||||
mustClauses.add(query);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "should":
|
case "should":
|
||||||
query = parseContext.parseInnerQueryBuilder();
|
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) {
|
if (parseContext.isFilter() && minimumShouldMatch == null) {
|
||||||
minimumShouldMatch = "1";
|
minimumShouldMatch = "1";
|
||||||
}
|
}
|
||||||
|
@ -120,16 +114,12 @@ public class BoolQueryParser extends BaseQueryParser {
|
||||||
break;
|
break;
|
||||||
case "filter":
|
case "filter":
|
||||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (query != null) {
|
filterClauses.add(query);
|
||||||
filterClauses.add(query);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "must_not":
|
case "must_not":
|
||||||
case "mustNot":
|
case "mustNot":
|
||||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||||
if (query != null) {
|
mustNotClauses.add(query);
|
||||||
mustNotClauses.add(query);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new QueryParsingException(parseContext, "bool query does not support [" + currentFieldName + "]");
|
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";
|
public static final String NAME = "boosting";
|
||||||
|
|
||||||
private QueryBuilder positiveQuery;
|
private final QueryBuilder positiveQuery;
|
||||||
|
|
||||||
private QueryBuilder negativeQuery;
|
private final QueryBuilder negativeQuery;
|
||||||
|
|
||||||
private float negativeBoost = -1;
|
private float negativeBoost = -1;
|
||||||
|
|
||||||
static final BoostingQueryBuilder PROTOTYPE = new BoostingQueryBuilder();
|
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) {
|
public BoostingQueryBuilder(QueryBuilder positiveQuery, QueryBuilder negativeQuery) {
|
||||||
this.positiveQuery = positiveQuery;
|
this.positiveQuery = Objects.requireNonNull(positiveQuery);
|
||||||
return this;
|
this.negativeQuery = Objects.requireNonNull(negativeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,14 +78,6 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
||||||
return this.positiveQuery;
|
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.
|
* Get the negative query for this boosting query.
|
||||||
*/
|
*/
|
||||||
|
@ -103,8 +103,10 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
||||||
@Override
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject(NAME);
|
builder.startObject(NAME);
|
||||||
doXContentInnerBuilder(builder, "positive", positiveQuery, params);
|
builder.field("positive");
|
||||||
doXContentInnerBuilder(builder, "negative", negativeQuery, params);
|
positiveQuery.toXContent(builder, params);
|
||||||
|
builder.field("negative");
|
||||||
|
negativeQuery.toXContent(builder, params);
|
||||||
builder.field("negative_boost", negativeBoost);
|
builder.field("negative_boost", negativeBoost);
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
@ -128,13 +130,10 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
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 positive = positiveQuery.toQuery(parseContext);
|
||||||
Query negative = negativeQuery.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) {
|
if (positive == null || negative == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -158,9 +157,7 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil
|
||||||
protected BoostingQueryBuilder doReadFrom(StreamInput in) throws IOException {
|
protected BoostingQueryBuilder doReadFrom(StreamInput in) throws IOException {
|
||||||
QueryBuilder positiveQuery = in.readNamedWriteable();
|
QueryBuilder positiveQuery = in.readNamedWriteable();
|
||||||
QueryBuilder negativeQuery = in.readNamedWriteable();
|
QueryBuilder negativeQuery = in.readNamedWriteable();
|
||||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
|
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positiveQuery, negativeQuery);
|
||||||
boostingQuery.positive(positiveQuery);
|
|
||||||
boostingQuery.negative(negativeQuery);
|
|
||||||
boostingQuery.negativeBoost = in.readFloat();
|
boostingQuery.negativeBoost = in.readFloat();
|
||||||
return boostingQuery;
|
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'");
|
throw new QueryParsingException(parseContext, "[boosting] query requires 'negative_boost' to be set to be a positive value'");
|
||||||
}
|
}
|
||||||
|
|
||||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
|
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positiveQuery, negativeQuery);
|
||||||
boostingQuery.positive(positiveQuery);
|
|
||||||
boostingQuery.negative(negativeQuery);
|
|
||||||
boostingQuery.negativeBoost(negativeBoost);
|
boostingQuery.negativeBoost(negativeBoost);
|
||||||
boostingQuery.boost(boost);
|
boostingQuery.boost(boost);
|
||||||
boostingQuery.queryName(queryName);
|
boostingQuery.queryName(queryName);
|
||||||
|
|
|
@ -38,7 +38,12 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
||||||
|
|
||||||
private final QueryBuilder filterBuilder;
|
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
|
* 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
|
* @param filterBuilder The query to wrap in a constant score query
|
||||||
*/
|
*/
|
||||||
public ConstantScoreQueryBuilder(QueryBuilder filterBuilder) {
|
public ConstantScoreQueryBuilder(QueryBuilder filterBuilder) {
|
||||||
this.filterBuilder = filterBuilder;
|
this.filterBuilder = Objects.requireNonNull(filterBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,24 +65,19 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor
|
||||||
@Override
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject(NAME);
|
builder.startObject(NAME);
|
||||||
doXContentInnerBuilder(builder, "filter", filterBuilder, params);
|
builder.field("filter");
|
||||||
|
filterBuilder.toXContent(builder, params);
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
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);
|
Query innerFilter = filterBuilder.toQuery(parseContext);
|
||||||
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(parseContext));
|
return new ConstantScoreQuery(filterBuilder.toQuery(parseContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,7 @@ public class DisMaxQueryParser extends BaseQueryParser {
|
||||||
if ("queries".equals(currentFieldName)) {
|
if ("queries".equals(currentFieldName)) {
|
||||||
queriesFound = true;
|
queriesFound = true;
|
||||||
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||||
if (query != null) {
|
queries.add(query);
|
||||||
queries.add(query);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new QueryParsingException(parseContext, "[dis_max] query does not support [" + currentFieldName + "]");
|
throw new QueryParsingException(parseContext, "[dis_max] query does not support [" + currentFieldName + "]");
|
||||||
}
|
}
|
||||||
|
@ -73,9 +71,7 @@ public class DisMaxQueryParser extends BaseQueryParser {
|
||||||
queriesFound = true;
|
queriesFound = true;
|
||||||
while (token != XContentParser.Token.END_ARRAY) {
|
while (token != XContentParser.Token.END_ARRAY) {
|
||||||
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||||
if (query != null) {
|
queries.add(query);
|
||||||
queries.add(query);
|
|
||||||
}
|
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
}
|
}
|
||||||
} else {
|
} 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";
|
public static final String NAME = "fquery";
|
||||||
|
|
||||||
static final FQueryFilterBuilder PROTOTYPE = new FQueryFilterBuilder(null);
|
static final FQueryFilterBuilder PROTOTYPE = new FQueryFilterBuilder();
|
||||||
|
|
||||||
private final QueryBuilder queryBuilder;
|
private final QueryBuilder queryBuilder;
|
||||||
|
|
||||||
|
@ -49,7 +49,11 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
||||||
* @param queryBuilder The query to wrap as a filter
|
* @param queryBuilder The query to wrap as a filter
|
||||||
*/
|
*/
|
||||||
public FQueryFilterBuilder(QueryBuilder queryBuilder) {
|
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
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject(FQueryFilterBuilder.NAME);
|
builder.startObject(FQueryFilterBuilder.NAME);
|
||||||
doXContentInnerBuilder(builder, "query", queryBuilder, params);
|
builder.field("query");
|
||||||
|
queryBuilder.toXContent(builder, params);
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
@ -70,9 +75,6 @@ public class FQueryFilterBuilder extends AbstractQueryBuilder<FQueryFilterBuilde
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||||
// inner query builder can potentially be `null`, in that case we ignore it
|
// 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);
|
Query innerQuery = this.queryBuilder.toQuery(parseContext);
|
||||||
if (innerQuery == null) {
|
if (innerQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -76,9 +76,6 @@ public class FQueryFilterParser extends BaseQueryParser {
|
||||||
if (!queryFound) {
|
if (!queryFound) {
|
||||||
throw new QueryParsingException(parseContext, "[fquery] requires 'query' element");
|
throw new QueryParsingException(parseContext, "[fquery] requires 'query' element");
|
||||||
}
|
}
|
||||||
if (wrappedQuery == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
FQueryFilterBuilder queryBuilder = new FQueryFilterBuilder(wrappedQuery);
|
FQueryFilterBuilder queryBuilder = new FQueryFilterBuilder(wrappedQuery);
|
||||||
queryBuilder.queryName(queryName);
|
queryBuilder.queryName(queryName);
|
||||||
queryBuilder.boost(boost);
|
queryBuilder.boost(boost);
|
||||||
|
|
|
@ -40,6 +40,7 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
||||||
|
|
||||||
static final FieldMaskingSpanQueryBuilder PROTOTYPE = new FieldMaskingSpanQueryBuilder();
|
static final FieldMaskingSpanQueryBuilder PROTOTYPE = new FieldMaskingSpanQueryBuilder();
|
||||||
|
|
||||||
|
// only used for prototype
|
||||||
private FieldMaskingSpanQueryBuilder() {
|
private FieldMaskingSpanQueryBuilder() {
|
||||||
this.queryBuilder = null;
|
this.queryBuilder = null;
|
||||||
this.fieldName = null;
|
this.fieldName = null;
|
||||||
|
@ -53,7 +54,7 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
||||||
*/
|
*/
|
||||||
public FieldMaskingSpanQueryBuilder(SpanQueryBuilder queryBuilder, String fieldName) {
|
public FieldMaskingSpanQueryBuilder(SpanQueryBuilder queryBuilder, String fieldName) {
|
||||||
this.queryBuilder = Objects.requireNonNull(queryBuilder);
|
this.queryBuilder = Objects.requireNonNull(queryBuilder);
|
||||||
this.fieldName = fieldName;
|
this.fieldName = Objects.requireNonNull(fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +74,8 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
||||||
@Override
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject(NAME);
|
builder.startObject(NAME);
|
||||||
doXContentInnerBuilder(builder, "query", queryBuilder, params);
|
builder.field("query");
|
||||||
|
queryBuilder.toXContent(builder, params);
|
||||||
builder.field("field", fieldName);
|
builder.field("field", fieldName);
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
|
@ -37,10 +37,14 @@ public class NotQueryBuilder extends AbstractQueryBuilder<NotQueryBuilder> {
|
||||||
|
|
||||||
private final QueryBuilder filter;
|
private final QueryBuilder filter;
|
||||||
|
|
||||||
static final NotQueryBuilder PROTOTYPE = new NotQueryBuilder(null);
|
static final NotQueryBuilder PROTOTYPE = new NotQueryBuilder();
|
||||||
|
|
||||||
public NotQueryBuilder(QueryBuilder filter) {
|
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
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject(NAME);
|
builder.startObject(NAME);
|
||||||
doXContentInnerBuilder(builder, "query", filter, params);
|
builder.field("query");
|
||||||
|
filter.toXContent(builder, params);
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||||
if (filter == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Query luceneQuery = filter.toQuery(parseContext);
|
Query luceneQuery = filter.toQuery(parseContext);
|
||||||
if (luceneQuery == null) {
|
if (luceneQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -95,6 +95,10 @@ public class OrQueryBuilder extends AbstractQueryBuilder<OrQueryBuilder> {
|
||||||
query.add(innerQuery, Occur.SHOULD);
|
query.add(innerQuery, Occur.SHOULD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (query.clauses().isEmpty()) {
|
||||||
|
// no inner lucene query exists, ignore upstream
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,8 +277,8 @@ public abstract class QueryBuilders {
|
||||||
* Unlike the "NOT" clause, this still selects documents that contain undesirable terms,
|
* Unlike the "NOT" clause, this still selects documents that contain undesirable terms,
|
||||||
* but reduces their overall score:
|
* but reduces their overall score:
|
||||||
*/
|
*/
|
||||||
public static BoostingQueryBuilder boostingQuery() {
|
public static BoostingQueryBuilder boostingQuery(QueryBuilder positiveQuery, QueryBuilder negativeQuery) {
|
||||||
return new BoostingQueryBuilder();
|
return new BoostingQueryBuilder(positiveQuery, negativeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class QueryFilterBuilder extends AbstractQueryBuilder<QueryFilterBuilder>
|
||||||
|
|
||||||
private final QueryBuilder queryBuilder;
|
private final QueryBuilder queryBuilder;
|
||||||
|
|
||||||
static final QueryFilterBuilder PROTOTYPE = new QueryFilterBuilder(null);
|
static final QueryFilterBuilder PROTOTYPE = new QueryFilterBuilder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter that simply wraps a query.
|
* 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
|
* @param queryBuilder The query to wrap as a filter
|
||||||
*/
|
*/
|
||||||
public QueryFilterBuilder(QueryBuilder queryBuilder) {
|
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
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
doXContentInnerBuilder(builder, NAME, queryBuilder, params);
|
builder.field(NAME);
|
||||||
|
queryBuilder.toXContent(builder, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||||
// inner query builder can potentially be `null`, in that case we ignore it
|
// 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);
|
Query innerQuery = this.queryBuilder.toQuery(parseContext);
|
||||||
if (innerQuery == null) {
|
if (innerQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -232,7 +232,7 @@ public class QueryParseContext {
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
if (token == XContentParser.Token.END_OBJECT) {
|
if (token == XContentParser.Token.END_OBJECT) {
|
||||||
// empty query
|
// empty query
|
||||||
return null;
|
return EmptyQueryBuilder.PROTOTYPE;
|
||||||
}
|
}
|
||||||
if (token != XContentParser.Token.FIELD_NAME) {
|
if (token != XContentParser.Token.FIELD_NAME) {
|
||||||
throw new QueryParsingException(this, "[_na] query malformed, no field after start_object");
|
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.inject.Inject;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.query.EmptyQueryBuilder;
|
||||||
import org.elasticsearch.index.query.QueryParser;
|
import org.elasticsearch.index.query.QueryParser;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -45,6 +46,9 @@ public class IndicesQueriesRegistry extends AbstractComponent {
|
||||||
}
|
}
|
||||||
namedWriteableRegistry.registerPrototype(queryParser.getBuilderPrototype());
|
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);
|
this.queryParsers = ImmutableMap.copyOf(queryParsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,9 @@ public class AndQueryBuilderTest extends BaseQueryTestCase<AndQueryBuilder> {
|
||||||
query.add(innerQuery, Occur.MUST);
|
query.add(innerQuery, Occur.MUST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (query.clauses().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +81,16 @@ public class AndQueryBuilderTest extends BaseQueryTestCase<AndQueryBuilder> {
|
||||||
context.indexQueryParserService().queryParser(AndQueryBuilder.PROTOTYPE.getName()).fromXContent(context);
|
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
|
@Test
|
||||||
public void testValidate() {
|
public void testValidate() {
|
||||||
AndQueryBuilder andQuery = new AndQueryBuilder();
|
AndQueryBuilder andQuery = new AndQueryBuilder();
|
||||||
|
|
|
@ -234,14 +234,22 @@ public abstract class BaseQueryTestCase<QB extends AbstractQueryBuilder<QB>> ext
|
||||||
|
|
||||||
Query expectedQuery = createExpectedQuery(testQuery, context);
|
Query expectedQuery = createExpectedQuery(testQuery, context);
|
||||||
Query actualQuery = testQuery.toQuery(context);
|
Query actualQuery = testQuery.toQuery(context);
|
||||||
assertThat(actualQuery, instanceOf(expectedQuery.getClass()));
|
// expectedQuery can be null, e.g. in case of BoostingQueryBuilder
|
||||||
assertThat(actualQuery, equalTo(expectedQuery));
|
// with inner clause that returns null itself
|
||||||
assertLuceneQuery(testQuery, actualQuery, context);
|
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 {
|
protected final Query createExpectedQuery(QB queryBuilder, QueryParseContext context) throws IOException {
|
||||||
Query expectedQuery = doCreateExpectedQuery(queryBuilder, context);
|
Query expectedQuery = doCreateExpectedQuery(queryBuilder, context);
|
||||||
expectedQuery.setBoost(queryBuilder.boost());
|
if (expectedQuery != null) {
|
||||||
|
expectedQuery.setBoost(queryBuilder.boost());
|
||||||
|
}
|
||||||
return expectedQuery;
|
return expectedQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,12 +72,14 @@ public class BoolQueryBuilderTest extends BaseQueryTestCase<BoolQueryBuilder> {
|
||||||
}
|
}
|
||||||
|
|
||||||
BooleanQuery boolQuery = new BooleanQuery(queryBuilder.disableCoord());
|
BooleanQuery boolQuery = new BooleanQuery(queryBuilder.disableCoord());
|
||||||
boolQuery.setBoost(queryBuilder.boost());
|
|
||||||
addBooleanClauses(context, boolQuery, queryBuilder.must(), BooleanClause.Occur.MUST);
|
addBooleanClauses(context, boolQuery, queryBuilder.must(), BooleanClause.Occur.MUST);
|
||||||
addBooleanClauses(context, boolQuery, queryBuilder.mustNot(), BooleanClause.Occur.MUST_NOT);
|
addBooleanClauses(context, boolQuery, queryBuilder.mustNot(), BooleanClause.Occur.MUST_NOT);
|
||||||
addBooleanClauses(context, boolQuery, queryBuilder.should(), BooleanClause.Occur.SHOULD);
|
addBooleanClauses(context, boolQuery, queryBuilder.should(), BooleanClause.Occur.SHOULD);
|
||||||
addBooleanClauses(context, boolQuery, queryBuilder.filter(), BooleanClause.Occur.FILTER);
|
addBooleanClauses(context, boolQuery, queryBuilder.filter(), BooleanClause.Occur.FILTER);
|
||||||
|
|
||||||
|
if (boolQuery.clauses().isEmpty()) {
|
||||||
|
return new MatchAllDocsQuery();
|
||||||
|
}
|
||||||
Queries.applyMinimumShouldMatch(boolQuery, queryBuilder.minimumNumberShouldMatch());
|
Queries.applyMinimumShouldMatch(boolQuery, queryBuilder.minimumNumberShouldMatch());
|
||||||
return queryBuilder.adjustPureNegative() ? fixNegativeQueryIfNeeded(boolQuery) : boolQuery;
|
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)
|
private static void addBooleanClauses(QueryParseContext parseContext, BooleanQuery booleanQuery, List<QueryBuilder> clauses, Occur occurs)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
for (QueryBuilder query : clauses) {
|
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);
|
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.queries.BoostingQuery;
|
||||||
import org.apache.lucene.search.Query;
|
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 org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -32,9 +29,7 @@ public class BoostingQueryBuilderTest extends BaseQueryTestCase<BoostingQueryBui
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BoostingQueryBuilder doCreateTestQueryBuilder() {
|
protected BoostingQueryBuilder doCreateTestQueryBuilder() {
|
||||||
BoostingQueryBuilder query = new BoostingQueryBuilder();
|
BoostingQueryBuilder query = new BoostingQueryBuilder(RandomQueryBuilder.createQuery(random()), RandomQueryBuilder.createQuery(random()));
|
||||||
query.positive(RandomQueryBuilder.createQuery(random()));
|
|
||||||
query.negative(RandomQueryBuilder.createQuery(random()));
|
|
||||||
query.negativeBoost(2.0f / randomIntBetween(1, 20));
|
query.negativeBoost(2.0f / randomIntBetween(1, 20));
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
@ -43,89 +38,30 @@ public class BoostingQueryBuilderTest extends BaseQueryTestCase<BoostingQueryBui
|
||||||
protected Query doCreateExpectedQuery(BoostingQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
|
protected Query doCreateExpectedQuery(BoostingQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
|
||||||
Query positive = queryBuilder.positive().toQuery(context);
|
Query positive = queryBuilder.positive().toQuery(context);
|
||||||
Query negative = queryBuilder.negative().toQuery(context);
|
Query negative = queryBuilder.negative().toQuery(context);
|
||||||
|
if (positive == null || negative == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return new BoostingQuery(positive, negative, queryBuilder.negativeBoost());
|
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
|
@Test
|
||||||
public void testValidate() {
|
public void testValidate() {
|
||||||
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
|
|
||||||
int totalExpectedErrors = 0;
|
int totalExpectedErrors = 0;
|
||||||
if (randomBoolean()) {
|
QueryBuilder positive;
|
||||||
boostingQuery.negative(RandomQueryBuilder.createInvalidQuery(random()));
|
QueryBuilder negative;
|
||||||
|
if (frequently()) {
|
||||||
|
negative = RandomQueryBuilder.createInvalidQuery(random());
|
||||||
totalExpectedErrors++;
|
totalExpectedErrors++;
|
||||||
} else if(rarely()) {
|
} else {
|
||||||
boostingQuery.negative(RandomQueryBuilder.createQuery(random()));
|
negative = RandomQueryBuilder.createQuery(random());
|
||||||
}
|
}
|
||||||
if (randomBoolean()) {
|
if (frequently()) {
|
||||||
boostingQuery.positive(RandomQueryBuilder.createInvalidQuery(random()));
|
positive = RandomQueryBuilder.createInvalidQuery(random());
|
||||||
totalExpectedErrors++;
|
totalExpectedErrors++;
|
||||||
} else if(rarely()) {
|
} else {
|
||||||
boostingQuery.positive(RandomQueryBuilder.createQuery(random()));
|
positive = RandomQueryBuilder.createQuery(random());
|
||||||
}
|
}
|
||||||
|
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positive, negative);
|
||||||
if (frequently()) {
|
if (frequently()) {
|
||||||
boostingQuery.negativeBoost(0.5f);
|
boostingQuery.negativeBoost(0.5f);
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,4 +70,13 @@ public class BoostingQueryBuilderTest extends BaseQueryTestCase<BoostingQueryBui
|
||||||
}
|
}
|
||||||
assertValidate(boostingQuery, totalExpectedErrors);
|
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
|
@Override
|
||||||
protected Query doCreateExpectedQuery(ConstantScoreQueryBuilder testBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
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 that missing "filter" element causes {@link QueryParsingException}
|
||||||
*/
|
*/
|
||||||
@Test(expected=QueryParsingException.class)
|
@Test(expected=QueryParsingException.class)
|
||||||
public void testNoFilterElement() throws IOException {
|
public void testFilterElement() throws IOException {
|
||||||
QueryParseContext context = createContext();
|
QueryParseContext context = createContext();
|
||||||
String queryId = ConstantScoreQueryBuilder.PROTOTYPE.getName();
|
String queryId = ConstantScoreQueryBuilder.PROTOTYPE.getName();
|
||||||
String queryString = "{ \""+queryId+"\" : {}";
|
String queryString = "{ \""+queryId+"\" : {}";
|
||||||
|
@ -56,24 +60,6 @@ public class ConstantScoreQueryBuilderTest extends BaseQueryTestCase<ConstantSco
|
||||||
context.indexQueryParserService().queryParser(queryId).fromXContent(context);
|
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
|
@Test
|
||||||
public void testValidate() {
|
public void testValidate() {
|
||||||
QueryBuilder innerQuery;
|
QueryBuilder innerQuery;
|
||||||
|
@ -87,4 +73,9 @@ public class ConstantScoreQueryBuilderTest extends BaseQueryTestCase<ConstantSco
|
||||||
ConstantScoreQueryBuilder constantScoreQuery = new ConstantScoreQueryBuilder(innerQuery);
|
ConstantScoreQueryBuilder constantScoreQuery = new ConstantScoreQueryBuilder(innerQuery);
|
||||||
assertValidate(constantScoreQuery, totalExpectedErrors);
|
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 org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
public class DisMaxQueryBuilderTest extends BaseQueryTestCase<DisMaxQueryBuilder> {
|
public class DisMaxQueryBuilderTest extends BaseQueryTestCase<DisMaxQueryBuilder> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doCreateExpectedQuery(DisMaxQueryBuilder testBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
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));
|
assertNull(disMaxBuilder.toQuery(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=NullPointerException.class)
|
||||||
|
public void testAddNull() {
|
||||||
|
new DisMaxQueryBuilder().add(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidate() {
|
public void testValidate() {
|
||||||
DisMaxQueryBuilder disMaxQuery = new DisMaxQueryBuilder();
|
DisMaxQueryBuilder disMaxQuery = new DisMaxQueryBuilder();
|
||||||
|
|
|
@ -32,11 +32,15 @@ public class FQueryFilterBuilderTest extends BaseQueryTestCase<FQueryFilterBuild
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doCreateExpectedQuery(FQueryFilterBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
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
|
@Override
|
||||||
protected FQueryFilterBuilder doCreateTestQueryBuilder() {
|
protected FQueryFilterBuilder doCreateTestQueryBuilder() {
|
||||||
|
@ -49,7 +53,7 @@ public class FQueryFilterBuilderTest extends BaseQueryTestCase<FQueryFilterBuild
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testNoInnerQuery() throws QueryParsingException, IOException {
|
public void testNoInnerQuery() throws QueryParsingException, IOException {
|
||||||
FQueryFilterBuilder queryFilterQuery = new FQueryFilterBuilder(null);
|
FQueryFilterBuilder queryFilterQuery = new FQueryFilterBuilder(EmptyQueryBuilder.PROTOTYPE);
|
||||||
assertNull(queryFilterQuery.toQuery(createContext()));
|
assertNull(queryFilterQuery.toQuery(createContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,4 +89,9 @@ public class FQueryFilterBuilderTest extends BaseQueryTestCase<FQueryFilterBuild
|
||||||
FQueryFilterBuilder fQueryFilter = new FQueryFilterBuilder(innerQuery);
|
FQueryFilterBuilder fQueryFilter = new FQueryFilterBuilder(innerQuery);
|
||||||
assertValidate(fQueryFilter, totalExpectedErrors);
|
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()) {
|
if (randomBoolean()) {
|
||||||
fieldName = "fieldName";
|
fieldName = "fieldName";
|
||||||
} else {
|
} else {
|
||||||
fieldName = randomBoolean() ? "" : null;
|
fieldName = "";
|
||||||
totalExpectedErrors++;
|
totalExpectedErrors++;
|
||||||
}
|
}
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
|
@ -73,4 +73,14 @@ public class FieldMaskingSpanQueryBuilderTest extends BaseQueryTestCase<FieldMas
|
||||||
FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(spanQueryBuilder, fieldName);
|
FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(spanQueryBuilder, fieldName);
|
||||||
assertValidate(queryBuilder, totalExpectedErrors);
|
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
|
@Override
|
||||||
protected Query doCreateExpectedQuery(NotQueryBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
protected Query doCreateExpectedQuery(NotQueryBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
||||||
if (queryBuilder.filter() == null) {
|
if (queryBuilder.filter().toQuery(context) == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Queries.not(queryBuilder.filter().toQuery(context));
|
return Queries.not(queryBuilder.filter().toQuery(context));
|
||||||
|
@ -45,25 +45,9 @@ public class NotQueryBuilderTest extends BaseQueryTestCase<NotQueryBuilder> {
|
||||||
return new NotQueryBuilder(RandomQueryBuilder.createQuery(random()));
|
return new NotQueryBuilder(RandomQueryBuilder.createQuery(random()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Test(expected=NullPointerException.class)
|
||||||
* test corner case where no inner query exist
|
public void testNotQueryBuilderNull() {
|
||||||
*/
|
new NotQueryBuilder(null);
|
||||||
@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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -44,6 +44,9 @@ public class OrQueryBuilderTest extends BaseQueryTestCase<OrQueryBuilder> {
|
||||||
query.add(innerQuery, Occur.SHOULD);
|
query.add(innerQuery, Occur.SHOULD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (query.clauses().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,4 +97,14 @@ public class OrQueryBuilderTest extends BaseQueryTestCase<OrQueryBuilder> {
|
||||||
}
|
}
|
||||||
assertValidate(orQuery, totalExpectedErrors);
|
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.ConstantScoreQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -32,11 +30,12 @@ public class QueryFilterBuilderTest extends BaseQueryTestCase<QueryFilterBuilder
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query doCreateExpectedQuery(QueryFilterBuilder queryBuilder, QueryParseContext context) throws QueryParsingException, IOException {
|
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
|
@Override
|
||||||
protected QueryFilterBuilder doCreateTestQueryBuilder() {
|
protected QueryFilterBuilder doCreateTestQueryBuilder() {
|
||||||
|
@ -44,32 +43,9 @@ public class QueryFilterBuilderTest extends BaseQueryTestCase<QueryFilterBuilder
|
||||||
return new QueryFilterBuilder(innerQuery);
|
return new QueryFilterBuilder(innerQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Test(expected=NullPointerException.class)
|
||||||
* test corner case where no inner query exist
|
public void testQueryFilterBuilderNull() {
|
||||||
*/
|
new QueryFilterBuilder(null);
|
||||||
@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
|
@Test
|
||||||
|
|
|
@ -36,13 +36,15 @@ public class RandomQueryBuilder {
|
||||||
* @return a random {@link QueryBuilder}
|
* @return a random {@link QueryBuilder}
|
||||||
*/
|
*/
|
||||||
public static QueryBuilder createQuery(Random r) {
|
public static QueryBuilder createQuery(Random r) {
|
||||||
switch (RandomInts.randomIntBetween(r, 0, 2)) {
|
switch (RandomInts.randomIntBetween(r, 0, 3)) {
|
||||||
case 0:
|
case 0:
|
||||||
return new MatchAllQueryBuilderTest().createTestQueryBuilder();
|
return new MatchAllQueryBuilderTest().createTestQueryBuilder();
|
||||||
case 1:
|
case 1:
|
||||||
return new TermQueryBuilderTest().createTestQueryBuilder();
|
return new TermQueryBuilderTest().createTestQueryBuilder();
|
||||||
case 2:
|
case 2:
|
||||||
return new IdsQueryBuilderTest().createTestQueryBuilder();
|
return new IdsQueryBuilderTest().createTestQueryBuilder();
|
||||||
|
case 3:
|
||||||
|
return EmptyQueryBuilder.PROTOTYPE;
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
@ -59,7 +61,7 @@ public class RandomQueryBuilder {
|
||||||
case 0:
|
case 0:
|
||||||
return new TermQueryBuilder("", "test");
|
return new TermQueryBuilder("", "test");
|
||||||
case 1:
|
case 1:
|
||||||
return new BoostingQueryBuilder().negativeBoost(-1f);
|
return new BoostingQueryBuilder(new MatchAllQueryBuilder(), new MatchAllQueryBuilder()).negativeBoost(-1f);
|
||||||
case 2:
|
case 2:
|
||||||
return new CommonTermsQueryBuilder("", "text");
|
return new CommonTermsQueryBuilder("", "text");
|
||||||
case 3:
|
case 3:
|
||||||
|
|
|
@ -964,7 +964,7 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||||
@Test
|
@Test
|
||||||
public void testBoostingQueryBuilder() throws IOException {
|
public void testBoostingQueryBuilder() throws IOException {
|
||||||
IndexQueryParserService queryParser = queryParser();
|
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));
|
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.highlight;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
|
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.elasticsearch.test.hamcrest.RegexMatcher.matches;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
@ -1368,7 +1367,7 @@ public class HighlighterSearchTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
logger.info("--> highlighting and searching on field1");
|
logger.info("--> highlighting and searching on field1");
|
||||||
SearchSourceBuilder source = searchSource()
|
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>"));
|
.highlight(highlight().field("field2").order("score").preTags("<x>").postTags("</x>"));
|
||||||
|
|
||||||
SearchResponse searchResponse = client().prepareSearch("test").setSource(source.buildAsBytes()).get();
|
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");
|
logger.info("--> highlighting and searching on field1");
|
||||||
SearchSourceBuilder source = searchSource()
|
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>"));
|
.highlight(highlight().field("field2").order("score").preTags("<x>").postTags("</x>"));
|
||||||
|
|
||||||
SearchResponse searchResponse = client().prepareSearch("test").setSource(source.buildAsBytes()).get();
|
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");
|
logger.info("--> highlighting and searching on field1");
|
||||||
SearchSourceBuilder source = searchSource()
|
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>"));
|
.highlight(highlight().field("field2").preTags("<x>").postTags("</x>"));
|
||||||
SearchResponse searchResponse = client().search(searchRequest("test").source(source)).actionGet();
|
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);
|
assertHighlight(response, 0, "field1", 0, 1, highlightedMatcher);
|
||||||
phrase.boost(1);
|
phrase.boost(1);
|
||||||
// Try with a boosting query
|
// 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);
|
assertHighlight(response, 0, "field1", 0, 1, highlightedMatcher);
|
||||||
// Try with a boosting query using a negative boost
|
// 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);
|
assertHighlight(response, 0, "field1", 0, 1, highlightedMatcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ on the query-refactoring feature branch.
|
||||||
|
|
||||||
=== Java-API
|
=== 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
|
==== QueryFilterBuilder
|
||||||
|
|
||||||
Removed the setter `queryName(String queryName)` since this field is not supported
|
Removed the setter `queryName(String queryName)` since this field is not supported
|
||||||
|
|
Loading…
Reference in New Issue