Fix multi fields empty query (#33017)
This change fixes empty query removal when all fields remove the search term in `simple_query_string`, `multi_match` and `query_string`. Closes #33009
This commit is contained in:
parent
f311680176
commit
8b43e21521
|
@ -328,8 +328,9 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
||||||
/**
|
/**
|
||||||
* @param type Sets how multiple fields should be combined to build textual part queries.
|
* @param type Sets how multiple fields should be combined to build textual part queries.
|
||||||
*/
|
*/
|
||||||
public void type(MultiMatchQueryBuilder.Type type) {
|
public QueryStringQueryBuilder type(MultiMatchQueryBuilder.Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -388,7 +389,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
||||||
this.analyzer = analyzer;
|
this.analyzer = analyzer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The optional analyzer used to analyze the query string. Note, if a field has search analyzer
|
* The optional analyzer used to analyze the query string. Note, if a field has search analyzer
|
||||||
* defined for it, then it will be used automatically. Defaults to the smart search analyzer.
|
* defined for it, then it will be used automatically. Defaults to the smart search analyzer.
|
||||||
|
@ -899,9 +900,9 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
||||||
Objects.equals(tieBreaker, other.tieBreaker) &&
|
Objects.equals(tieBreaker, other.tieBreaker) &&
|
||||||
Objects.equals(rewrite, other.rewrite) &&
|
Objects.equals(rewrite, other.rewrite) &&
|
||||||
Objects.equals(minimumShouldMatch, other.minimumShouldMatch) &&
|
Objects.equals(minimumShouldMatch, other.minimumShouldMatch) &&
|
||||||
Objects.equals(lenient, other.lenient) &&
|
Objects.equals(lenient, other.lenient) &&
|
||||||
Objects.equals(
|
Objects.equals(
|
||||||
timeZone == null ? null : timeZone.getID(),
|
timeZone == null ? null : timeZone.getID(),
|
||||||
other.timeZone == null ? null : other.timeZone.getID()) &&
|
other.timeZone == null ? null : other.timeZone.getID()) &&
|
||||||
Objects.equals(escape, other.escape) &&
|
Objects.equals(escape, other.escape) &&
|
||||||
Objects.equals(maxDeterminizedStates, other.maxDeterminizedStates) &&
|
Objects.equals(maxDeterminizedStates, other.maxDeterminizedStates) &&
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
|
|
||||||
private Query combineGrouped(List<? extends Query> groupQuery) {
|
private Query combineGrouped(List<? extends Query> groupQuery) {
|
||||||
if (groupQuery == null || groupQuery.isEmpty()) {
|
if (groupQuery == null || groupQuery.isEmpty()) {
|
||||||
return new MatchNoDocsQuery("[multi_match] list of group queries was empty");
|
return zeroTermsQuery();
|
||||||
}
|
}
|
||||||
if (groupQuery.size() == 1) {
|
if (groupQuery.size() == 1) {
|
||||||
return groupQuery.get(0);
|
return groupQuery.get(0);
|
||||||
|
|
|
@ -347,6 +347,9 @@ public class QueryStringQueryParser extends XQueryParser {
|
||||||
}
|
}
|
||||||
queryBuilder.setPhraseSlop(slop);
|
queryBuilder.setPhraseSlop(slop);
|
||||||
Query query = queryBuilder.parse(MultiMatchQueryBuilder.Type.PHRASE, fields, queryText, null);
|
Query query = queryBuilder.parse(MultiMatchQueryBuilder.Type.PHRASE, fields, queryText, null);
|
||||||
|
if (query == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return applySlop(query, slop);
|
return applySlop(query, slop);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ParseException(e.getMessage());
|
throw new ParseException(e.getMessage());
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.queries.ExtendedCommonTermsQuery;
|
import org.apache.lucene.queries.ExtendedCommonTermsQuery;
|
||||||
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.DisjunctionMaxQuery;
|
import org.apache.lucene.search.DisjunctionMaxQuery;
|
||||||
|
@ -381,6 +382,69 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
|
||||||
assertEquals(expected, query);
|
assertEquals(expected, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWithStopWords() throws Exception {
|
||||||
|
Query query = new MultiMatchQueryBuilder("the quick fox")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
Query expected = new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), BooleanClause.Occur.SHOULD)
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), BooleanClause.Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new MultiMatchQueryBuilder("the quick fox")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new DisjunctionMaxQuery(
|
||||||
|
Arrays.asList(
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), BooleanClause.Occur.SHOULD)
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), BooleanClause.Occur.SHOULD)
|
||||||
|
.build(),
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME_2, "quick")), BooleanClause.Occur.SHOULD)
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME_2, "fox")), BooleanClause.Occur.SHOULD)
|
||||||
|
.build()
|
||||||
|
), 0f);
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new MultiMatchQueryBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new DisjunctionMaxQuery(Arrays.asList(new MatchNoDocsQuery(), new MatchNoDocsQuery()), 0f);
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new BoolQueryBuilder()
|
||||||
|
.should(
|
||||||
|
new MultiMatchQueryBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.analyzer("stop")
|
||||||
|
)
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new BooleanQuery.Builder()
|
||||||
|
.add(new MatchNoDocsQuery(), BooleanClause.Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new BoolQueryBuilder()
|
||||||
|
.should(
|
||||||
|
new MultiMatchQueryBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
)
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new BooleanQuery.Builder()
|
||||||
|
.add(new DisjunctionMaxQuery(Arrays.asList(new MatchNoDocsQuery(), new MatchNoDocsQuery()), 0f), BooleanClause.Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(expected, query);
|
||||||
|
}
|
||||||
|
|
||||||
private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) {
|
private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) {
|
||||||
Settings build = Settings.builder().put(oldIndexSettings)
|
Settings build = Settings.builder().put(oldIndexSettings)
|
||||||
.put(indexSettings)
|
.put(indexSettings)
|
||||||
|
|
|
@ -1266,11 +1266,58 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
.field(STRING_FIELD_NAME)
|
.field(STRING_FIELD_NAME)
|
||||||
.analyzer("stop")
|
.analyzer("stop")
|
||||||
.toQuery(createShardContext());
|
.toQuery(createShardContext());
|
||||||
BooleanQuery expected = new BooleanQuery.Builder()
|
Query expected = new BooleanQuery.Builder()
|
||||||
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), Occur.SHOULD)
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), BooleanClause.Occur.SHOULD)
|
||||||
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), Occur.SHOULD)
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), BooleanClause.Occur.SHOULD)
|
||||||
.build();
|
.build();
|
||||||
assertEquals(expected, query);
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new QueryStringQueryBuilder("the quick fox")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new DisjunctionMaxQuery(
|
||||||
|
Arrays.asList(
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), Occur.SHOULD)
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), Occur.SHOULD)
|
||||||
|
.build(),
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME_2, "quick")), Occur.SHOULD)
|
||||||
|
.add(new TermQuery(new Term(STRING_FIELD_NAME_2, "fox")), Occur.SHOULD)
|
||||||
|
.build()
|
||||||
|
), 0f);
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new QueryStringQueryBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
assertEquals(new BooleanQuery.Builder().build(), query);
|
||||||
|
|
||||||
|
query = new BoolQueryBuilder()
|
||||||
|
.should(
|
||||||
|
new QueryStringQueryBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.analyzer("stop")
|
||||||
|
)
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanQuery.Builder().build(), BooleanClause.Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new BoolQueryBuilder()
|
||||||
|
.should(
|
||||||
|
new QueryStringQueryBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
)
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
assertEquals(expected, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWithPrefixStopWords() throws Exception {
|
public void testWithPrefixStopWords() throws Exception {
|
||||||
|
|
|
@ -613,11 +613,59 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
.field(STRING_FIELD_NAME)
|
.field(STRING_FIELD_NAME)
|
||||||
.analyzer("stop")
|
.analyzer("stop")
|
||||||
.toQuery(createShardContext());
|
.toQuery(createShardContext());
|
||||||
BooleanQuery expected = new BooleanQuery.Builder()
|
Query expected = new BooleanQuery.Builder()
|
||||||
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), BooleanClause.Occur.SHOULD)
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "quick")), BooleanClause.Occur.SHOULD)
|
||||||
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), BooleanClause.Occur.SHOULD)
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "fox")), BooleanClause.Occur.SHOULD)
|
||||||
.build();
|
.build();
|
||||||
assertEquals(expected, query);
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new SimpleQueryStringBuilder("the quick fox")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new BooleanQuery.Builder()
|
||||||
|
.add(new DisjunctionMaxQuery(
|
||||||
|
Arrays.asList(
|
||||||
|
new TermQuery(new Term(STRING_FIELD_NAME, "quick")),
|
||||||
|
new TermQuery(new Term(STRING_FIELD_NAME_2, "quick"))
|
||||||
|
), 1.0f), BooleanClause.Occur.SHOULD)
|
||||||
|
.add(new DisjunctionMaxQuery(
|
||||||
|
Arrays.asList(
|
||||||
|
new TermQuery(new Term(STRING_FIELD_NAME, "fox")),
|
||||||
|
new TermQuery(new Term(STRING_FIELD_NAME_2, "fox"))
|
||||||
|
), 1.0f), BooleanClause.Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new SimpleQueryStringBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
assertEquals(new MatchNoDocsQuery(), query);
|
||||||
|
|
||||||
|
query = new BoolQueryBuilder()
|
||||||
|
.should(
|
||||||
|
new SimpleQueryStringBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.analyzer("stop")
|
||||||
|
)
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
expected = new BooleanQuery.Builder()
|
||||||
|
.add(new MatchNoDocsQuery(), BooleanClause.Occur.SHOULD)
|
||||||
|
.build();
|
||||||
|
assertEquals(expected, query);
|
||||||
|
|
||||||
|
query = new BoolQueryBuilder()
|
||||||
|
.should(
|
||||||
|
new SimpleQueryStringBuilder("the")
|
||||||
|
.field(STRING_FIELD_NAME)
|
||||||
|
.field(STRING_FIELD_NAME_2)
|
||||||
|
.analyzer("stop")
|
||||||
|
)
|
||||||
|
.toQuery(createShardContext());
|
||||||
|
assertEquals(expected, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWithPrefixStopWords() throws Exception {
|
public void testWithPrefixStopWords() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue