Skip to content

Commit 8496c27

Browse files
committed
Refactors MultiMatchQueryBuilder and Parser
Relates to #10217 This PR is against the query-refactoring branch. Closes #13405
1 parent f2b4ba9 commit 8496c27

File tree

8 files changed

+550
-168
lines changed

8 files changed

+550
-168
lines changed

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

Lines changed: 288 additions & 80 deletions
Large diffs are not rendered by default.

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

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

2020
package org.elasticsearch.index.query;
2121

22-
import org.apache.lucene.search.Query;
2322
import org.elasticsearch.common.inject.Inject;
24-
import org.elasticsearch.common.regex.Regex;
2523
import org.elasticsearch.common.unit.Fuzziness;
2624
import org.elasticsearch.common.xcontent.XContentParser;
27-
import org.elasticsearch.index.query.support.QueryParsers;
2825
import org.elasticsearch.index.search.MatchQuery;
29-
import org.elasticsearch.index.search.MultiMatchQuery;
3026

3127
import java.io.IOException;
3228
import java.util.HashMap;
@@ -35,7 +31,7 @@
3531
/**
3632
* Same as {@link MatchQueryParser} but has support for multiple fields.
3733
*/
38-
public class MultiMatchQueryParser extends BaseQueryParserTemp {
34+
public class MultiMatchQueryParser extends BaseQueryParser<MultiMatchQueryBuilder> {
3935

4036
@Inject
4137
public MultiMatchQueryParser() {
@@ -49,31 +45,41 @@ public String[] names() {
4945
}
5046

5147
@Override
52-
public Query parse(QueryShardContext context) throws IOException, QueryParsingException {
53-
QueryParseContext parseContext = context.parseContext();
48+
public MultiMatchQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
5449
XContentParser parser = parseContext.parser();
5550

5651
Object value = null;
57-
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
58-
Float tieBreaker = null;
59-
MultiMatchQueryBuilder.Type type = null;
60-
MultiMatchQuery multiMatchQuery = new MultiMatchQuery(context);
52+
Map<String, Float> fieldsBoosts = new HashMap<>();
53+
MultiMatchQueryBuilder.Type type = MultiMatchQueryBuilder.DEFAULT_TYPE;
54+
String analyzer = null;
55+
int slop = MultiMatchQueryBuilder.DEFAULT_PHRASE_SLOP;
56+
Fuzziness fuzziness = null;
57+
int prefixLength = MultiMatchQueryBuilder.DEFAULT_PREFIX_LENGTH;
58+
int maxExpansions = MultiMatchQueryBuilder.DEFAULT_MAX_EXPANSIONS;
59+
Operator operator = MultiMatchQueryBuilder.DEFAULT_OPERATOR;
6160
String minimumShouldMatch = null;
62-
Map<String, Float> fieldNameWithBoosts = new HashMap<>();
61+
String fuzzyRewrite = null;
62+
Boolean useDisMax = null;
63+
Float tieBreaker = null;
64+
Float cutoffFrequency = null;
65+
boolean lenient = MultiMatchQueryBuilder.DEFAULT_LENIENCY;
66+
MatchQuery.ZeroTermsQuery zeroTermsQuery = MultiMatchQueryBuilder.DEFAULT_ZERO_TERMS_QUERY;
67+
68+
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
6369
String queryName = null;
70+
6471
XContentParser.Token token;
6572
String currentFieldName = null;
66-
Boolean useDisMax = null;
6773
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
6874
if (token == XContentParser.Token.FIELD_NAME) {
6975
currentFieldName = parser.currentName();
7076
} else if ("fields".equals(currentFieldName)) {
7177
if (token == XContentParser.Token.START_ARRAY) {
7278
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
73-
extractFieldAndBoost(context, parser, fieldNameWithBoosts);
79+
parseFieldAndBoost(parser, fieldsBoosts);
7480
}
7581
} else if (token.isValue()) {
76-
extractFieldAndBoost(context, parser, fieldNameWithBoosts);
82+
parseFieldAndBoost(parser, fieldsBoosts);
7783
} else {
7884
throw new QueryParsingException(parseContext, "[" + MultiMatchQueryBuilder.NAME + "] query does not support [" + currentFieldName + "]");
7985
}
@@ -83,41 +89,37 @@ public Query parse(QueryShardContext context) throws IOException, QueryParsingEx
8389
} else if ("type".equals(currentFieldName)) {
8490
type = MultiMatchQueryBuilder.Type.parse(parser.text(), parseContext.parseFieldMatcher());
8591
} else if ("analyzer".equals(currentFieldName)) {
86-
String analyzer = parser.text();
87-
if (context.analysisService().analyzer(analyzer) == null) {
88-
throw new QueryParsingException(parseContext, "[" + MultiMatchQueryBuilder.NAME + "] analyzer [" + parser.text() + "] not found");
89-
}
90-
multiMatchQuery.setAnalyzer(analyzer);
92+
analyzer = parser.text();
9193
} else if ("boost".equals(currentFieldName)) {
9294
boost = parser.floatValue();
9395
} else if ("slop".equals(currentFieldName) || "phrase_slop".equals(currentFieldName) || "phraseSlop".equals(currentFieldName)) {
94-
multiMatchQuery.setPhraseSlop(parser.intValue());
96+
slop = parser.intValue();
9597
} else if (parseContext.parseFieldMatcher().match(currentFieldName, Fuzziness.FIELD)) {
96-
multiMatchQuery.setFuzziness(Fuzziness.parse(parser));
98+
fuzziness = Fuzziness.parse(parser);
9799
} else if ("prefix_length".equals(currentFieldName) || "prefixLength".equals(currentFieldName)) {
98-
multiMatchQuery.setFuzzyPrefixLength(parser.intValue());
100+
prefixLength = parser.intValue();
99101
} else if ("max_expansions".equals(currentFieldName) || "maxExpansions".equals(currentFieldName)) {
100-
multiMatchQuery.setMaxExpansions(parser.intValue());
102+
maxExpansions = parser.intValue();
101103
} else if ("operator".equals(currentFieldName)) {
102-
multiMatchQuery.setOccur(Operator.fromString(parser.text()).toBooleanClauseOccur());
104+
operator = Operator.fromString(parser.text());
103105
} else if ("minimum_should_match".equals(currentFieldName) || "minimumShouldMatch".equals(currentFieldName)) {
104106
minimumShouldMatch = parser.textOrNull();
105107
} else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) {
106-
multiMatchQuery.setFuzzyRewriteMethod(QueryParsers.parseRewriteMethod(parseContext.parseFieldMatcher(), parser.textOrNull(), null));
108+
fuzzyRewrite = parser.textOrNull();
107109
} else if ("use_dis_max".equals(currentFieldName) || "useDisMax".equals(currentFieldName)) {
108110
useDisMax = parser.booleanValue();
109111
} else if ("tie_breaker".equals(currentFieldName) || "tieBreaker".equals(currentFieldName)) {
110-
multiMatchQuery.setTieBreaker(tieBreaker = parser.floatValue());
112+
tieBreaker = parser.floatValue();
111113
} else if ("cutoff_frequency".equals(currentFieldName)) {
112-
multiMatchQuery.setCommonTermsCutoff(parser.floatValue());
114+
cutoffFrequency = parser.floatValue();
113115
} else if ("lenient".equals(currentFieldName)) {
114-
multiMatchQuery.setLenient(parser.booleanValue());
116+
lenient = parser.booleanValue();
115117
} else if ("zero_terms_query".equals(currentFieldName)) {
116118
String zeroTermsDocs = parser.text();
117119
if ("none".equalsIgnoreCase(zeroTermsDocs)) {
118-
multiMatchQuery.setZeroTermsQuery(MatchQuery.ZeroTermsQuery.NONE);
120+
zeroTermsQuery = MatchQuery.ZeroTermsQuery.NONE;
119121
} else if ("all".equalsIgnoreCase(zeroTermsDocs)) {
120-
multiMatchQuery.setZeroTermsQuery(MatchQuery.ZeroTermsQuery.ALL);
122+
zeroTermsQuery = MatchQuery.ZeroTermsQuery.ALL;
121123
} else {
122124
throw new QueryParsingException(parseContext, "Unsupported zero_terms_docs value [" + zeroTermsDocs + "]");
123125
}
@@ -133,37 +135,33 @@ public Query parse(QueryShardContext context) throws IOException, QueryParsingEx
133135
throw new QueryParsingException(parseContext, "No text specified for multi_match query");
134136
}
135137

136-
if (fieldNameWithBoosts.isEmpty()) {
138+
if (fieldsBoosts.isEmpty()) {
137139
throw new QueryParsingException(parseContext, "No fields specified for multi_match query");
138140
}
139-
if (type == null) {
140-
type = MultiMatchQueryBuilder.Type.BEST_FIELDS;
141-
}
142-
if (useDisMax != null) { // backwards foobar
143-
boolean typeUsesDismax = type.tieBreaker() != 1.0f;
144-
if (typeUsesDismax != useDisMax) {
145-
if (useDisMax && tieBreaker == null) {
146-
multiMatchQuery.setTieBreaker(0.0f);
147-
} else {
148-
multiMatchQuery.setTieBreaker(1.0f);
149-
}
150-
}
151-
}
152-
Query query = multiMatchQuery.parse(type, fieldNameWithBoosts, value, minimumShouldMatch);
153-
if (query == null) {
154-
return null;
155-
}
156141

157-
query.setBoost(boost);
158-
if (queryName != null) {
159-
context.addNamedQuery(queryName, query);
160-
}
161-
return query;
142+
return new MultiMatchQueryBuilder(value)
143+
.fields(fieldsBoosts)
144+
.type(type)
145+
.analyzer(analyzer)
146+
.cutoffFrequency(cutoffFrequency)
147+
.fuzziness(fuzziness)
148+
.fuzzyRewrite(fuzzyRewrite)
149+
.useDisMax(useDisMax)
150+
.lenient(lenient)
151+
.maxExpansions(maxExpansions)
152+
.minimumShouldMatch(minimumShouldMatch)
153+
.operator(operator)
154+
.prefixLength(prefixLength)
155+
.slop(slop)
156+
.tieBreaker(tieBreaker)
157+
.zeroTermsQuery(zeroTermsQuery)
158+
.boost(boost)
159+
.queryName(queryName);
162160
}
163161

164-
private void extractFieldAndBoost(QueryShardContext context, XContentParser parser, Map<String, Float> fieldNameWithBoosts) throws IOException {
162+
private void parseFieldAndBoost(XContentParser parser, Map<String, Float> fieldsBoosts) throws IOException {
165163
String fField = null;
166-
Float fBoost = null;
164+
Float fBoost = AbstractQueryBuilder.DEFAULT_BOOST;
167165
char[] fieldText = parser.textCharacters();
168166
int end = parser.textOffset() + parser.textLength();
169167
for (int i = parser.textOffset(); i < end; i++) {
@@ -177,14 +175,7 @@ private void extractFieldAndBoost(QueryShardContext context, XContentParser pars
177175
if (fField == null) {
178176
fField = parser.text();
179177
}
180-
181-
if (Regex.isSimpleMatchPattern(fField)) {
182-
for (String field : context.mapperService().simpleMatchToIndexNames(fField)) {
183-
fieldNameWithBoosts.put(field, fBoost);
184-
}
185-
} else {
186-
fieldNameWithBoosts.put(fField, fBoost);
187-
}
178+
fieldsBoosts.put(fField, fBoost);
188179
}
189180

190181
@Override

core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
package org.elasticsearch.index.query;
2121

2222
import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator;
23-
2423
import org.apache.lucene.search.Query;
2524
import org.elasticsearch.Version;
26-
import org.elasticsearch.action.ActionFuture;
2725
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
2826
import org.elasticsearch.action.get.GetRequest;
2927
import org.elasticsearch.action.get.GetResponse;
@@ -79,11 +77,7 @@
7977
import org.elasticsearch.threadpool.ThreadPoolModule;
8078
import org.joda.time.DateTime;
8179
import org.joda.time.DateTimeZone;
82-
import org.junit.After;
83-
import org.junit.AfterClass;
84-
import org.junit.Before;
85-
import org.junit.BeforeClass;
86-
import org.junit.Test;
80+
import org.junit.*;
8781

8882
import java.io.IOException;
8983
import java.lang.reflect.InvocationHandler;
@@ -95,10 +89,7 @@
9589
import java.util.Map;
9690
import java.util.concurrent.ExecutionException;
9791

98-
import static org.hamcrest.Matchers.equalTo;
99-
import static org.hamcrest.Matchers.not;
100-
import static org.hamcrest.Matchers.notNullValue;
101-
import static org.hamcrest.Matchers.nullValue;
92+
import static org.hamcrest.Matchers.*;
10293

10394
public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>> extends ESTestCase {
10495

0 commit comments

Comments
 (0)