From 42c5054e52ae406f0da56d620e01d0d8ea60ba50 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 2 Oct 2019 09:54:10 +0200 Subject: [PATCH] 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. --- .../index/search/MatchQuery.java | 25 +++++++++++++------ .../index/search/MultiMatchQuery.java | 2 +- .../index/search/QueryParserHelper.java | 2 +- .../index/query/MatchQueryBuilderTests.java | 13 ++++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java b/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java index 64ef628a7b1..639944ebeaf 100644 --- a/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java +++ b/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java @@ -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 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 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); diff --git a/server/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java b/server/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java index 7d88e508d0d..ed0f1db8ed3 100644 --- a/server/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java +++ b/server/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java @@ -194,7 +194,7 @@ public class MultiMatchQuery extends MatchQuery { } @Override - protected Query newPrefixQuery(String field, Term term) { + protected Query newPrefixQuery(Term term) { List disjunctions = new ArrayList<>(); for (FieldAndBoost fieldType : blendedFields) { Query query = fieldType.fieldType.prefixQuery(term.text(), null, context); diff --git a/server/src/main/java/org/elasticsearch/index/search/QueryParserHelper.java b/server/src/main/java/org/elasticsearch/index/search/QueryParserHelper.java index 8d6198e17e2..e4b397c9a53 100644 --- a/server/src/main/java/org/elasticsearch/index/search/QueryParserHelper.java +++ b/server/src/main/java/org/elasticsearch/index/search/QueryParserHelper.java @@ -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; } diff --git a/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java index 4dbdd08aaba..c5222b64cbd 100644 --- a/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java @@ -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