- Fixed boosting per field with multi_match query.

This commit is contained in:
Martijn van Groningen 2012-09-12 11:06:58 +02:00
parent fbd352b448
commit b6a9bd9a31
3 changed files with 42 additions and 22 deletions

View File

@ -63,8 +63,7 @@ public class MultiMatchQueryParser implements QueryParser {
MatchQuery.Type type = MatchQuery.Type.BOOLEAN;
MultiMatchQuery multiMatchQuery = new MultiMatchQuery(parseContext);
String minimumShouldMatch = null;
List<String> fieldNames = Lists.newArrayList();
Map<String, Float> fieldNameToBoost = Maps.newHashMap();
Map<String, Float> fieldNameWithBoosts = Maps.newHashMap();
XContentParser.Token token;
String currentFieldName = null;
@ -75,7 +74,7 @@ public class MultiMatchQueryParser implements QueryParser {
if ("fields".equals(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String fField = null;
float fBoost = -1;
Float fBoost = null;
char[] fieldText = parser.textCharacters();
int end = parser.textOffset() + parser.textLength();
for (int i = parser.textOffset(); i < end; i++) {
@ -92,16 +91,10 @@ public class MultiMatchQueryParser implements QueryParser {
if (Regex.isSimpleMatchPattern(fField)) {
for (String field : parseContext.mapperService().simpleMatchToIndexNames(fField)) {
fieldNames.add(field);
if (fBoost != -1) {
fieldNameToBoost.put(field, fBoost);
}
fieldNameWithBoosts.put(field, fBoost);
}
} else {
fieldNames.add(fField);
if (fBoost != -1) {
fieldNameToBoost.put(fField, fBoost);
}
fieldNameWithBoosts.put(fField, fBoost);
}
}
} else {
@ -166,11 +159,11 @@ public class MultiMatchQueryParser implements QueryParser {
throw new QueryParsingException(parseContext.index(), "No text specified for match_all query");
}
if (fieldNames.isEmpty()) {
if (fieldNameWithBoosts.isEmpty()) {
throw new QueryParsingException(parseContext.index(), "No fields specified for match_all query");
}
Query query = multiMatchQuery.parse(type, fieldNames, text);
Query query = multiMatchQuery.parse(type, fieldNameWithBoosts, text);
if (query == null) {
return null;
}

View File

@ -26,6 +26,7 @@ import org.apache.lucene.search.Query;
import org.elasticsearch.index.query.QueryParseContext;
import java.util.List;
import java.util.Map;
public class MultiMatchQuery extends MatchQuery {
@ -44,16 +45,28 @@ public class MultiMatchQuery extends MatchQuery {
super(parseContext);
}
public Query parse(Type type, List<String> fieldNames, String text) {
public Query parse(Type type, Map<String, Float> fieldNames, String text) {
if (fieldNames.size() == 1) {
return parse(type, fieldNames.get(0), text);
Map.Entry<String, Float> fieldBoost = fieldNames.entrySet().iterator().next();
Float boostValue = fieldBoost.getValue();
if (boostValue == null) {
return parse(type, fieldBoost.getKey(), text);
} else {
Query query = parse(type, fieldBoost.getKey(), text);
query.setBoost(boostValue);
return query;
}
}
if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
boolean clauseAdded = false;
for (String fieldName : fieldNames) {
for (String fieldName : fieldNames.keySet()) {
Query query = parse(type, fieldName, text);
Float boostValue = fieldNames.get(fieldName);
if (boostValue != null) {
query.setBoost(boostValue);
}
if (query != null) {
clauseAdded = true;
disMaxQuery.add(query);
@ -62,8 +75,12 @@ public class MultiMatchQuery extends MatchQuery {
return clauseAdded ? disMaxQuery : null;
} else {
BooleanQuery booleanQuery = new BooleanQuery();
for (String fieldName : fieldNames) {
for (String fieldName : fieldNames.keySet()) {
Query query = parse(type, fieldName, text);
Float boostValue = fieldNames.get(fieldName);
if (boostValue != null) {
query.setBoost(boostValue);
}
if (query != null) {
booleanQuery.add(query, BooleanClause.Occur.SHOULD);
}

View File

@ -409,9 +409,9 @@ public class SimpleQueryTests extends AbstractNodesTests {
client.admin().indices().prepareCreate("test").setSettings(ImmutableSettings.settingsBuilder().put("number_of_shards", 1)).execute().actionGet();
client.prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value4").execute().actionGet();
client.prepareIndex("test", "type1", "2").setSource("field1", "value2", "field2", "value5").execute().actionGet();
client.prepareIndex("test", "type1", "3").setSource("field1", "value3", "field2", "value6").execute().actionGet();
client.prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value4", "field3", "value3").execute().actionGet();
client.prepareIndex("test", "type1", "2").setSource("field1", "value2", "field2", "value5", "field3", "value2").execute().actionGet();
client.prepareIndex("test", "type1", "3").setSource("field1", "value3", "field2", "value6", "field3", "value1").execute().actionGet();
client.admin().indices().prepareRefresh("test").execute().actionGet();
MultiMatchQueryBuilder builder = QueryBuilders.multiMatchQuery("value1 value2 value4", "field1", "field2");
@ -442,11 +442,21 @@ public class SimpleQueryTests extends AbstractNodesTests {
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
assertThat("1", equalTo(searchResponse.hits().getAt(0).id()));
client.admin().indices().prepareRefresh("test").execute().actionGet();
builder = QueryBuilders.multiMatchQuery("value1", "field1", "field3^1.5")
.operator(MatchQueryBuilder.Operator.AND); // Operator only applies on terms inside a field! Fields are always OR-ed together.
searchResponse = client.prepareSearch()
.setQuery(builder)
.execute().actionGet();
assertThat(searchResponse.hits().totalHits(), equalTo(2l));
assertThat("3", equalTo(searchResponse.hits().getAt(0).id()));
assertThat("1", equalTo(searchResponse.hits().getAt(1).id()));
// Test lenient
client.prepareIndex("test", "type1", "3").setSource("field1", "value7", "field2", "value8", "field3", 5).execute().actionGet();
client.prepareIndex("test", "type1", "3").setSource("field1", "value7", "field2", "value8", "field4", 5).execute().actionGet();
client.admin().indices().prepareRefresh("test").execute().actionGet();
builder = QueryBuilders.multiMatchQuery("value1", "field1", "field2", "field3");
builder = QueryBuilders.multiMatchQuery("value1", "field1", "field2", "field4");
try {
client.prepareSearch()
.setQuery(builder)