Refactors BoolQueryBuilder and Parser. Splits the parse(QueryParseContext ctx) method into a parsing
and a query building part, adding NamedWriteable implementation for serialization and hashCode(), equals() for testing. This change also adds tests using fixed set of leaf queries (Terms, Ids, MatchAll) as nested Queries in test query setup. Also QueryParseContext is adapted to return QueryBuilder instances for inner filter parses instead of previously returning Query instances, keeping old methods in place but deprecating them. Relates to #10217 Closes #11427
This commit is contained in:
parent
22c5205e67
commit
458d62e4a0
|
@ -509,6 +509,20 @@ public abstract class StreamInput extends InputStream {
|
|||
return namedWriteable.readFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a list of {@link NamedWriteable} from the current stream, by first reading its size and then
|
||||
* reading the individual objects using {@link #readNamedWriteable()}.
|
||||
*/
|
||||
public <C> List<C> readNamedWritableList() throws IOException {
|
||||
List<C> list = new ArrayList<>();
|
||||
int size = readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
C obj = readNamedWriteable();
|
||||
list.add(obj);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static StreamInput wrap(BytesReference reference) {
|
||||
if (reference.hasArray() == false) {
|
||||
reference = reference.toBytesArray();
|
||||
|
|
|
@ -457,4 +457,15 @@ public abstract class StreamOutput extends OutputStream {
|
|||
writeString(namedWriteable.getName());
|
||||
namedWriteable.writeTo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a list of {@link NamedWriteable} to the current stream, by first writing its size and then iterating over the objects
|
||||
* in the list
|
||||
*/
|
||||
public void writeNamedWritableList(List<? extends NamedWriteable> list) throws IOException {
|
||||
writeInt(list.size());
|
||||
for (NamedWriteable obj : list) {
|
||||
writeNamedWriteable(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,20 +19,36 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.lucene.search.Queries.fixNegativeQueryIfNeeded;
|
||||
|
||||
/**
|
||||
* A Query that matches documents matching boolean combinations of other queries.
|
||||
*/
|
||||
public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuilder<BoolQueryBuilder> {
|
||||
public class BoolQueryBuilder extends QueryBuilder<BoolQueryBuilder> implements BoostableQueryBuilder<BoolQueryBuilder> {
|
||||
|
||||
public static final String NAME = "bool";
|
||||
|
||||
static final boolean ADJUST_PURE_NEGATIVE_DEFAULT = true;
|
||||
|
||||
static final boolean DISABLE_COORD_DEFAULT = false;
|
||||
|
||||
static final BoolQueryBuilder PROTOTYPE = new BoolQueryBuilder();
|
||||
|
||||
private final List<QueryBuilder> mustClauses = new ArrayList<>();
|
||||
|
||||
private final List<QueryBuilder> mustNotClauses = new ArrayList<>();
|
||||
|
@ -41,18 +57,16 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
|
||||
private final List<QueryBuilder> shouldClauses = new ArrayList<>();
|
||||
|
||||
private float boost = -1;
|
||||
private float boost = 1.0f;
|
||||
|
||||
private Boolean disableCoord;
|
||||
private boolean disableCoord = DISABLE_COORD_DEFAULT;
|
||||
|
||||
private boolean adjustPureNegative = ADJUST_PURE_NEGATIVE_DEFAULT;
|
||||
|
||||
private String minimumShouldMatch;
|
||||
|
||||
private Boolean adjustPureNegative;
|
||||
|
||||
private String queryName;
|
||||
|
||||
static final BoolQueryBuilder PROTOTYPE = new BoolQueryBuilder();
|
||||
|
||||
/**
|
||||
* Adds a query that <b>must</b> appear in the matching documents and will
|
||||
* contribute to scoring.
|
||||
|
@ -62,6 +76,22 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of queries that <b>must</b> appear in the matching documents and will
|
||||
* contribute to scoring.
|
||||
*/
|
||||
public BoolQueryBuilder must(List<QueryBuilder> queryBuilders) {
|
||||
mustClauses.addAll(queryBuilders);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queries that <b>must</b> appear in the matching documents.
|
||||
*/
|
||||
public List<QueryBuilder> must() {
|
||||
return this.mustClauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a query that <b>must</b> appear in the matching documents but will
|
||||
* not contribute to scoring.
|
||||
|
@ -72,8 +102,23 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a query that <b>must not</b> appear in the matching documents and
|
||||
* will not contribute to scoring.
|
||||
* Adds a list of queries that <b>must</b> appear in the matching documents but will
|
||||
* not contribute to scoring.
|
||||
*/
|
||||
public BoolQueryBuilder filter(List<QueryBuilder> queryBuilders) {
|
||||
filterClauses.addAll(queryBuilders);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queries that <b>must</b> appear in the matching documents but don't conntribute to scoring
|
||||
*/
|
||||
public List<QueryBuilder> filter() {
|
||||
return this.filterClauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a query that <b>must not</b> appear in the matching documents.
|
||||
*/
|
||||
public BoolQueryBuilder mustNot(QueryBuilder queryBuilder) {
|
||||
mustNotClauses.add(queryBuilder);
|
||||
|
@ -81,7 +126,22 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a query that <i>should</i> appear in the matching documents. For a boolean query with no
|
||||
* Adds a list of queries that <b>must not</b> appear in the matching documents.
|
||||
*/
|
||||
public BoolQueryBuilder mustNot(List<QueryBuilder> queryBuilders) {
|
||||
mustNotClauses.addAll(queryBuilders);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queries that <b>must not</b> appear in the matching documents.
|
||||
*/
|
||||
public List<QueryBuilder> mustNot() {
|
||||
return this.mustNotClauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a clause that <i>should</i> be matched by the returned documents. For a boolean query with no
|
||||
* <tt>MUST</tt> clauses one or more <code>SHOULD</code> clauses must match a document
|
||||
* for the BooleanQuery to match.
|
||||
*
|
||||
|
@ -92,6 +152,28 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of clauses that <i>should</i> be matched by the returned documents. For a boolean query with no
|
||||
* <tt>MUST</tt> clauses one or more <code>SHOULD</code> clauses must match a document
|
||||
* for the BooleanQuery to match.
|
||||
*
|
||||
* @see #minimumNumberShouldMatch(int)
|
||||
*/
|
||||
public BoolQueryBuilder should(List<QueryBuilder> queryBuilders) {
|
||||
shouldClauses.addAll(queryBuilders);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of clauses that <b>should</b> be matched by the returned documents.
|
||||
*
|
||||
* @see #should(QueryBuilder)
|
||||
* @see #minimumNumberShouldMatch(int)
|
||||
*/
|
||||
public List<QueryBuilder> should() {
|
||||
return this.shouldClauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the boost for this query. Documents matching this query will (in addition to the normal
|
||||
* weightings) have their score multiplied by the boost provided.
|
||||
|
@ -102,6 +184,13 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boost for this query.
|
||||
*/
|
||||
public float boost() {
|
||||
return this.boost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables <tt>Similarity#coord(int,int)</tt> in scoring. Defaults to <tt>false</tt>.
|
||||
*/
|
||||
|
@ -110,6 +199,13 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the <tt>Similarity#coord(int,int)</tt> in scoring are disabled. Defaults to <tt>false</tt>.
|
||||
*/
|
||||
public boolean disableCoord() {
|
||||
return this.disableCoord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a minimum number of the optional (should) boolean clauses which must be satisfied.
|
||||
* <p/>
|
||||
|
@ -128,6 +224,23 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies a minimum number of the optional (should) boolean clauses which must be satisfied.
|
||||
* @see BoolQueryBuilder#minimumNumberShouldMatch(int)
|
||||
*/
|
||||
public BoolQueryBuilder minimumNumberShouldMatch(String minimumNumberShouldMatch) {
|
||||
this.minimumShouldMatch = minimumNumberShouldMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the string representation of the minimumShouldMatch settings for this query
|
||||
*/
|
||||
public String minimumNumberShouldMatch() {
|
||||
return this.minimumShouldMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum should match using the special syntax (for example, supporting percentage).
|
||||
*/
|
||||
|
@ -154,6 +267,13 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the setting for the adjust_pure_negative setting in this query
|
||||
*/
|
||||
public boolean adjustPureNegative() {
|
||||
return this.adjustPureNegative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query name for the filter that can be used when searching for matched_filters per hit.
|
||||
*/
|
||||
|
@ -162,6 +282,13 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the query name for the filter that can be used when searching for matched_filters per hit.
|
||||
*/
|
||||
public String queryName() {
|
||||
return this.queryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(NAME);
|
||||
|
@ -169,25 +296,19 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
doXArrayContent("filter", filterClauses, builder, params);
|
||||
doXArrayContent("must_not", mustNotClauses, builder, params);
|
||||
doXArrayContent("should", shouldClauses, builder, params);
|
||||
if (boost != -1) {
|
||||
builder.field("boost", boost);
|
||||
}
|
||||
if (disableCoord != null) {
|
||||
builder.field("disable_coord", disableCoord);
|
||||
}
|
||||
builder.field("boost", boost);
|
||||
builder.field("disable_coord", disableCoord);
|
||||
builder.field("adjust_pure_negative", adjustPureNegative);
|
||||
if (minimumShouldMatch != null) {
|
||||
builder.field("minimum_should_match", minimumShouldMatch);
|
||||
}
|
||||
if (adjustPureNegative != null) {
|
||||
builder.field("adjust_pure_negative", adjustPureNegative);
|
||||
}
|
||||
if (queryName != null) {
|
||||
builder.field("_name", queryName);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
private void doXArrayContent(String field, List<QueryBuilder> clauses, XContentBuilder builder, Params params) throws IOException {
|
||||
private static void doXArrayContent(String field, List<QueryBuilder> clauses, XContentBuilder builder, Params params) throws IOException {
|
||||
if (clauses.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -207,4 +328,100 @@ public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuil
|
|||
public String queryId() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException {
|
||||
if (!hasClauses()) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
BooleanQuery booleanQuery = new BooleanQuery(this.disableCoord);
|
||||
addBooleanClauses(parseContext, booleanQuery, this.mustClauses, BooleanClause.Occur.MUST);
|
||||
addBooleanClauses(parseContext, booleanQuery, this.mustNotClauses, BooleanClause.Occur.MUST_NOT);
|
||||
addBooleanClauses(parseContext, booleanQuery, this.shouldClauses, BooleanClause.Occur.SHOULD);
|
||||
addBooleanClauses(parseContext, booleanQuery, this.filterClauses, BooleanClause.Occur.FILTER);
|
||||
|
||||
booleanQuery.setBoost(this.boost);
|
||||
Queries.applyMinimumShouldMatch(booleanQuery, this.minimumShouldMatch);
|
||||
Query query = this.adjustPureNegative ? fixNegativeQueryIfNeeded(booleanQuery) : booleanQuery;
|
||||
if (this.queryName != null) {
|
||||
parseContext.addNamedQuery(this.queryName, query);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryValidationException validate() {
|
||||
// nothing to validate, clauses are optional, see hasClauses(), other parameters have defaults
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addBooleanClauses(QueryParseContext parseContext, BooleanQuery booleanQuery, List<QueryBuilder> clauses, Occur occurs)
|
||||
throws IOException {
|
||||
for (QueryBuilder query : clauses) {
|
||||
Query luceneQuery = query.toQuery(parseContext);
|
||||
if (luceneQuery != null) {
|
||||
booleanQuery.add(new BooleanClause(luceneQuery, occurs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(boost, adjustPureNegative, disableCoord,
|
||||
minimumShouldMatch, queryName, mustClauses, shouldClauses, mustNotClauses, filterClauses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
BoolQueryBuilder other = (BoolQueryBuilder) obj;
|
||||
return Objects.equals(boost, other.boost) &&
|
||||
Objects.equals(adjustPureNegative, other.adjustPureNegative) &&
|
||||
Objects.equals(disableCoord, other.disableCoord) &&
|
||||
Objects.equals(minimumShouldMatch, other.minimumShouldMatch) &&
|
||||
Objects.equals(queryName, other.queryName) &&
|
||||
Objects.equals(mustClauses, other.mustClauses) &&
|
||||
Objects.equals(shouldClauses, other.shouldClauses) &&
|
||||
Objects.equals(mustNotClauses, other.mustNotClauses) &&
|
||||
Objects.equals(filterClauses, other.filterClauses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolQueryBuilder readFrom(StreamInput in) throws IOException {
|
||||
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
|
||||
List<QueryBuilder> queryBuilders = in.readNamedWritableList();
|
||||
boolQueryBuilder.must(queryBuilders);
|
||||
queryBuilders = in.readNamedWritableList();
|
||||
boolQueryBuilder.mustNot(queryBuilders);
|
||||
queryBuilders = in.readNamedWritableList();
|
||||
boolQueryBuilder.should(queryBuilders);
|
||||
queryBuilders = in.readNamedWritableList();
|
||||
boolQueryBuilder.filter(queryBuilders);
|
||||
boolQueryBuilder.boost = in.readFloat();
|
||||
boolQueryBuilder.adjustPureNegative = in.readBoolean();
|
||||
boolQueryBuilder.disableCoord = in.readBoolean();
|
||||
boolQueryBuilder.queryName = in.readOptionalString();
|
||||
boolQueryBuilder.minimumShouldMatch = in.readOptionalString();
|
||||
return boolQueryBuilder;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeNamedWritableList(this.mustClauses);
|
||||
out.writeNamedWritableList(this.mustNotClauses);
|
||||
out.writeNamedWritableList(this.shouldClauses);
|
||||
out.writeNamedWritableList(this.filterClauses);
|
||||
out.writeFloat(this.boost);
|
||||
out.writeBoolean(this.adjustPureNegative);
|
||||
out.writeBoolean(this.disableCoord);
|
||||
out.writeOptionalString(queryName);
|
||||
out.writeOptionalString(this.minimumShouldMatch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,8 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
|
@ -32,12 +28,11 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static org.elasticsearch.common.lucene.search.Queries.fixNegativeQueryIfNeeded;
|
||||
|
||||
/**
|
||||
*
|
||||
* Parser for the {@link BoolQueryBuilder}
|
||||
*/
|
||||
public class BoolQueryParser extends BaseQueryParserTemp {
|
||||
public class BoolQueryParser extends BaseQueryParser {
|
||||
|
||||
@Inject
|
||||
public BoolQueryParser(Settings settings) {
|
||||
|
@ -50,19 +45,23 @@ public class BoolQueryParser extends BaseQueryParserTemp {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
boolean disableCoord = false;
|
||||
boolean disableCoord = BoolQueryBuilder.DISABLE_COORD_DEFAULT;
|
||||
boolean adjustPureNegative = BoolQueryBuilder.ADJUST_PURE_NEGATIVE_DEFAULT;
|
||||
float boost = 1.0f;
|
||||
String minimumShouldMatch = null;
|
||||
|
||||
List<BooleanClause> clauses = newArrayList();
|
||||
boolean adjustPureNegative = true;
|
||||
List<QueryBuilder> mustClauses = newArrayList();
|
||||
List<QueryBuilder> mustNotClauses = newArrayList();
|
||||
List<QueryBuilder> shouldClauses = newArrayList();
|
||||
List<QueryBuilder> filterClauses = newArrayList();
|
||||
String queryName = null;
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
QueryBuilder query;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
|
@ -71,31 +70,31 @@ public class BoolQueryParser extends BaseQueryParserTemp {
|
|||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
switch (currentFieldName) {
|
||||
case "must":
|
||||
Query query = parseContext.parseInnerQuery();
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.MUST));
|
||||
mustClauses.add(query);
|
||||
}
|
||||
break;
|
||||
case "should":
|
||||
query = parseContext.parseInnerQuery();
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.SHOULD));
|
||||
shouldClauses.add(query);
|
||||
if (parseContext.isFilter() && minimumShouldMatch == null) {
|
||||
minimumShouldMatch = "1";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "filter":
|
||||
query = parseContext.parseInnerFilter();
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.FILTER));
|
||||
filterClauses.add(query);
|
||||
}
|
||||
break;
|
||||
case "must_not":
|
||||
case "mustNot":
|
||||
query = parseContext.parseInnerFilter();
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.MUST_NOT));
|
||||
mustNotClauses.add(query);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -105,31 +104,31 @@ public class BoolQueryParser extends BaseQueryParserTemp {
|
|||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
switch (currentFieldName) {
|
||||
case "must":
|
||||
Query query = parseContext.parseInnerQuery();
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.MUST));
|
||||
mustClauses.add(query);
|
||||
}
|
||||
break;
|
||||
case "should":
|
||||
query = parseContext.parseInnerQuery();
|
||||
query = parseContext.parseInnerQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.SHOULD));
|
||||
shouldClauses.add(query);
|
||||
if (parseContext.isFilter() && minimumShouldMatch == null) {
|
||||
minimumShouldMatch = "1";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "filter":
|
||||
query = parseContext.parseInnerFilter();
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.FILTER));
|
||||
filterClauses.add(query);
|
||||
}
|
||||
break;
|
||||
case "must_not":
|
||||
case "mustNot":
|
||||
query = parseContext.parseInnerFilter();
|
||||
query = parseContext.parseInnerFilterToQueryBuilder();
|
||||
if (query != null) {
|
||||
clauses.add(new BooleanClause(query, BooleanClause.Occur.MUST_NOT));
|
||||
mustNotClauses.add(query);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -154,22 +153,18 @@ public class BoolQueryParser extends BaseQueryParserTemp {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clauses.isEmpty()) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
BooleanQuery booleanQuery = new BooleanQuery(disableCoord);
|
||||
for (BooleanClause clause : clauses) {
|
||||
booleanQuery.add(clause);
|
||||
}
|
||||
booleanQuery.setBoost(boost);
|
||||
Queries.applyMinimumShouldMatch(booleanQuery, minimumShouldMatch);
|
||||
Query query = adjustPureNegative ? fixNegativeQueryIfNeeded(booleanQuery) : booleanQuery;
|
||||
if (queryName != null) {
|
||||
parseContext.addNamedQuery(queryName, query);
|
||||
}
|
||||
return query;
|
||||
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
|
||||
boolQuery.must(mustClauses);
|
||||
boolQuery.mustNot(mustNotClauses);
|
||||
boolQuery.should(shouldClauses);
|
||||
boolQuery.filter(filterClauses);
|
||||
boolQuery.boost(boost);
|
||||
boolQuery.disableCoord(disableCoord);
|
||||
boolQuery.adjustPureNegative(adjustPureNegative);
|
||||
boolQuery.minimumNumberShouldMatch(minimumShouldMatch);
|
||||
boolQuery.queryName(queryName);
|
||||
boolQuery.validate();
|
||||
return boolQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -267,18 +267,37 @@ public class QueryParseContext {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated replaced by calls to parseInnerFilterToQueryBuilder() for the resulting queries
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public Query parseInnerFilter() throws QueryParsingException, IOException {
|
||||
QueryBuilder builder = parseInnerFilterToQueryBuilder();
|
||||
Query result = null;
|
||||
if (builder != null) {
|
||||
result = builder.toQuery(this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws QueryParsingException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Nullable
|
||||
public QueryBuilder parseInnerFilterToQueryBuilder() throws QueryParsingException, IOException {
|
||||
final boolean originalIsFilter = isFilter;
|
||||
try {
|
||||
isFilter = true;
|
||||
return parseInnerQuery();
|
||||
return parseInnerQueryBuilder();
|
||||
} finally {
|
||||
isFilter = originalIsFilter;
|
||||
}
|
||||
}
|
||||
|
||||
public Query parseInnerFilter(String queryName) throws IOException, QueryParsingException {
|
||||
public QueryBuilder parseInnerFilterToQueryBuilder(String queryName) throws IOException, QueryParsingException {
|
||||
final boolean originalIsFilter = isFilter;
|
||||
try {
|
||||
isFilter = true;
|
||||
|
@ -286,12 +305,22 @@ public class QueryParseContext {
|
|||
if (queryParser == null) {
|
||||
throw new QueryParsingException(this, "No query registered for [" + queryName + "]");
|
||||
}
|
||||
return queryParser.parse(this);
|
||||
return queryParser.fromXContent(this);
|
||||
} finally {
|
||||
isFilter = originalIsFilter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated replaced by calls to parseInnerFilterToQueryBuilder(String queryName) for the resulting queries
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public Query parseInnerFilter(String queryName) throws IOException, QueryParsingException {
|
||||
QueryBuilder builder = parseInnerFilterToQueryBuilder(queryName);
|
||||
return (builder != null) ? builder.toQuery(this) : null;
|
||||
}
|
||||
|
||||
public Collection<String> simpleMatchToIndexNames(String pattern) {
|
||||
return indexQueryParser.mapperService.simpleMatchToIndexNames(pattern, getTypes());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.elasticsearch.common.lucene.search.Queries.fixNegativeQueryIfNeeded;
|
||||
|
||||
public class BoolQueryBuilderTest extends BaseQueryTestCase<BoolQueryBuilder> {
|
||||
|
||||
@Override
|
||||
protected void assertLuceneQuery(BoolQueryBuilder queryBuilder, Query query, QueryParseContext context) {
|
||||
if (queryBuilder.queryName() != null) {
|
||||
Query namedQuery = context.copyNamedFilters().get(queryBuilder.queryName());
|
||||
if (queryBuilder.hasClauses()) {
|
||||
assertThat(namedQuery, equalTo(query));
|
||||
} else {
|
||||
assertNull(namedQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BoolQueryBuilder createTestQueryBuilder() {
|
||||
BoolQueryBuilder query = new BoolQueryBuilder();
|
||||
if (randomBoolean()) {
|
||||
query.boost(2.0f / randomIntBetween(1, 20));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
query.adjustPureNegative(randomBoolean());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
query.disableCoord(randomBoolean());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
query.minimumNumberShouldMatch(randomIntBetween(1, 10));
|
||||
}
|
||||
int mustClauses = randomIntBetween(0, 3);
|
||||
for (int i = 0; i < mustClauses; i++) {
|
||||
query.must(RandomQueryBuilder.create(random()));
|
||||
}
|
||||
int mustNotClauses = randomIntBetween(0, 3);
|
||||
for (int i = 0; i < mustNotClauses; i++) {
|
||||
query.mustNot(RandomQueryBuilder.create(random()));
|
||||
}
|
||||
int shouldClauses = randomIntBetween(0, 3);
|
||||
for (int i = 0; i < shouldClauses; i++) {
|
||||
query.should(RandomQueryBuilder.create(random()));
|
||||
}
|
||||
int filterClauses = randomIntBetween(0, 3);
|
||||
for (int i = 0; i < filterClauses; i++) {
|
||||
query.filter(RandomQueryBuilder.create(random()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
query.queryName(randomUnicodeOfLengthBetween(3, 15));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BoolQueryBuilder createEmptyQueryBuilder() {
|
||||
return new BoolQueryBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query createExpectedQuery(BoolQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
|
||||
if (!queryBuilder.hasClauses()) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Queries.applyMinimumShouldMatch(boolQuery, queryBuilder.minimumNumberShouldMatch());
|
||||
Query returnedQuery = queryBuilder.adjustPureNegative() ? fixNegativeQueryIfNeeded(boolQuery) : boolQuery;
|
||||
return returnedQuery;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 com.carrotsearch.randomizedtesting.generators.RandomInts;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Utility class for creating random QueryBuilders.
|
||||
* So far only leaf queries like {@link MatchAllQueryBuilder}, {@link TermQueryBuilder} or
|
||||
* {@link IdsQueryBuilder} are returned.
|
||||
*/
|
||||
public class RandomQueryBuilder {
|
||||
|
||||
/**
|
||||
* @param r random seed
|
||||
* @return a random {@link QueryBuilder}
|
||||
*/
|
||||
public static QueryBuilder create(Random r) {
|
||||
QueryBuilder query = null;
|
||||
switch (RandomInts.randomIntBetween(r, 0, 2)) {
|
||||
case 0:
|
||||
return new MatchAllQueryBuilderTest().createTestQueryBuilder();
|
||||
case 1:
|
||||
return new TermQueryBuilderTest().createTestQueryBuilder();
|
||||
case 2:
|
||||
return new IdsQueryBuilderTest().createTestQueryBuilder();
|
||||
}
|
||||
return query;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue