Query: boosting query, closes #683.
This commit is contained in:
parent
65197ba39d
commit
1b5cdb181a
|
@ -225,6 +225,7 @@ public class IndexQueryParserModule extends AbstractModule {
|
|||
bindings.processXContentQueryParser(DisMaxQueryParser.NAME, DisMaxQueryParser.class);
|
||||
bindings.processXContentQueryParser(MatchAllQueryParser.NAME, MatchAllQueryParser.class);
|
||||
bindings.processXContentQueryParser(QueryStringQueryParser.NAME, QueryStringQueryParser.class);
|
||||
bindings.processXContentQueryParser(BoostingQueryParser.NAME, BoostingQueryParser.class);
|
||||
bindings.processXContentQueryParser(BoolQueryParser.NAME, BoolQueryParser.class);
|
||||
bindings.processXContentQueryParser(TermQueryParser.NAME, TermQueryParser.class);
|
||||
bindings.processXContentQueryParser(TermsQueryParser.NAME, TermsQueryParser.class);
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search 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.xcontent;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilderException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The BoostingQuery class can be used to effectively demote results that match a given query.
|
||||
* Unlike the "NOT" clause, this still selects documents that contain undesirable terms,
|
||||
* but reduces their overall score:
|
||||
*
|
||||
* Query balancedQuery = new BoostingQuery(positiveQuery, negativeQuery, 0.01f);
|
||||
* In this scenario the positiveQuery contains the mandatory, desirable criteria which is used to
|
||||
* select all matching documents, and the negativeQuery contains the undesirable elements which
|
||||
* are simply used to lessen the scores. Documents that match the negativeQuery have their score
|
||||
* multiplied by the supplied "boost" parameter, so this should be less than 1 to achieve a
|
||||
* demoting effect
|
||||
*/
|
||||
public class BoostingQueryBuilder extends BaseQueryBuilder {
|
||||
|
||||
private XContentQueryBuilder positiveQuery;
|
||||
|
||||
private XContentQueryBuilder negativeQuery;
|
||||
|
||||
private float negativeBoost = -1;
|
||||
|
||||
private float boost = -1;
|
||||
|
||||
public BoostingQueryBuilder() {
|
||||
|
||||
}
|
||||
|
||||
public BoostingQueryBuilder positive(XContentQueryBuilder positiveQuery) {
|
||||
this.positiveQuery = positiveQuery;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BoostingQueryBuilder negative(XContentQueryBuilder negativeQuery) {
|
||||
this.negativeQuery = negativeQuery;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BoostingQueryBuilder negativeBoost(float negativeBoost) {
|
||||
this.negativeBoost = negativeBoost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BoostingQueryBuilder boost(float boost) {
|
||||
this.boost = boost;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (positiveQuery == null) {
|
||||
throw new QueryBuilderException("boosting query requires positive query to be set");
|
||||
}
|
||||
if (negativeQuery == null) {
|
||||
throw new QueryBuilderException("boosting query requires negative query to be set");
|
||||
}
|
||||
if (negativeBoost == -1) {
|
||||
throw new QueryBuilderException("boosting query requires negativeBoost to be set");
|
||||
}
|
||||
builder.startObject(BoostingQueryParser.NAME);
|
||||
builder.field("positive");
|
||||
positiveQuery.toXContent(builder, params);
|
||||
builder.field("negative");
|
||||
negativeQuery.toXContent(builder, params);
|
||||
|
||||
builder.field("negative_boost", negativeBoost);
|
||||
|
||||
if (boost != -1) {
|
||||
builder.field("boost", boost);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search 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.xcontent;
|
||||
|
||||
import org.apache.lucene.search.BoostingQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.AbstractIndexComponent;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.query.QueryParsingException;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class BoostingQueryParser extends AbstractIndexComponent implements XContentQueryParser {
|
||||
|
||||
public static final String NAME = "boosting";
|
||||
|
||||
@Inject public BoostingQueryParser(Index index, @IndexSettings Settings settings) {
|
||||
super(index, settings);
|
||||
}
|
||||
|
||||
@Override public String[] names() {
|
||||
return new String[]{NAME};
|
||||
}
|
||||
|
||||
@Override public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
Query positiveQuery = null;
|
||||
Query negativeQuery = null;
|
||||
float boost = -1;
|
||||
float negativeBoost = -1;
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if ("positive".equals(currentFieldName)) {
|
||||
positiveQuery = parseContext.parseInnerQuery();
|
||||
} else if ("negative".equals(currentFieldName)) {
|
||||
negativeQuery = parseContext.parseInnerQuery();
|
||||
}
|
||||
} else if (token.isValue()) {
|
||||
if ("negative_boost".equals(currentFieldName) || "negativeBoost".equals(currentFieldName)) {
|
||||
negativeBoost = parser.floatValue();
|
||||
} else if ("boost".equals(currentFieldName)) {
|
||||
boost = parser.floatValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (positiveQuery == null) {
|
||||
throw new QueryParsingException(index, "[boosting] query requires 'positive' query to be set'");
|
||||
}
|
||||
if (negativeQuery == null) {
|
||||
throw new QueryParsingException(index, "[boosting] query requires 'negative' query to be set'");
|
||||
}
|
||||
if (negativeBoost == -1) {
|
||||
throw new QueryParsingException(index, "[boosting] query requires 'negative_boost' to be set'");
|
||||
}
|
||||
|
||||
BoostingQuery boostingQuery = new BoostingQuery(positiveQuery, negativeQuery, negativeBoost);
|
||||
if (boost != -1) {
|
||||
boostingQuery.setBoost(boost);
|
||||
}
|
||||
return boostingQuery;
|
||||
}
|
||||
}
|
|
@ -252,6 +252,15 @@ public abstract class QueryBuilders {
|
|||
return new QueryStringQueryBuilder(queryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* The BoostingQuery class can be used to effectively demote results that match a given query.
|
||||
* Unlike the "NOT" clause, this still selects documents that contain undesirable terms,
|
||||
* but reduces their overall score:
|
||||
*/
|
||||
public static BoostingQueryBuilder boostingQuery() {
|
||||
return new BoostingQueryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* A Query that matches documents matching boolean combinations of other queries.
|
||||
*/
|
||||
|
|
|
@ -713,6 +713,19 @@ public class SimpleIndexQueryParserTests {
|
|||
assertThat(((TermFilter) notFilter.filter()).getTerm(), equalTo(new Term("name.first", "shay1")));
|
||||
}
|
||||
|
||||
@Test public void testBoostingQueryBuilder() throws IOException {
|
||||
IndexQueryParser queryParser = queryParser();
|
||||
Query parsedQuery = queryParser.parse(boostingQuery().positive(termQuery("field1", "value1")).negative(termQuery("field1", "value2")).negativeBoost(0.2f)).query();
|
||||
assertThat(parsedQuery, instanceOf(BoostingQuery.class));
|
||||
}
|
||||
|
||||
@Test public void testBoostingQuery() throws IOException {
|
||||
IndexQueryParser queryParser = queryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/boosting-query.json");
|
||||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(BoostingQuery.class));
|
||||
}
|
||||
|
||||
@Test public void testBoolQueryBuilder() throws IOException {
|
||||
IndexQueryParser queryParser = queryParser();
|
||||
Query parsedQuery = queryParser.parse(boolQuery().must(termQuery("content", "test1")).must(termQuery("content", "test4")).mustNot(termQuery("content", "test2")).should(termQuery("content", "test3"))).query();
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"boosting" : {
|
||||
"positive" : {
|
||||
"term" : {
|
||||
"field1" : "value1"
|
||||
}
|
||||
},
|
||||
"negative" : {
|
||||
"term" : {
|
||||
"field2" : "value2"
|
||||
}
|
||||
},
|
||||
"negative_boost" : 0.2
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue