From b6a9bd9a31862bf4f73efd0009727134b91c4f27 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Wed, 12 Sep 2012 11:06:58 +0200 Subject: [PATCH] - Fixed boosting per field with multi_match query. --- .../index/query/MultiMatchQueryParser.java | 19 +++++--------- .../index/search/MultiMatchQuery.java | 25 ++++++++++++++++--- .../search/query/SimpleQueryTests.java | 20 +++++++++++---- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java b/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java index 4e39f537316..e3611532ada 100644 --- a/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java @@ -63,8 +63,7 @@ public class MultiMatchQueryParser implements QueryParser { MatchQuery.Type type = MatchQuery.Type.BOOLEAN; MultiMatchQuery multiMatchQuery = new MultiMatchQuery(parseContext); String minimumShouldMatch = null; - List fieldNames = Lists.newArrayList(); - Map fieldNameToBoost = Maps.newHashMap(); + Map 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; } diff --git a/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java b/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java index fc283073a38..3b7cb183e51 100644 --- a/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java +++ b/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java @@ -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 fieldNames, String text) { + public Query parse(Type type, Map fieldNames, String text) { if (fieldNames.size() == 1) { - return parse(type, fieldNames.get(0), text); + Map.Entry 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); } diff --git a/src/test/java/org/elasticsearch/test/integration/search/query/SimpleQueryTests.java b/src/test/java/org/elasticsearch/test/integration/search/query/SimpleQueryTests.java index 98e753c3e66..4620c01f5b9 100644 --- a/src/test/java/org/elasticsearch/test/integration/search/query/SimpleQueryTests.java +++ b/src/test/java/org/elasticsearch/test/integration/search/query/SimpleQueryTests.java @@ -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)