multi_match query supports fields as single string and array

The multi_match query accepted only an array in the fields parameter. This patch allows to use a single string as well.

Also added tests for parsing in both cases.

Closes #4164
This commit is contained in:
Alexander Reelsen 2013-11-14 15:11:37 +01:00
parent 826b8bd742
commit c8020760d7
4 changed files with 59 additions and 25 deletions

View File

@ -67,33 +67,13 @@ public class MultiMatchQueryParser implements QueryParser {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_ARRAY) {
if ("fields".equals(currentFieldName)) {
} else if ("fields".equals(currentFieldName)) {
if (token == XContentParser.Token.START_ARRAY) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String fField = null;
Float fBoost = null;
char[] fieldText = parser.textCharacters();
int end = parser.textOffset() + parser.textLength();
for (int i = parser.textOffset(); i < end; i++) {
if (fieldText[i] == '^') {
int relativeLocation = i - parser.textOffset();
fField = new String(fieldText, parser.textOffset(), relativeLocation);
fBoost = Float.parseFloat(new String(fieldText, i + 1, parser.textLength() - relativeLocation - 1));
break;
}
}
if (fField == null) {
fField = parser.text();
}
if (Regex.isSimpleMatchPattern(fField)) {
for (String field : parseContext.mapperService().simpleMatchToIndexNames(fField)) {
fieldNameWithBoosts.put(field, fBoost);
}
} else {
fieldNameWithBoosts.put(fField, fBoost);
}
extractFieldAndBoost(parseContext, parser, fieldNameWithBoosts);
}
} else if (token.isValue()) {
extractFieldAndBoost(parseContext, parser, fieldNameWithBoosts);
} else {
throw new QueryParsingException(parseContext.index(), "[query_string] query does not support [" + currentFieldName + "]");
}
@ -184,4 +164,30 @@ public class MultiMatchQueryParser implements QueryParser {
}
return query;
}
private void extractFieldAndBoost(QueryParseContext parseContext, XContentParser parser, Map<String, Float> fieldNameWithBoosts) throws IOException {
String fField = null;
Float fBoost = null;
char[] fieldText = parser.textCharacters();
int end = parser.textOffset() + parser.textLength();
for (int i = parser.textOffset(); i < end; i++) {
if (fieldText[i] == '^') {
int relativeLocation = i - parser.textOffset();
fField = new String(fieldText, parser.textOffset(), relativeLocation);
fBoost = Float.parseFloat(new String(fieldText, i + 1, parser.textLength() - relativeLocation - 1));
break;
}
}
if (fField == null) {
fField = parser.text();
}
if (Regex.isSimpleMatchPattern(fField)) {
for (String field : parseContext.mapperService().simpleMatchToIndexNames(fField)) {
fieldNameWithBoosts.put(field, fBoost);
}
} else {
fieldNameWithBoosts.put(fField, fBoost);
}
}
}

View File

@ -2268,4 +2268,20 @@ public class SimpleIndexQueryParserTests extends ElasticsearchTestCase {
Query parsedQuery = queryParser.parse(query).query();
assertThat((double) (parsedQuery.getBoost()), Matchers.closeTo(3.0, 1.e-7));
}
@Test
public void testMultiMatchQuery() throws Exception {
IndexQueryParserService queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/multiMatch-query-simple.json");
Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(DisjunctionMaxQuery.class));
}
@Test
public void testMultiMatchQueryWithFieldsAsString() throws Exception {
IndexQueryParserService queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/multiMatch-query-fields-as-string.json");
Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(BooleanQuery.class));
}
}

View File

@ -0,0 +1,6 @@
{
"multi_match": {
"query": "foo bar",
"fields": "myField"
}
}

View File

@ -0,0 +1,6 @@
{
"multi_match": {
"query": "foo bar",
"fields": [ "myField", "otherField" ]
}
}