Full text queries should not always ignore unmapped fields (#41062)

Full text queries ignore unmapped fields since https://github.com/elastic/elasticsearch/issues/41022
even if all fields in the query are unmapped.
This change makes sure that we ignore unmapped fields only if they are mixed
with mapped fields and returns a MatchNoDocsQuery otherwise.

Closes #41022
This commit is contained in:
Jim Ferenczi 2019-04-15 09:46:50 +02:00 committed by jimczi
parent fe9442b05b
commit d30fec4914
4 changed files with 53 additions and 5 deletions

View File

@ -36,6 +36,8 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.mapper.SeqNoFieldMapper;
import org.elasticsearch.index.mapper.TypeFieldMapper;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@ -52,7 +54,11 @@ public class Queries {
public static Query newUnmappedFieldQuery(String field) {
return Queries.newMatchNoDocsQuery("unmapped field [" + (field != null ? field : "null") + "]");
return newUnmappedFieldsQuery(Collections.singletonList(field));
}
public static Query newUnmappedFieldsQuery(Collection<String> fields) {
return Queries.newMatchNoDocsQuery("unmapped fields " + fields);
}
public static Query newLenientFieldQuery(String field, RuntimeException e) {

View File

@ -59,6 +59,12 @@ public class MultiMatchQuery extends MatchQuery {
public Query parse(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames,
Object value, String minimumShouldMatch) throws IOException {
boolean hasMappedField = fieldNames.keySet().stream()
.anyMatch(k -> context.fieldMapper(k) != null);
if (hasMappedField == false) {
// all query fields are unmapped
return Queries.newUnmappedFieldsQuery(fieldNames.keySet());
}
final float tieBreaker = groupTieBreaker == null ? type.tieBreaker() : groupTieBreaker;
final List<Query> queries;
switch (type) {
@ -91,7 +97,7 @@ public class MultiMatchQuery extends MatchQuery {
}
private List<Query> buildFieldQueries(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames,
Object value, String minimumShouldMatch) throws IOException{
Object value, String minimumShouldMatch) throws IOException {
List<Query> queries = new ArrayList<>();
for (String fieldName : fieldNames.keySet()) {
if (context.fieldMapper(fieldName) == null) {

View File

@ -1210,13 +1210,13 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
.field("unmapped_field")
.lenient(true)
.toQuery(createShardContext());
assertEquals(new BooleanQuery.Builder().build(), query);
assertEquals(new MatchNoDocsQuery(), query);
// Unmapped prefix field
query = new QueryStringQueryBuilder("unmapped_field:hello")
.lenient(true)
.toQuery(createShardContext());
assertEquals(new BooleanQuery.Builder().build(), query);
assertEquals(new MatchNoDocsQuery(), query);
// Unmapped fields
query = new QueryStringQueryBuilder("hello")
@ -1224,7 +1224,32 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
.field("unmapped_field")
.field("another_field")
.toQuery(createShardContext());
assertEquals(new BooleanQuery.Builder().build(), query);
assertEquals(new MatchNoDocsQuery(), query);
// Multi block
query = new QueryStringQueryBuilder("first unmapped:second")
.field(STRING_FIELD_NAME)
.field("unmapped")
.field("another_unmapped")
.defaultOperator(Operator.AND)
.toQuery(createShardContext());
BooleanQuery expected = new BooleanQuery.Builder()
.add(new TermQuery(new Term(STRING_FIELD_NAME, "first")), BooleanClause.Occur.MUST)
.add(new MatchNoDocsQuery(), BooleanClause.Occur.MUST)
.build();
assertEquals(expected, query);
query = new SimpleQueryStringBuilder("first unknown:second")
.field("unmapped")
.field("another_unmapped")
.defaultOperator(Operator.AND)
.toQuery(createShardContext());
expected = new BooleanQuery.Builder()
.add(new MatchNoDocsQuery(), BooleanClause.Occur.MUST)
.add(new MatchNoDocsQuery(), BooleanClause.Occur.MUST)
.build();
assertEquals(expected, query);
}
public void testDefaultField() throws Exception {

View File

@ -717,6 +717,17 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
.add(new TermQuery(new Term(STRING_FIELD_NAME, "second")), BooleanClause.Occur.MUST)
.build();
assertEquals(expected, query);
query = new SimpleQueryStringBuilder("first & second")
.field("unmapped")
.field("another_unmapped")
.defaultOperator(Operator.AND)
.toQuery(createShardContext());
expected = new BooleanQuery.Builder()
.add(new MatchNoDocsQuery(), BooleanClause.Occur.MUST)
.add(new MatchNoDocsQuery(), BooleanClause.Occur.MUST)
.add(new MatchNoDocsQuery(), BooleanClause.Occur.MUST)
.build();
assertEquals(expected, query);
}
public void testNegativeFieldBoost() {