diff --git a/docs/changelog/132987.yaml b/docs/changelog/132987.yaml new file mode 100644 index 0000000000000..59772f4841523 --- /dev/null +++ b/docs/changelog/132987.yaml @@ -0,0 +1,7 @@ +pr: 132987 +summary: Rewrite more queries to `match_none` when they target an unmapped field +area: Search +type: enhancement +issues: + - 97129 + - 131037 diff --git a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java index d6422efdfed26..e3f6d36bc7bb7 100644 --- a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java +++ b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java @@ -422,7 +422,9 @@ public void parse(DocumentParserContext context) throws IOException { IndexVersion indexVersion = context.indexSettings().getIndexVersionCreated(); createQueryBuilderField(indexVersion, clusterTransportVersion.get(), queryBuilderField, queryBuilder, context); - QueryBuilder queryBuilderForProcessing = queryBuilder.rewrite(new SearchExecutionContext(executionContext)); + SearchExecutionContext copy = new SearchExecutionContext(executionContext); + configureContext(copy, isMapUnmappedFieldAsText()); + QueryBuilder queryBuilderForProcessing = queryBuilder.rewrite(copy); Query query = queryBuilderForProcessing.toQuery(executionContext); processQuery(query, context); } diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/simple/SimpleSearchIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/simple/SimpleSearchIT.java index 5a9be73d92268..571d5a45e2d5d 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/simple/SimpleSearchIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/simple/SimpleSearchIT.java @@ -473,7 +473,7 @@ public void testTermQueryBigInt() throws Exception { public void testTooLongRegexInRegexpQuery() throws Exception { createIndex("idx"); - indexRandom(true, prepareIndex("idx").setSource("{}", XContentType.JSON)); + indexRandom(true, prepareIndex("idx").setSource("num", "value")); int defaultMaxRegexLength = IndexSettings.MAX_REGEX_LENGTH_SETTING.get(Settings.EMPTY); StringBuilder regexp = new StringBuilder(defaultMaxRegexLength); diff --git a/server/src/main/java/org/elasticsearch/index/query/AbstractGeometryQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/AbstractGeometryQueryBuilder.java index b2a816c9e5690..d40fea479856d 100644 --- a/server/src/main/java/org/elasticsearch/index/query/AbstractGeometryQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/AbstractGeometryQueryBuilder.java @@ -460,6 +460,15 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws }); return newShapeQueryBuilder(this.fieldName, supplier::get, this.indexedShapeId).relation(relation); } + return super.doRewrite(queryRewriteContext); + } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } return this; } diff --git a/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java index a9a49bed3ecc4..57491621bc9ab 100644 --- a/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.XContentBuilder; @@ -161,4 +162,17 @@ protected int doHashCode() { protected boolean doEquals(QB other) { return Objects.equals(fieldName, other.fieldName) && Objects.equals(value, other.value); } + + @Override + protected final QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(this.fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query is against a field that does not exist"); + } + return doIndexMetadataRewrite(context, fieldType); + } + + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context, MappedFieldType fieldType) throws IOException { + return this; + } } diff --git a/server/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java index 13ebb8e19322e..a8b41de5a704d 100644 --- a/server/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java @@ -252,15 +252,12 @@ public String getWriteableName() { } @Override - protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException { - SearchExecutionContext context = queryRewriteContext.convertToSearchExecutionContext(); - if (context != null) { - MappedFieldType fieldType = context.getFieldType(fieldName); - if (fieldType == null) { - return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); - } + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); } - return super.doRewrite(context); + return this; } @Override diff --git a/server/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java index 254f70aeaeba2..eb1ceb44d22c1 100644 --- a/server/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java @@ -384,4 +384,13 @@ public String getWriteableName() { public TransportVersion getMinimalSupportedVersion() { return TransportVersion.zero(); } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } } diff --git a/server/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java index 93e6c0a8bd6b0..8b95097c00637 100644 --- a/server/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java @@ -386,4 +386,13 @@ public String getWriteableName() { public TransportVersion getMinimalSupportedVersion() { return TransportVersion.zero(); } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } } diff --git a/server/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java index d113d6b9ba82b..d2782464a0551 100644 --- a/server/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java @@ -320,4 +320,13 @@ public String getWriteableName() { public TransportVersion getMinimalSupportedVersion() { return TransportVersion.zero(); } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } } diff --git a/server/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java index 2e648652fab63..19b12fc3d07c1 100644 --- a/server/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java @@ -15,6 +15,7 @@ import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.search.MatchQueryParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.XContentBuilder; @@ -287,4 +288,13 @@ public static MatchPhrasePrefixQueryBuilder fromXContent(XContentParser parser) public TransportVersion getMinimalSupportedVersion() { return TransportVersion.zero(); } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } } diff --git a/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java index f943df4b76810..b86ec18276667 100644 --- a/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java @@ -164,6 +164,10 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep @Override protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query is against a field that does not exist"); + } // If we're using the default keyword analyzer then we can rewrite this to a TermQueryBuilder // and possibly shortcut // If we're using a keyword analyzer then we can rewrite this to a TermQueryBuilder diff --git a/server/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java index 56e002287e1e3..5ec9f4e2f269b 100644 --- a/server/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java @@ -366,6 +366,10 @@ public void doXContent(XContentBuilder builder, Params params) throws IOExceptio @Override protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query is against a field that does not exist"); + } if (fuzziness != null || lenient) { // Term queries can be neither fuzzy nor lenient, so don't rewrite under these conditions return this; diff --git a/server/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java index c1787cf0a84cc..d15f481f8202a 100644 --- a/server/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java @@ -480,6 +480,15 @@ protected MappedFieldType.Relation getRelation(final SearchExecutionContext sear ); } + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } + @Override protected QueryBuilder doCoordinatorRewrite(final CoordinatorRewriteContext coordinatorRewriteContext) { return toQueryBuilder(getRelation(coordinatorRewriteContext)); diff --git a/server/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java index 1a0833693ad77..c657c3c1757b0 100644 --- a/server/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java @@ -322,4 +322,13 @@ protected boolean doEquals(RegexpQueryBuilder other) { public TransportVersion getMinimalSupportedVersion() { return TransportVersion.zero(); } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } } diff --git a/server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java index ccb7b0cc28c0b..dba8fdd2ffa45 100644 --- a/server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java @@ -166,11 +166,7 @@ protected void addExtraXContent(XContentBuilder builder, Params params) throws I } @Override - protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) { - MappedFieldType fieldType = context.getFieldType(this.fieldName); - if (fieldType == null) { - return new MatchNoneQueryBuilder("The \"" + getName() + "\" query is against a field that does not exist"); - } + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context, MappedFieldType fieldType) throws IOException { return maybeRewriteBasedOnConstantFields(fieldType, context); } diff --git a/server/src/main/java/org/elasticsearch/index/query/TermsSetQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/TermsSetQueryBuilder.java index b12b417e24aa8..1e3060662e534 100644 --- a/server/src/main/java/org/elasticsearch/index/query/TermsSetQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/TermsSetQueryBuilder.java @@ -266,6 +266,15 @@ public static TermsSetQueryBuilder fromXContent(XContentParser parser) throws IO return queryBuilder; } + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) throws IOException { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } + @Override protected Query doToQuery(SearchExecutionContext context) { if (values.isEmpty()) { diff --git a/server/src/test/java/org/elasticsearch/index/query/RegexpQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/RegexpQueryBuilderTests.java index 62073ef7e451c..420ca2b2291b3 100644 --- a/server/src/test/java/org/elasticsearch/index/query/RegexpQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/RegexpQueryBuilderTests.java @@ -9,10 +9,12 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.RegexpQuery; import org.elasticsearch.common.ParsingException; import org.elasticsearch.core.Strings; +import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.test.AbstractQueryTestCase; import java.io.IOException; @@ -72,11 +74,15 @@ private static RegexpQueryBuilder randomRegexpQuery() { @Override protected void doAssertLuceneQuery(RegexpQueryBuilder queryBuilder, Query query, SearchExecutionContext context) throws IOException { - assertThat(query, instanceOf(RegexpQuery.class)); - RegexpQuery regexpQuery = (RegexpQuery) query; - - String expectedFieldName = expectedFieldName(queryBuilder.fieldName()); - assertThat(regexpQuery.getField(), equalTo(expectedFieldName)); + MappedFieldType fieldType = context.getFieldType(queryBuilder.fieldName()); + if (fieldType == null) { + assertThat(query, instanceOf(MatchNoDocsQuery.class)); + } else { + assertThat(query, instanceOf(RegexpQuery.class)); + RegexpQuery regexpQuery = (RegexpQuery) query; + String expectedFieldName = expectedFieldName(queryBuilder.fieldName()); + assertThat(regexpQuery.getField(), equalTo(expectedFieldName)); + } } public void testIllegalArguments() { diff --git a/server/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java index c4a9267ff68a0..c548fbbed7eb2 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java @@ -12,12 +12,12 @@ import org.apache.lucene.index.Term; import org.apache.lucene.queries.spans.SpanTermQuery; import org.apache.lucene.search.BoostQuery; +import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.elasticsearch.common.ParsingException; import org.elasticsearch.index.mapper.IdFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; -import org.elasticsearch.lucene.queries.SpanMatchNoDocsQuery; import org.elasticsearch.xcontent.json.JsonStringEncoder; import java.io.IOException; @@ -58,7 +58,7 @@ protected void doAssertLuceneQuery(SpanTermQueryBuilder queryBuilder, Query quer Term term = ((TermQuery) mapper.termQuery(queryBuilder.value(), null)).getTerm(); assertThat(spanTermQuery.getTerm(), equalTo(term)); } else { - assertThat(query, instanceOf(SpanMatchNoDocsQuery.class)); + assertThat(query, instanceOf(MatchNoDocsQuery.class)); } } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/query/GeoGridQueryBuilder.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/query/GeoGridQueryBuilder.java index 8e73fc37f96ba..bf31c779190b3 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/query/GeoGridQueryBuilder.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/query/GeoGridQueryBuilder.java @@ -27,6 +27,9 @@ import org.elasticsearch.index.mapper.GeoShapeQueryable; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.query.AbstractQueryBuilder; +import org.elasticsearch.index.query.MatchNoneQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryRewriteContext; import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils; @@ -402,4 +405,13 @@ public String getWriteableName() { public TransportVersion getMinimalSupportedVersion() { return TransportVersions.V_8_3_0; } + + @Override + protected QueryBuilder doIndexMetadataRewrite(QueryRewriteContext context) { + MappedFieldType fieldType = context.getFieldType(fieldName); + if (fieldType == null) { + return new MatchNoneQueryBuilder("The \"" + getName() + "\" query was rewritten to a \"match_none\" query."); + } + return this; + } }