Skip to content

Commit cea5add

Browse files
authored
Fix alias field resolution in match query (#47369)
Synonym queries (when two tokens/paths start at the same position) use the alias field instead of the concrete field to build Lucene queries. This commit fixes this bug by resolving the alias field upfront in order to provide the concrete field to the actual query parser.
1 parent 4073499 commit cea5add

File tree

4 files changed

+32
-10
lines changed

4 files changed

+32
-10
lines changed

server/src/main/java/org/elasticsearch/index/search/MatchQuery.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import java.util.ArrayList;
6060
import java.util.Iterator;
6161
import java.util.List;
62+
import java.util.Set;
6263
import java.util.function.Supplier;
6364

6465
import static org.elasticsearch.common.lucene.search.Queries.newLenientFieldQuery;
@@ -235,6 +236,14 @@ public Query parse(Type type, String fieldName, Object value) throws IOException
235236
if (fieldType == null) {
236237
return newUnmappedFieldQuery(fieldName);
237238
}
239+
Set<String> fields = context.simpleMatchToIndexNames(fieldName);
240+
if (fields.contains(fieldName)) {
241+
assert fields.size() == 1;
242+
// this field is a concrete field or an alias so we use the
243+
// field type name directly
244+
fieldName = fieldType.name();
245+
}
246+
238247
Analyzer analyzer = getAnalyzer(fieldType, type == Type.PHRASE || type == Type.PHRASE_PREFIX);
239248
assert analyzer != null;
240249

@@ -248,9 +257,9 @@ public Query parse(Type type, String fieldName, Object value) throws IOException
248257
*/
249258
if (analyzer == Lucene.KEYWORD_ANALYZER && type != Type.PHRASE_PREFIX) {
250259
final Term term = new Term(fieldName, value.toString());
251-
if ((fieldType instanceof TextFieldMapper.TextFieldType || fieldType instanceof KeywordFieldMapper.KeywordFieldType)
252-
&& type == Type.BOOLEAN_PREFIX) {
253-
return builder.newPrefixQuery(fieldName, term);
260+
if (type == Type.BOOLEAN_PREFIX
261+
&& (fieldType instanceof TextFieldMapper.TextFieldType || fieldType instanceof KeywordFieldMapper.KeywordFieldType)) {
262+
return builder.newPrefixQuery(term);
254263
} else {
255264
return builder.newTermQuery(term);
256265
}
@@ -540,12 +549,12 @@ protected Query newTermQuery(Term term) {
540549
/**
541550
* Builds a new prefix query instance.
542551
*/
543-
protected Query newPrefixQuery(String field, Term term) {
552+
protected Query newPrefixQuery(Term term) {
544553
try {
545554
return fieldType.prefixQuery(term.text(), null, context);
546555
} catch (RuntimeException e) {
547556
if (lenient) {
548-
return newLenientFieldQuery(field, e);
557+
return newLenientFieldQuery(term.field(), e);
549558
}
550559
throw e;
551560
}
@@ -562,7 +571,7 @@ private Query analyzeTerm(String field, TokenStream stream, boolean isPrefix) th
562571
final Term term = new Term(field, termAtt.getBytesRef());
563572
int lastOffset = offsetAtt.endOffset();
564573
stream.end();
565-
return isPrefix && lastOffset == offsetAtt.endOffset() ? newPrefixQuery(field, term) : newTermQuery(term);
574+
return isPrefix && lastOffset == offsetAtt.endOffset() ? newPrefixQuery(term) : newTermQuery(term);
566575
}
567576

568577
private void add(BooleanQuery.Builder q, String field, List<Term> current, BooleanClause.Occur operator, boolean isPrefix) {
@@ -571,7 +580,7 @@ private void add(BooleanQuery.Builder q, String field, List<Term> current, Boole
571580
}
572581
if (current.size() == 1) {
573582
if (isPrefix) {
574-
q.add(newPrefixQuery(field, current.get(0)), operator);
583+
q.add(newPrefixQuery(current.get(0)), operator);
575584
} else {
576585
q.add(newTermQuery(current.get(0)), operator);
577586
}
@@ -688,7 +697,7 @@ public Query next() {
688697
Term[] terms = graph.getTerms(field, start);
689698
assert terms.length > 0;
690699
if (terms.length == 1) {
691-
queryPos = usePrefix ? newPrefixQuery(field, terms[0]) : newTermQuery(terms[0]);
700+
queryPos = usePrefix ? newPrefixQuery(terms[0]) : newTermQuery(terms[0]);
692701
} else {
693702
// We don't apply prefix on synonyms
694703
queryPos = newSynonymQuery(terms);

server/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ protected Query newTermQuery(Term term) {
194194
}
195195

196196
@Override
197-
protected Query newPrefixQuery(String field, Term term) {
197+
protected Query newPrefixQuery(Term term) {
198198
List<Query> disjunctions = new ArrayList<>();
199199
for (FieldAndBoost fieldType : blendedFields) {
200200
Query query = fieldType.fieldType.prefixQuery(term.text(), null, context);

server/src/main/java/org/elasticsearch/index/search/QueryParserHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public static Map<String, Float> parseFieldsAndWeights(List<String> fields) {
5252
float boost = 1.0f;
5353
if (boostIndex != -1) {
5454
fieldName = field.substring(0, boostIndex);
55-
boost = Float.parseFloat(field.substring(boostIndex+1, field.length()));
55+
boost = Float.parseFloat(field.substring(boostIndex+1));
5656
} else {
5757
fieldName = field;
5858
}

server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.lucene.search.PhraseQuery;
3232
import org.apache.lucene.search.PointRangeQuery;
3333
import org.apache.lucene.search.Query;
34+
import org.apache.lucene.search.SynonymQuery;
3435
import org.apache.lucene.search.TermQuery;
3536
import org.apache.lucene.search.spans.SpanNearQuery;
3637
import org.apache.lucene.search.spans.SpanOrQuery;
@@ -475,6 +476,18 @@ public void testMultiWordSynonymsPhrase() throws Exception {
475476
assertEquals(expected, actual);
476477
}
477478

479+
480+
public void testAliasWithSynonyms() throws Exception {
481+
final MatchQuery matchQuery = new MatchQuery(createShardContext());
482+
matchQuery.setAnalyzer(new MockSynonymAnalyzer());
483+
final Query actual = matchQuery.parse(Type.PHRASE, STRING_ALIAS_FIELD_NAME, "dogs");
484+
Query expected = new SynonymQuery.Builder(STRING_FIELD_NAME)
485+
.addTerm(new Term(STRING_FIELD_NAME, "dogs"))
486+
.addTerm(new Term(STRING_FIELD_NAME, "dog"))
487+
.build();
488+
assertEquals(expected, actual);
489+
}
490+
478491
public void testMaxBooleanClause() {
479492
MatchQuery query = new MatchQuery(createShardContext());
480493
query.setAnalyzer(new MockGraphAnalyzer(createGiantGraph(40)));

0 commit comments

Comments
 (0)