Skip to content

Commit 33668a8

Browse files
committed
Merge pull request #11621 from cbuescher/feature/query-refactoring-boostingquery
Query refactoring: BoostingQueryBuilder and Parser
2 parents 22cf442 + 6202118 commit 33668a8

File tree

4 files changed

+265
-32
lines changed

4 files changed

+265
-32
lines changed

core/src/main/java/org/elasticsearch/index/query/BoostingQueryBuilder.java

Lines changed: 117 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@
1919

2020
package org.elasticsearch.index.query;
2121

22+
import org.apache.lucene.search.Query;
23+
import org.apache.lucene.queries.BoostingQuery;
24+
import org.elasticsearch.common.io.stream.StreamInput;
25+
import org.elasticsearch.common.io.stream.StreamOutput;
2226
import org.elasticsearch.common.xcontent.XContentBuilder;
2327

2428
import java.io.IOException;
29+
import java.util.Objects;
2530

2631
/**
2732
* The BoostingQuery class can be used to effectively demote results that match a given query.
@@ -35,7 +40,7 @@
3540
* multiplied by the supplied "boost" parameter, so this should be less than 1 to achieve a
3641
* demoting effect
3742
*/
38-
public class BoostingQueryBuilder extends QueryBuilder implements BoostableQueryBuilder<BoostingQueryBuilder> {
43+
public class BoostingQueryBuilder extends QueryBuilder<BoostingQueryBuilder> implements BoostableQueryBuilder<BoostingQueryBuilder> {
3944

4045
public static final String NAME = "boosting";
4146

@@ -45,34 +50,74 @@ public class BoostingQueryBuilder extends QueryBuilder implements BoostableQuery
4550

4651
private float negativeBoost = -1;
4752

48-
private float boost = -1;
53+
private float boost = 1.0f;
4954

5055
static final BoostingQueryBuilder PROTOTYPE = new BoostingQueryBuilder();
5156

5257
public BoostingQueryBuilder() {
5358
}
5459

60+
/**
61+
* Add the positive query for this boosting query.
62+
*/
5563
public BoostingQueryBuilder positive(QueryBuilder positiveQuery) {
5664
this.positiveQuery = positiveQuery;
5765
return this;
5866
}
5967

68+
/**
69+
* Get the positive query for this boosting query.
70+
*/
71+
public QueryBuilder positive() {
72+
return this.positiveQuery;
73+
}
74+
75+
/**
76+
* Add the negative query for this boosting query.
77+
*/
6078
public BoostingQueryBuilder negative(QueryBuilder negativeQuery) {
6179
this.negativeQuery = negativeQuery;
6280
return this;
6381
}
6482

83+
/**
84+
* Get the negative query for this boosting query.
85+
*/
86+
public QueryBuilder negative() {
87+
return this.negativeQuery;
88+
}
89+
90+
/**
91+
* Set the negative boost factor.
92+
*/
6593
public BoostingQueryBuilder negativeBoost(float negativeBoost) {
6694
this.negativeBoost = negativeBoost;
6795
return this;
6896
}
6997

98+
/**
99+
* Get the negative boost factor.
100+
*/
101+
public float negativeBoost() {
102+
return this.negativeBoost;
103+
}
104+
105+
/**
106+
* Set the boost factor.
107+
*/
70108
@Override
71109
public BoostingQueryBuilder boost(float boost) {
72110
this.boost = boost;
73111
return this;
74112
}
75113

114+
/**
115+
* Get the boost factor.
116+
*/
117+
public float boost() {
118+
return this.boost;
119+
}
120+
76121
@Override
77122
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
78123
if (positiveQuery == null) {
@@ -81,25 +126,87 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
81126
if (negativeQuery == null) {
82127
throw new IllegalArgumentException("boosting query requires negative query to be set");
83128
}
84-
if (negativeBoost == -1) {
85-
throw new IllegalArgumentException("boosting query requires negativeBoost to be set");
86-
}
87129
builder.startObject(NAME);
88130
builder.field("positive");
89131
positiveQuery.toXContent(builder, params);
90132
builder.field("negative");
91133
negativeQuery.toXContent(builder, params);
92-
93134
builder.field("negative_boost", negativeBoost);
94-
95-
if (boost != -1) {
96-
builder.field("boost", boost);
97-
}
135+
builder.field("boost", boost);
98136
builder.endObject();
99137
}
100138

139+
@Override
140+
public QueryValidationException validate() {
141+
QueryValidationException validationException = null;
142+
if (negativeBoost < 0) {
143+
validationException = QueryValidationException
144+
.addValidationError("[boosting] query requires negativeBoost to be set to positive value", validationException);
145+
}
146+
return validationException;
147+
};
148+
101149
@Override
102150
public String queryId() {
103151
return NAME;
104152
}
153+
154+
@Override
155+
public Query toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException {
156+
157+
// make upstream queries ignore this query by returning `null`
158+
// if either inner query builder is null or returns null-Query
159+
if (positiveQuery == null || negativeQuery == null) {
160+
return null;
161+
}
162+
Query positive = positiveQuery.toQuery(parseContext);
163+
Query negative = negativeQuery.toQuery(parseContext);
164+
if (positive == null || negative == null) {
165+
return null;
166+
}
167+
168+
BoostingQuery boostingQuery = new BoostingQuery(positive, negative, negativeBoost);
169+
boostingQuery.setBoost(boost);
170+
return boostingQuery;
171+
}
172+
173+
@Override
174+
public int hashCode() {
175+
return Objects.hash(this.boost, this.negativeBoost, this.positiveQuery, this.negativeQuery);
176+
}
177+
178+
@Override
179+
public boolean equals(Object obj) {
180+
if (this == obj) {
181+
return true;
182+
}
183+
if (obj == null || getClass() != obj.getClass()) {
184+
return false;
185+
}
186+
BoostingQueryBuilder other = (BoostingQueryBuilder) obj;
187+
return Objects.equals(this.boost, other.boost) &&
188+
Objects.equals(this.negativeBoost, other.negativeBoost) &&
189+
Objects.equals(this.positiveQuery, other.positiveQuery) &&
190+
Objects.equals(this.negativeQuery, other.negativeQuery);
191+
}
192+
193+
@Override
194+
public BoostingQueryBuilder readFrom(StreamInput in) throws IOException {
195+
QueryBuilder positiveQuery = in.readNamedWriteable();
196+
QueryBuilder negativeQuery = in.readNamedWriteable();
197+
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
198+
boostingQuery.positive(positiveQuery);
199+
boostingQuery.negative(negativeQuery);
200+
boostingQuery.boost = in.readFloat();
201+
boostingQuery.negativeBoost = in.readFloat();
202+
return boostingQuery;
203+
}
204+
205+
@Override
206+
public void writeTo(StreamOutput out) throws IOException {
207+
out.writeNamedWriteable(this.positiveQuery);
208+
out.writeNamedWriteable(this.negativeQuery);
209+
out.writeFloat(this.boost);
210+
out.writeFloat(this.negativeBoost);
211+
}
105212
}

core/src/main/java/org/elasticsearch/index/query/BoostingQueryParser.java

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
package org.elasticsearch.index.query;
2121

22-
import org.apache.lucene.queries.BoostingQuery;
23-
import org.apache.lucene.search.Query;
2422
import org.elasticsearch.common.inject.Inject;
2523
import org.elasticsearch.common.xcontent.XContentParser;
2624

@@ -29,7 +27,7 @@
2927
/**
3028
*
3129
*/
32-
public class BoostingQueryParser extends BaseQueryParserTemp {
30+
public class BoostingQueryParser extends BaseQueryParser {
3331

3432
@Inject
3533
public BoostingQueryParser() {
@@ -41,14 +39,14 @@ public String[] names() {
4139
}
4240

4341
@Override
44-
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
42+
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
4543
XContentParser parser = parseContext.parser();
4644

47-
Query positiveQuery = null;
45+
QueryBuilder positiveQuery = null;
4846
boolean positiveQueryFound = false;
49-
Query negativeQuery = null;
47+
QueryBuilder negativeQuery = null;
5048
boolean negativeQueryFound = false;
51-
float boost = -1;
49+
float boost = 1.0f;
5250
float negativeBoost = -1;
5351

5452
String currentFieldName = null;
@@ -58,10 +56,10 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
5856
currentFieldName = parser.currentName();
5957
} else if (token == XContentParser.Token.START_OBJECT) {
6058
if ("positive".equals(currentFieldName)) {
61-
positiveQuery = parseContext.parseInnerQuery();
59+
positiveQuery = parseContext.parseInnerQueryBuilder();
6260
positiveQueryFound = true;
6361
} else if ("negative".equals(currentFieldName)) {
64-
negativeQuery = parseContext.parseInnerQuery();
62+
negativeQuery = parseContext.parseInnerQueryBuilder();
6563
negativeQueryFound = true;
6664
} else {
6765
throw new QueryParsingException(parseContext, "[boosting] query does not support [" + currentFieldName + "]");
@@ -83,19 +81,16 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
8381
if (negativeQuery == null && !negativeQueryFound) {
8482
throw new QueryParsingException(parseContext, "[boosting] query requires 'negative' query to be set'");
8583
}
86-
if (negativeBoost == -1) {
87-
throw new QueryParsingException(parseContext, "[boosting] query requires 'negative_boost' to be set'");
84+
if (negativeBoost < 0) {
85+
throw new QueryParsingException(parseContext, "[boosting] query requires 'negative_boost' to be set to be a positive value'");
8886
}
8987

90-
// parsers returned null
91-
if (positiveQuery == null || negativeQuery == null) {
92-
return null;
93-
}
94-
95-
BoostingQuery boostingQuery = new BoostingQuery(positiveQuery, negativeQuery, negativeBoost);
96-
if (boost != -1) {
97-
boostingQuery.setBoost(boost);
98-
}
88+
BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder();
89+
boostingQuery.positive(positiveQuery);
90+
boostingQuery.negative(negativeQuery);
91+
boostingQuery.negativeBoost(negativeBoost);
92+
boostingQuery.boost(boost);
93+
boostingQuery.validate();
9994
return boostingQuery;
10095
}
10196

core/src/main/java/org/elasticsearch/index/query/QueryBuilder.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ public final String getName() {
6060
}
6161

6262
/**
63-
* Converts this QueryBuilder to a lucene {@link Query}
63+
* Converts this QueryBuilder to a lucene {@link Query}.
64+
* Returns <tt>null</tt> if this query should be ignored in the context of
65+
* parent queries.
66+
*
6467
* @param parseContext additional information needed to construct the queries
65-
* @return the {@link Query}
68+
* @return the {@link Query} or <tt>null</tt> if this query should be ignored upstream
6669
* @throws QueryParsingException
6770
* @throws IOException
6871
*/

0 commit comments

Comments
 (0)