Limit the number of expanded fields it query_string and simple_query_string (#26541)
* Limit the number of expanded fields it query_string and simple_query_string This limits the number of automatically expanded fields for the "all fields" mode (`"default_field": "*"`) for the `query_string` and `simple_query_string` queries to 1024 fields. Resolves #25105 * Add blurb about limit to the docs
This commit is contained in:
parent
dd90cf1bbb
commit
2702918780
|
@ -124,6 +124,7 @@ public final class QueryParserHelper {
|
||||||
!multiField, !allField, fieldSuffix);
|
!multiField, !allField, fieldSuffix);
|
||||||
resolvedFields.putAll(fieldMap);
|
resolvedFields.putAll(fieldMap);
|
||||||
}
|
}
|
||||||
|
checkForTooManyFields(resolvedFields);
|
||||||
return resolvedFields;
|
return resolvedFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +185,13 @@ public final class QueryParserHelper {
|
||||||
}
|
}
|
||||||
fields.put(fieldName, weight);
|
fields.put(fieldName, weight);
|
||||||
}
|
}
|
||||||
|
checkForTooManyFields(fields);
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void checkForTooManyFields(Map<String, Float> fields) {
|
||||||
|
if (fields.size() > 1024) {
|
||||||
|
throw new IllegalArgumentException("field expansion matches too many fields, limit: 1024, got: " + fields.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.query.Operator;
|
import org.elasticsearch.index.query.Operator;
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.index.query.QueryStringQueryBuilder;
|
import org.elasticsearch.index.query.QueryStringQueryBuilder;
|
||||||
|
@ -46,6 +47,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
||||||
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
|
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||||
|
@ -351,6 +353,37 @@ public class QueryStringIT extends ESIntegTestCase {
|
||||||
assertSearchHits(searchResponse, "1", "2", "3");
|
assertSearchHits(searchResponse, "1", "2", "3");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLimitOnExpandedFields() throws Exception {
|
||||||
|
XContentBuilder builder = jsonBuilder();
|
||||||
|
builder.startObject();
|
||||||
|
builder.startObject("type1");
|
||||||
|
builder.startObject("properties");
|
||||||
|
for (int i = 0; i < 1025; i++) {
|
||||||
|
builder.startObject("field" + i).field("type", "text").endObject();
|
||||||
|
}
|
||||||
|
builder.endObject(); // properties
|
||||||
|
builder.endObject(); // type1
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
assertAcked(prepareCreate("toomanyfields")
|
||||||
|
.setSettings(Settings.builder().put(MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING.getKey(), 1200))
|
||||||
|
.addMapping("type1", builder));
|
||||||
|
|
||||||
|
client().prepareIndex("toomanyfields", "type1", "1").setSource("field171", "foo bar baz").get();
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
Exception e = expectThrows(Exception.class, () -> {
|
||||||
|
QueryStringQueryBuilder qb = queryStringQuery("bar");
|
||||||
|
if (randomBoolean()) {
|
||||||
|
qb.useAllFields(true);
|
||||||
|
}
|
||||||
|
logger.info("--> using {}", qb);
|
||||||
|
client().prepareSearch("toomanyfields").setQuery(qb).get();
|
||||||
|
});
|
||||||
|
assertThat(ExceptionsHelper.detailedMessage(e),
|
||||||
|
containsString("field expansion matches too many fields, limit: 1024, got: 1025"));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertHits(SearchHits hits, String... ids) {
|
private void assertHits(SearchHits hits, String... ids) {
|
||||||
assertThat(hits.getTotalHits(), equalTo((long) ids.length));
|
assertThat(hits.getTotalHits(), equalTo((long) ids.length));
|
||||||
Set<String> hitIds = new HashSet<>();
|
Set<String> hitIds = new HashSet<>();
|
||||||
|
|
|
@ -24,11 +24,15 @@ import org.elasticsearch.ExceptionsHelper;
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
||||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
import org.elasticsearch.index.query.Operator;
|
import org.elasticsearch.index.query.Operator;
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.elasticsearch.index.query.SimpleQueryStringBuilder;
|
||||||
import org.elasticsearch.index.query.SimpleQueryStringFlag;
|
import org.elasticsearch.index.query.SimpleQueryStringFlag;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
|
@ -540,6 +544,38 @@ public class SimpleQueryStringIT extends ESIntegTestCase {
|
||||||
containsString("NumberFormatException[For input string: \"foo123\"]"));
|
containsString("NumberFormatException[For input string: \"foo123\"]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testLimitOnExpandedFields() throws Exception {
|
||||||
|
XContentBuilder builder = jsonBuilder();
|
||||||
|
builder.startObject();
|
||||||
|
builder.startObject("type1");
|
||||||
|
builder.startObject("properties");
|
||||||
|
for (int i = 0; i < 1025; i++) {
|
||||||
|
builder.startObject("field" + i).field("type", "text").endObject();
|
||||||
|
}
|
||||||
|
builder.endObject(); // properties
|
||||||
|
builder.endObject(); // type1
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
assertAcked(prepareCreate("toomanyfields")
|
||||||
|
.setSettings(Settings.builder().put(MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING.getKey(), 1200))
|
||||||
|
.addMapping("type1", builder));
|
||||||
|
|
||||||
|
client().prepareIndex("toomanyfields", "type1", "1").setSource("field171", "foo bar baz").get();
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
Exception e = expectThrows(Exception.class, () -> {
|
||||||
|
SimpleQueryStringBuilder qb = simpleQueryStringQuery("bar");
|
||||||
|
if (randomBoolean()) {
|
||||||
|
qb.useAllFields(true);
|
||||||
|
}
|
||||||
|
logger.info("--> using {}", qb);
|
||||||
|
client().prepareSearch("toomanyfields").setQuery(qb).get();
|
||||||
|
});
|
||||||
|
assertThat(ExceptionsHelper.detailedMessage(e),
|
||||||
|
containsString("field expansion matches too many fields, limit: 1024, got: 1025"));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertHits(SearchHits hits, String... ids) {
|
private void assertHits(SearchHits hits, String... ids) {
|
||||||
assertThat(hits.getTotalHits(), equalTo((long) ids.length));
|
assertThat(hits.getTotalHits(), equalTo((long) ids.length));
|
||||||
Set<String> hitIds = new HashSet<>();
|
Set<String> hitIds = new HashSet<>();
|
||||||
|
|
|
@ -48,12 +48,12 @@ The `query_string` top level parameters include:
|
||||||
|Parameter |Description
|
|Parameter |Description
|
||||||
|`query` |The actual query to be parsed. See <<query-string-syntax>>.
|
|`query` |The actual query to be parsed. See <<query-string-syntax>>.
|
||||||
|
|
||||||
|`default_field` |The default field for query terms if no prefix field
|
|`default_field` |The default field for query terms if no prefix field is
|
||||||
is specified. Defaults to the `index.query.default_field` index
|
specified. Defaults to the `index.query.default_field` index settings, which in
|
||||||
settings, which in turn defaults to `*`.
|
turn defaults to `*`. `*` extracts all fields in the mapping that are eligible
|
||||||
`*` extracts all fields in the mapping that are eligible to term queries
|
to term queries and filters the metadata fields. All extracted fields are then
|
||||||
and filters the metadata fields. All extracted fields are then combined
|
combined to build a query when no prefix field is provided. There is a limit of
|
||||||
to build a query when no prefix field is provided.
|
no more than 1024 fields being queried at once.
|
||||||
|
|
||||||
|`default_operator` |The default operator used if no explicit operator
|
|`default_operator` |The default operator used if no explicit operator
|
||||||
is specified. For example, with a default operator of `OR`, the query
|
is specified. For example, with a default operator of `OR`, the query
|
||||||
|
|
|
@ -29,9 +29,10 @@ The `simple_query_string` top level parameters include:
|
||||||
|`query` |The actual query to be parsed. See below for syntax.
|
|`query` |The actual query to be parsed. See below for syntax.
|
||||||
|
|
||||||
|`fields` |The fields to perform the parsed query against. Defaults to the
|
|`fields` |The fields to perform the parsed query against. Defaults to the
|
||||||
`index.query.default_field` index settings, which in turn defaults to `*`.
|
`index.query.default_field` index settings, which in turn defaults to `*`. `*`
|
||||||
`*` extracts all fields in the mapping that are eligible to term queries
|
extracts all fields in the mapping that are eligible to term queries and filters
|
||||||
and filters the metadata fields.
|
the metadata fields. There is a limit of no more than 1024 fields being queried
|
||||||
|
at once.
|
||||||
|
|
||||||
|`default_operator` |The default operator used if no explicit operator
|
|`default_operator` |The default operator used if no explicit operator
|
||||||
is specified. For example, with a default operator of `OR`, the query
|
is specified. For example, with a default operator of `OR`, the query
|
||||||
|
|
Loading…
Reference in New Issue