From f2e11ae5a44002dfc02e18c34cbb9a609525f440 Mon Sep 17 00:00:00 2001 From: Aurelien FOUCRET Date: Fri, 8 Nov 2024 18:01:35 +0100 Subject: [PATCH] More testing. --- .../index/query/NestedQueryBuilder.java | 7 ++ .../kql/parser/AbstractKqlParserTestCase.java | 39 --------- .../kql/parser/KqlNestedFieldQueryTests.java | 81 ++++++++++++++++++- .../kql/parser/KqlParserExistsQueryTests.java | 3 +- 4 files changed, 86 insertions(+), 44 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java index 626875c75a5fe..83bca7d27aeeb 100644 --- a/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java @@ -112,6 +112,13 @@ public QueryBuilder query() { return query; } + /** + * Returns path to the searched nested object. + */ + public String path() { + return path; + } + /** * Returns inner hit definition in the scope of this query and reusing the defined type and query. */ diff --git a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java index cfb3ca7fed5e4..e6e4e20cfd3ca 100644 --- a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java +++ b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/AbstractKqlParserTestCase.java @@ -46,48 +46,9 @@ import static org.hamcrest.Matchers.equalTo; public abstract class AbstractKqlParserTestCase extends AbstractBuilderTestCase { - - protected static final String NESTED_FIELD_NAME = "mapped_nested"; - - @Override - protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { - XContentBuilder mapping = jsonBuilder().startObject().startObject("_doc").startObject("properties"); - - mapping.startObject(TEXT_FIELD_NAME).field("type", "text").endObject(); - mapping.startObject(NESTED_FIELD_NAME); - { - mapping.field("type", "nested"); - mapping.startObject("properties"); - { - mapping.startObject(TEXT_FIELD_NAME).field("type", "text").endObject(); - mapping.startObject(KEYWORD_FIELD_NAME).field("type", "keyword").endObject(); - mapping.startObject(INT_FIELD_NAME).field("type", "integer").endObject(); - mapping.startObject(NESTED_FIELD_NAME); - { - mapping.field("type", "nested"); - mapping.startObject("properties"); - { - mapping.startObject(TEXT_FIELD_NAME).field("type", "text").endObject(); - mapping.startObject(KEYWORD_FIELD_NAME).field("type", "keyword").endObject(); - mapping.startObject(INT_FIELD_NAME).field("type", "integer").endObject(); - } - mapping.endObject(); - } - mapping.endObject(); - } - mapping.endObject(); - } - mapping.endObject(); - - mapping.endObject().endObject().endObject(); - - mapperService.merge("_doc", new CompressedXContent(Strings.toString(mapping)), MapperService.MergeReason.MAPPING_UPDATE); - } - protected static final String SUPPORTED_QUERY_FILE_PATH = "/supported-queries"; protected static final String UNSUPPORTED_QUERY_FILE_PATH = "/unsupported-queries"; protected static final Predicate BOOLEAN_QUERY_FILTER = (q) -> q.matches("(?i)[^{]*[^\\\\]*(NOT|AND|OR)[^}]*"); - protected static final String NESTED_FIELD_NAME = "mapped_nested"; @Override diff --git a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java index 8f58c202c05e7..6625f09cd5f54 100644 --- a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java +++ b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlNestedFieldQueryTests.java @@ -7,21 +7,94 @@ package org.elasticsearch.xpack.kql.parser; -import org.elasticsearch.common.Strings; +import org.elasticsearch.index.query.NestedQueryBuilder; +import org.elasticsearch.test.ESTestCase; import org.hamcrest.Matchers; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class KqlNestedFieldQueryTests extends AbstractKqlParserTestCase { +import static org.elasticsearch.common.Strings.format; +import static org.hamcrest.Matchers.equalTo; +public class KqlNestedFieldQueryTests extends AbstractKqlParserTestCase { public void testInvalidNestedFieldName() { - for (String invalidFieldName : List.of(TEXT_FIELD_NAME, "not_a_field", "mapped_nest*")) { + for (String invalidFieldName : List.of(OBJECT_FIELD_NAME, TEXT_FIELD_NAME, "not_a_field", "mapped_nest*")) { KqlParsingException e = assertThrows( KqlParsingException.class, - () -> parseKqlQuery(Strings.format("%s : { %s: foo AND %s < 10 } ", invalidFieldName, TEXT_FIELD_NAME, INT_FIELD_NAME)) + () -> parseKqlQuery(format("%s : { %s: foo AND %s < 10 } ", invalidFieldName, TEXT_FIELD_NAME, INT_FIELD_NAME)) ); assertThat(e.getMessage(), Matchers.containsString(invalidFieldName)); assertThat(e.getMessage(), Matchers.containsString("is not a valid nested field name")); } } + + public void testInlineNestedFieldMatchTextQuery() { + for (String fieldName : List.of(TEXT_FIELD_NAME, INT_FIELD_NAME)) { + { + // Querying a nested text subfield. + String nestedFieldName = format("%s.%s", NESTED_FIELD_NAME, fieldName); + String searchTerms = Stream.generate(ESTestCase::randomIdentifier) + .limit(randomIntBetween(1, 10)) + .collect(Collectors.joining(" ")); + String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms); + + NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString)); + + assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME)); + assertMatchQueryBuilder(nestedQuery.query(), nestedFieldName, searchTerms); + } + + { + // Several levels of nested fields. + String nestedFieldName = format("%s.%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME, fieldName); + String searchTerms = Stream.generate(ESTestCase::randomIdentifier) + .limit(randomIntBetween(1, 10)) + .collect(Collectors.joining(" ")); + String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms); + + NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString)); + assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME)); + + NestedQueryBuilder nestedSubQuery = asInstanceOf(NestedQueryBuilder.class, nestedQuery.query()); + assertThat(nestedSubQuery.path(), equalTo(format("%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME))); + + assertMatchQueryBuilder(nestedSubQuery.query(), nestedFieldName, searchTerms); + } + } + } + + public void testInlineNestedFieldMatchKeywordFieldQuery() { + { + // Querying a nested text subfield. + String nestedFieldName = format("%s.%s", NESTED_FIELD_NAME, KEYWORD_FIELD_NAME); + String searchTerms = Stream.generate(ESTestCase::randomIdentifier) + .limit(randomIntBetween(1, 10)) + .collect(Collectors.joining(" ")); + String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms); + + NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString)); + + assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME)); + assertTermQueryBuilder(nestedQuery.query(), nestedFieldName, searchTerms); + } + + { + // Several levels of nested fields. + String nestedFieldName = format("%s.%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME, KEYWORD_FIELD_NAME); + String searchTerms = Stream.generate(ESTestCase::randomIdentifier) + .limit(randomIntBetween(1, 10)) + .collect(Collectors.joining(" ")); + String kqlQueryString = format("%s: %s", nestedFieldName, searchTerms); + + NestedQueryBuilder nestedQuery = asInstanceOf(NestedQueryBuilder.class, parseKqlQuery(kqlQueryString)); + assertThat(nestedQuery.path(), equalTo(NESTED_FIELD_NAME)); + + NestedQueryBuilder nestedSubQuery = asInstanceOf(NestedQueryBuilder.class, nestedQuery.query()); + assertThat(nestedSubQuery.path(), equalTo(format("%s.%s", NESTED_FIELD_NAME, NESTED_FIELD_NAME))); + + assertTermQueryBuilder(nestedSubQuery.query(), nestedFieldName, searchTerms); + } + } } diff --git a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java index 22c18100679d6..6415cdb94ada7 100644 --- a/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java +++ b/x-pack/plugin/kql/src/test/java/org/elasticsearch/xpack/kql/parser/KqlParserExistsQueryTests.java @@ -64,7 +64,8 @@ public void testParseExistsQueryUsingWildcardFieldName() { assertThat( parsedQuery.should(), containsInAnyOrder( - searchableFields(fieldNamePattern).stream().map(fieldName -> parseKqlQuery(kqlExistsQuery(fieldName))).toArray()) + searchableFields(fieldNamePattern).stream().map(fieldName -> parseKqlQuery(kqlExistsQuery(fieldName))).toArray() + ) ); }