Skip to content

Commit 852df12

Browse files
authored
Match phrase queries against non-indexed fields should throw an exception (#31060)
When `lenient=false`, attempts to create match phrase queries with custom analyzers against non-text fields will throw an IllegalArgumentException. Also changes `*Match*QueryBuilderTests` so that it avoids this scenario Fixes #31061
1 parent 609de08 commit 852df12

File tree

5 files changed

+29
-34
lines changed

5 files changed

+29
-34
lines changed

docs/reference/migration/migrate_7_0/search.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
* The boundary specified using geohashes in the `geo_bounding_box` query
1616
now include entire geohash cell, instead of just geohash center.
1717

18+
* Attempts to generate multi-term phrase queries against non-text fields
19+
with a custom analyzer will now throw an exception
20+
1821
==== Adaptive replica selection enabled by default
1922

2023
Adaptive replica selection has been enabled by default. If you wish to return to

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -352,38 +352,41 @@ protected Query newSynonymQuery(Term[] terms) {
352352

353353
@Override
354354
protected Query analyzePhrase(String field, TokenStream stream, int slop) throws IOException {
355-
IllegalStateException e = checkForPositions(field);
356-
if (e != null) {
355+
try {
356+
checkForPositions(field);
357+
Query query = mapper.phraseQuery(field, stream, slop, enablePositionIncrements);
358+
if (query instanceof PhraseQuery) {
359+
// synonyms that expand to multiple terms can return a phrase query.
360+
return blendPhraseQuery((PhraseQuery) query, mapper);
361+
}
362+
return query;
363+
}
364+
catch (IllegalArgumentException | IllegalStateException e) {
357365
if (lenient) {
358366
return newLenientFieldQuery(field, e);
359367
}
360368
throw e;
361369
}
362-
Query query = mapper.phraseQuery(field, stream, slop, enablePositionIncrements);
363-
if (query instanceof PhraseQuery) {
364-
// synonyms that expand to multiple terms can return a phrase query.
365-
return blendPhraseQuery((PhraseQuery) query, mapper);
366-
}
367-
return query;
368370
}
369371

370372
@Override
371373
protected Query analyzeMultiPhrase(String field, TokenStream stream, int slop) throws IOException {
372-
IllegalStateException e = checkForPositions(field);
373-
if (e != null) {
374+
try {
375+
checkForPositions(field);
376+
return mapper.multiPhraseQuery(field, stream, slop, enablePositionIncrements);
377+
}
378+
catch (IllegalArgumentException | IllegalStateException e) {
374379
if (lenient) {
375380
return newLenientFieldQuery(field, e);
376381
}
377382
throw e;
378383
}
379-
return mapper.multiPhraseQuery(field, stream, slop, enablePositionIncrements);
380384
}
381385

382-
private IllegalStateException checkForPositions(String field) {
386+
private void checkForPositions(String field) {
383387
if (hasPositions(mapper) == false) {
384-
return new IllegalStateException("field:[" + field + "] was indexed without position data; cannot run PhraseQuery");
388+
throw new IllegalStateException("field:[" + field + "] was indexed without position data; cannot run PhraseQuery");
385389
}
386-
return null;
387390
}
388391

389392
/**

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected MatchPhrasePrefixQueryBuilder doCreateTestQueryBuilder() {
6161

6262
MatchPhrasePrefixQueryBuilder matchQuery = new MatchPhrasePrefixQueryBuilder(fieldName, value);
6363

64-
if (randomBoolean()) {
64+
if (randomBoolean() && fieldName.equals(STRING_FIELD_NAME)) {
6565
matchQuery.analyzer(randomFrom("simple", "keyword", "whitespace"));
6666
}
6767

@@ -99,15 +99,6 @@ protected void doAssertLuceneQuery(MatchPhrasePrefixQueryBuilder queryBuilder, Q
9999
.or(instanceOf(IndexOrDocValuesQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
100100
}
101101

102-
/**
103-
* Overridden to allow for annotating with @AwaitsFix. Please remove this method after fixing.
104-
*/
105-
@Override
106-
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/31061")
107-
public void testToQuery() throws IOException {
108-
super.testToQuery();
109-
}
110-
111102
public void testIllegalValues() {
112103
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new MatchPhrasePrefixQueryBuilder(null, "value"));
113104
assertEquals("[match_phrase_prefix] requires fieldName", e.getMessage());
@@ -127,6 +118,12 @@ public void testBadAnalyzer() throws IOException {
127118
assertThat(e.getMessage(), containsString("analyzer [bogusAnalyzer] not found"));
128119
}
129120

121+
public void testPhraseOnFieldWithNoTerms() {
122+
MatchPhrasePrefixQueryBuilder matchQuery = new MatchPhrasePrefixQueryBuilder(DATE_FIELD_NAME, "three term phrase");
123+
matchQuery.analyzer("whitespace");
124+
expectThrows(IllegalArgumentException.class, () -> matchQuery.doToQuery(createShardContext()));
125+
}
126+
130127
public void testPhrasePrefixMatchQuery() throws IOException {
131128
String json1 = "{\n" +
132129
" \"match_phrase_prefix\" : {\n" +

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ protected MatchPhraseQueryBuilder doCreateTestQueryBuilder() {
6464

6565
MatchPhraseQueryBuilder matchQuery = new MatchPhraseQueryBuilder(fieldName, value);
6666

67-
if (randomBoolean()) {
67+
if (randomBoolean() && fieldName.equals(STRING_FIELD_NAME)) {
6868
matchQuery.analyzer(randomFrom("simple", "keyword", "whitespace"));
6969
}
7070

@@ -107,15 +107,6 @@ protected void doAssertLuceneQuery(MatchPhraseQueryBuilder queryBuilder, Query q
107107
.or(instanceOf(IndexOrDocValuesQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
108108
}
109109

110-
/**
111-
* Overridden to allow for annotating with @AwaitsFix. Please remove this method after fixing.
112-
*/
113-
@Override
114-
@AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/31061")
115-
public void testToQuery() throws IOException {
116-
super.testToQuery();
117-
}
118-
119110
public void testIllegalValues() {
120111
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new MatchPhraseQueryBuilder(null, "value"));
121112
assertEquals("[match_phrase] requires fieldName", e.getMessage());

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.index.query;
2121

22+
import com.carrotsearch.randomizedtesting.annotations.Seed;
2223
import org.apache.lucene.index.Term;
2324
import org.apache.lucene.queries.ExtendedCommonTermsQuery;
2425
import org.apache.lucene.search.BooleanQuery;

0 commit comments

Comments
 (0)