Skip to content

Commit bd3a68c

Browse files
authored
Add tests for multi_match phrase prefix query across multiple fields (#95772)
This adds unit test coverage for a bug that was recently found in Lucene. We would have caught it earlier if we were testing the underlying lucene query being generated. Closes #95738
1 parent 1afafb3 commit bd3a68c

File tree

2 files changed

+45
-27
lines changed

2 files changed

+45
-27
lines changed

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

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@
2222
import org.apache.lucene.search.PrefixQuery;
2323
import org.apache.lucene.search.Query;
2424
import org.apache.lucene.search.TermQuery;
25-
import org.elasticsearch.cluster.metadata.IndexMetadata;
2625
import org.elasticsearch.common.ParsingException;
2726
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
28-
import org.elasticsearch.common.settings.Settings;
2927
import org.elasticsearch.common.unit.Fuzziness;
3028
import org.elasticsearch.core.Strings;
3129
import org.elasticsearch.index.query.MultiMatchQueryBuilder.Type;
@@ -43,7 +41,6 @@
4341
import static org.hamcrest.CoreMatchers.anyOf;
4442
import static org.hamcrest.CoreMatchers.containsString;
4543
import static org.hamcrest.CoreMatchers.equalTo;
46-
import static org.hamcrest.CoreMatchers.hasItems;
4744
import static org.hamcrest.CoreMatchers.instanceOf;
4845
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
4946

@@ -453,27 +450,6 @@ public void testNegativeFieldBoost() {
453450
assertThat(exc.getMessage(), containsString("negative [boost]"));
454451
}
455452

456-
private static IndexMetadata newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) {
457-
Settings build = Settings.builder().put(oldIndexSettings).put(indexSettings).build();
458-
return IndexMetadata.builder(name).settings(build).build();
459-
}
460-
461-
private void assertQueryWithAllFieldsWildcard(Query query) {
462-
assertEquals(DisjunctionMaxQuery.class, query.getClass());
463-
DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query;
464-
int noMatchNoDocsQueries = 0;
465-
for (Query q : disjunctionMaxQuery.getDisjuncts()) {
466-
if (q.getClass() == MatchNoDocsQuery.class) {
467-
noMatchNoDocsQueries++;
468-
}
469-
}
470-
assertEquals(9, noMatchNoDocsQueries);
471-
assertThat(
472-
disjunctionMaxQuery.getDisjuncts(),
473-
hasItems(new TermQuery(new Term(TEXT_FIELD_NAME, "hello")), new TermQuery(new Term(KEYWORD_FIELD_NAME, "hello")))
474-
);
475-
}
476-
477453
/**
478454
* "now" on date fields should make the query non-cachable.
479455
*/

server/src/test/java/org/elasticsearch/index/search/MultiMatchQueryParserTests.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,15 @@
4444
import java.util.Collection;
4545
import java.util.Collections;
4646
import java.util.HashMap;
47+
import java.util.HashSet;
4748
import java.util.List;
4849
import java.util.Map;
50+
import java.util.Set;
4951

5052
import static java.util.Collections.emptyMap;
5153
import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
5254
import static org.hamcrest.Matchers.equalTo;
55+
import static org.hamcrest.Matchers.instanceOf;
5356

5457
public class MultiMatchQueryParserTests extends ESSingleNodeTestCase {
5558

@@ -73,15 +76,27 @@ public void setup() throws IOException {
7376
"properties": {
7477
"first": {
7578
"type": "text",
76-
"analyzer": "standard"
79+
"analyzer": "standard",
80+
"index_prefixes": {
81+
"min_chars" : 1,
82+
"max_chars" : 19
83+
}
7784
},
7885
"last": {
7986
"type": "text",
80-
"analyzer": "standard"
87+
"analyzer": "standard",
88+
"index_prefixes": {
89+
"min_chars" : 1,
90+
"max_chars" : 19
91+
}
8192
},
8293
"nickname": {
8394
"type": "text",
84-
"analyzer": "whitespace"
95+
"analyzer": "whitespace",
96+
"index_prefixes": {
97+
"min_chars" : 1,
98+
"max_chars" : 19
99+
}
85100
}
86101
}
87102
}
@@ -93,6 +108,33 @@ public void setup() throws IOException {
93108
this.indexService = indexService;
94109
}
95110

111+
public void testToQueryPhrasePrefix() throws IOException {
112+
SearchExecutionContext searchExecutionContext = indexService.newSearchExecutionContext(randomInt(20), 0, null, () -> {
113+
throw new UnsupportedOperationException();
114+
}, null, emptyMap());
115+
searchExecutionContext.setAllowUnmappedFields(true);
116+
MultiMatchQueryBuilder multiMatchQueryBuilder = new MultiMatchQueryBuilder("Har", "name.first", "name.last", "name.nickname");
117+
multiMatchQueryBuilder.type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX);
118+
Query query = multiMatchQueryBuilder.toQuery(searchExecutionContext);
119+
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
120+
DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query;
121+
Set<Term> expectedTerms = new HashSet<>(
122+
Arrays.asList(
123+
new Term("name.first._index_prefix", "har"),
124+
new Term("name.last._index_prefix", "har"),
125+
new Term("name.nickname._index_prefix", "Har")
126+
)
127+
);
128+
for (Query disjunct : disjunctionMaxQuery.getDisjuncts()) {
129+
assertThat(disjunct, instanceOf(SynonymQuery.class));
130+
SynonymQuery synonymQuery = (SynonymQuery) disjunct;
131+
assertEquals(1, synonymQuery.getTerms().size());
132+
Term term = synonymQuery.getTerms().get(0);
133+
assertTrue("Unexpected term " + term, expectedTerms.remove(term));
134+
}
135+
assertEquals("Expected terms not found in the query: " + expectedTerms, 0, expectedTerms.size());
136+
}
137+
96138
public void testCrossFieldMultiMatchQuery() throws IOException {
97139
SearchExecutionContext searchExecutionContext = indexService.newSearchExecutionContext(randomInt(20), 0, null, () -> {
98140
throw new UnsupportedOperationException();

0 commit comments

Comments
 (0)