Exists queries to MatchNoneQueryBuilder when the field is unmapped (#55785)

Co-authored-by: Sivagurunathan Velayutham <sivadeva.93@gmail.com>

Closes #54062
This commit is contained in:
Adrien Grand 2020-04-27 11:06:50 +02:00 committed by GitHub
parent 4403b69048
commit 0753d9a35c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 18 deletions

View File

@ -80,6 +80,18 @@ public class ExistsQueryBuilder extends AbstractQueryBuilder<ExistsQueryBuilder>
return this.fieldName;
}
@Override
protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
QueryShardContext context = queryShardContext.convertToShardContext();
if (context != null) {
Collection<String> fields = getMappedField(context, fieldName);
if (fields.isEmpty()) {
return new MatchNoneQueryBuilder();
}
}
return super.doRewrite(queryShardContext);
}
@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME);
@ -132,20 +144,10 @@ public class ExistsQueryBuilder extends AbstractQueryBuilder<ExistsQueryBuilder>
public static Query newFilter(QueryShardContext context, String fieldPattern) {
final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = (FieldNamesFieldMapper.FieldNamesFieldType) context
.getMapperService().fieldType(FieldNamesFieldMapper.NAME);
if (fieldNamesFieldType == null) {
// can only happen when no types exist, so no docs exist either
return Queries.newMatchNoDocsQuery("Missing types in \"" + NAME + "\" query.");
}
Collection<String> fields = getMappedField(context, fieldPattern);
final Collection<String> fields;
if (context.getObjectMapper(fieldPattern) != null) {
// the _field_names field also indexes objects, so we don't have to
// do any more work to support exists queries on whole objects
fields = Collections.singleton(fieldPattern);
} else {
fields = context.simpleMatchToIndexNames(fieldPattern);
if (fields.isEmpty()) {
throw new IllegalStateException("Rewrite first");
}
if (context.indexVersionCreated().before(Version.V_6_1_0)) {
@ -194,7 +196,7 @@ public class ExistsQueryBuilder extends AbstractQueryBuilder<ExistsQueryBuilder>
if (context.getObjectMapper(field) != null) {
return newObjectFieldExistsQuery(context, field);
}
return Queries.newMatchNoDocsQuery("No field \"" + field + "\" exists in mappings.");
return Queries.newMatchNoDocsQuery("User requested \"match_none\" query.");
}
Query filter = fieldType.existsQuery(context);
return new ConstantScoreQuery(filter);
@ -210,6 +212,43 @@ public class ExistsQueryBuilder extends AbstractQueryBuilder<ExistsQueryBuilder>
return new ConstantScoreQuery(booleanQuery.build());
}
/**
* Helper method to get field mapped to this fieldPattern
* @return return collection of fields if exists else return empty.
*/
private static Collection<String> getMappedField(QueryShardContext context, String fieldPattern) {
final FieldNamesFieldMapper.FieldNamesFieldType fieldNamesFieldType = (FieldNamesFieldMapper.FieldNamesFieldType) context
.getMapperService().fieldType(FieldNamesFieldMapper.NAME);
if (fieldNamesFieldType == null) {
// can only happen when no types exist, so no docs exist either
return Collections.emptySet();
}
final Collection<String> fields;
if (context.getObjectMapper(fieldPattern) != null) {
// the _field_names field also indexes objects, so we don't have to
// do any more work to support exists queries on whole objects
fields = Collections.singleton(fieldPattern);
} else {
fields = context.simpleMatchToIndexNames(fieldPattern);
}
if (fields.size() == 1) {
String field = fields.iterator().next();
MappedFieldType fieldType = context.getMapperService().fieldType(field);
if (fieldType == null) {
// The field does not exist as a leaf but could be an object so
// check for an object mapper
if (context.getObjectMapper(field) == null) {
return Collections.emptySet();
}
}
}
return fields;
}
@Override
protected int doHashCode() {
return Objects.hash(fieldName);

View File

@ -36,7 +36,6 @@ import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
@ -83,11 +82,9 @@ public class ExistsQueryBuilderTests extends AbstractQueryTestCase<ExistsQueryBu
assertThat(booleanClause.getOccur(), equalTo(BooleanClause.Occur.SHOULD));
}
}
} else if (fields.size() == 1 && mappedFields.size() == 0) {
} else if (mappedFields.size() == 0) {
assertThat(query, instanceOf(MatchNoDocsQuery.class));
MatchNoDocsQuery matchNoDocsQuery = (MatchNoDocsQuery) query;
assertThat(matchNoDocsQuery.toString(null),
containsString("No field \"" + fields.iterator().next() + "\" exists in mappings."));
} else if (fields.size() == 1) {
assertThat(query, instanceOf(ConstantScoreQuery.class));
ConstantScoreQuery constantScoreQuery = (ConstantScoreQuery) query;
@ -128,6 +125,16 @@ public class ExistsQueryBuilderTests extends AbstractQueryTestCase<ExistsQueryBu
}
}
@Override
public void testMustRewrite() throws IOException {
QueryShardContext context = createShardContext();
context.setAllowUnmappedFields(true);
ExistsQueryBuilder queryBuilder = new ExistsQueryBuilder("foo");
IllegalStateException e = expectThrows(IllegalStateException.class,
() -> queryBuilder.toQuery(context));
assertEquals("Rewrite first", e.getMessage());
}
public void testIllegalArguments() {
expectThrows(IllegalArgumentException.class, () -> new ExistsQueryBuilder((String) null));
expectThrows(IllegalArgumentException.class, () -> new ExistsQueryBuilder(""));