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.
This commit is contained in:
parent
033aa9cf9b
commit
42c5054e52
|
@ -62,6 +62,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.elasticsearch.common.lucene.search.Queries.newLenientFieldQuery;
|
||||
|
@ -248,6 +249,14 @@ public class MatchQuery {
|
|||
if (fieldType == null) {
|
||||
return newUnmappedFieldQuery(fieldName);
|
||||
}
|
||||
Set<String> fields = context.simpleMatchToIndexNames(fieldName);
|
||||
if (fields.contains(fieldName)) {
|
||||
assert fields.size() == 1;
|
||||
// this field is a concrete field or an alias so we use the
|
||||
// field type name directly
|
||||
fieldName = fieldType.name();
|
||||
}
|
||||
|
||||
Analyzer analyzer = getAnalyzer(fieldType, type == Type.PHRASE || type == Type.PHRASE_PREFIX);
|
||||
assert analyzer != null;
|
||||
|
||||
|
@ -261,9 +270,9 @@ public class MatchQuery {
|
|||
*/
|
||||
if (analyzer == Lucene.KEYWORD_ANALYZER && type != Type.PHRASE_PREFIX) {
|
||||
final Term term = new Term(fieldName, value.toString());
|
||||
if ((fieldType instanceof TextFieldMapper.TextFieldType || fieldType instanceof KeywordFieldMapper.KeywordFieldType)
|
||||
&& type == Type.BOOLEAN_PREFIX) {
|
||||
return builder.newPrefixQuery(fieldName, term);
|
||||
if (type == Type.BOOLEAN_PREFIX
|
||||
&& (fieldType instanceof TextFieldMapper.TextFieldType || fieldType instanceof KeywordFieldMapper.KeywordFieldType)) {
|
||||
return builder.newPrefixQuery(term);
|
||||
} else {
|
||||
return builder.newTermQuery(term);
|
||||
}
|
||||
|
@ -581,12 +590,12 @@ public class MatchQuery {
|
|||
/**
|
||||
* Builds a new prefix query instance.
|
||||
*/
|
||||
protected Query newPrefixQuery(String field, Term term) {
|
||||
protected Query newPrefixQuery(Term term) {
|
||||
try {
|
||||
return fieldType.prefixQuery(term.text(), null, context);
|
||||
} catch (RuntimeException e) {
|
||||
if (lenient) {
|
||||
return newLenientFieldQuery(field, e);
|
||||
return newLenientFieldQuery(term.field(), e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
@ -603,7 +612,7 @@ public class MatchQuery {
|
|||
final Term term = new Term(field, termAtt.getBytesRef());
|
||||
int lastOffset = offsetAtt.endOffset();
|
||||
stream.end();
|
||||
return isPrefix && lastOffset == offsetAtt.endOffset() ? newPrefixQuery(field, term) : newTermQuery(term);
|
||||
return isPrefix && lastOffset == offsetAtt.endOffset() ? newPrefixQuery(term) : newTermQuery(term);
|
||||
}
|
||||
|
||||
private void add(BooleanQuery.Builder q, String field, List<Term> current, BooleanClause.Occur operator, boolean isPrefix) {
|
||||
|
@ -612,7 +621,7 @@ public class MatchQuery {
|
|||
}
|
||||
if (current.size() == 1) {
|
||||
if (isPrefix) {
|
||||
q.add(newPrefixQuery(field, current.get(0)), operator);
|
||||
q.add(newPrefixQuery(current.get(0)), operator);
|
||||
} else {
|
||||
q.add(newTermQuery(current.get(0)), operator);
|
||||
}
|
||||
|
@ -729,7 +738,7 @@ public class MatchQuery {
|
|||
Term[] terms = graph.getTerms(field, start);
|
||||
assert terms.length > 0;
|
||||
if (terms.length == 1) {
|
||||
queryPos = usePrefix ? newPrefixQuery(field, terms[0]) : newTermQuery(terms[0]);
|
||||
queryPos = usePrefix ? newPrefixQuery(terms[0]) : newTermQuery(terms[0]);
|
||||
} else {
|
||||
// We don't apply prefix on synonyms
|
||||
queryPos = newSynonymQuery(terms);
|
||||
|
|
|
@ -194,7 +194,7 @@ public class MultiMatchQuery extends MatchQuery {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Query newPrefixQuery(String field, Term term) {
|
||||
protected Query newPrefixQuery(Term term) {
|
||||
List<Query> disjunctions = new ArrayList<>();
|
||||
for (FieldAndBoost fieldType : blendedFields) {
|
||||
Query query = fieldType.fieldType.prefixQuery(term.text(), null, context);
|
||||
|
|
|
@ -52,7 +52,7 @@ public final class QueryParserHelper {
|
|||
float boost = 1.0f;
|
||||
if (boostIndex != -1) {
|
||||
fieldName = field.substring(0, boostIndex);
|
||||
boost = Float.parseFloat(field.substring(boostIndex+1, field.length()));
|
||||
boost = Float.parseFloat(field.substring(boostIndex+1));
|
||||
} else {
|
||||
fieldName = field;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.apache.lucene.search.MatchNoDocsQuery;
|
|||
import org.apache.lucene.search.PhraseQuery;
|
||||
import org.apache.lucene.search.PointRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.SynonymQuery;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.spans.SpanNearQuery;
|
||||
import org.apache.lucene.search.spans.SpanOrQuery;
|
||||
|
@ -488,6 +489,18 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase<MatchQueryBuil
|
|||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
||||
public void testAliasWithSynonyms() throws Exception {
|
||||
final MatchQuery matchQuery = new MatchQuery(createShardContext());
|
||||
matchQuery.setAnalyzer(new MockSynonymAnalyzer());
|
||||
final Query actual = matchQuery.parse(Type.PHRASE, STRING_ALIAS_FIELD_NAME, "dogs");
|
||||
Query expected = new SynonymQuery.Builder(STRING_FIELD_NAME)
|
||||
.addTerm(new Term(STRING_FIELD_NAME, "dogs"))
|
||||
.addTerm(new Term(STRING_FIELD_NAME, "dog"))
|
||||
.build();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testMaxBooleanClause() {
|
||||
MatchQuery query = new MatchQuery(createShardContext());
|
||||
query.setAnalyzer(new MockGraphAnalyzer(createGiantGraph(40)));
|
||||
|
|
Loading…
Reference in New Issue