From 753847b3652a0f4f3c291e8ee3d9380edaf32f14 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:43:50 -0800 Subject: [PATCH] Validate field and fields parameters in relevance search functions (#1067) (#1199) Change relevance functions that query fields to throw a SemanticCheckException when a field is queried that does not exist. Signed-off-by: forestmvey (cherry picked from commit d03c176c10f6914a0efe972535bd3565b86fe077) Co-authored-by: Forest Vey <36905077+forestmvey@users.noreply.github.com> --- .../function/OpenSearchFunctions.java | 22 +++---- .../function/RelevanceFunctionResolver.java | 11 ---- .../sql/analysis/ExpressionAnalyzerTest.java | 50 +++++++------- .../org/opensearch/sql/config/TestConfig.java | 2 + .../RelevanceFunctionResolverTest.java | 11 +--- .../java/org/opensearch/sql/sql/MatchIT.java | 37 +++++++++++ .../lucene/relevance/SingleFieldQuery.java | 3 +- .../script/filter/FilterQueryBuilderTest.java | 66 +++++++++++-------- .../lucene/MatchBoolPrefixQueryTest.java | 11 +++- .../lucene/MatchPhrasePrefixQueryTest.java | 26 +++++--- .../filter/lucene/MatchPhraseQueryTest.java | 65 ++++++++++++------ .../script/filter/lucene/MatchQueryTest.java | 53 ++++++++++----- .../filter/lucene/WildcardQueryTest.java | 11 +++- .../relevance/SingleFieldQueryTest.java | 20 +++++- .../sql/ppl/parser/AstExpressionBuilder.java | 2 +- .../ppl/parser/AstExpressionBuilderTest.java | 2 +- .../sql/sql/parser/AstExpressionBuilder.java | 2 +- .../sql/parser/AstExpressionBuilderTest.java | 18 ++--- 18 files changed, 259 insertions(+), 153 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/function/OpenSearchFunctions.java b/core/src/main/java/org/opensearch/sql/expression/function/OpenSearchFunctions.java index d8efe42640..842cf25cd6 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/OpenSearchFunctions.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/OpenSearchFunctions.java @@ -5,10 +5,6 @@ package org.opensearch.sql.expression.function; -import static org.opensearch.sql.data.type.ExprCoreType.STRING; -import static org.opensearch.sql.data.type.ExprCoreType.STRUCT; - -import com.google.common.collect.ImmutableMap; import java.util.List; import java.util.stream.Collectors; import lombok.experimental.UtilityClass; @@ -48,46 +44,46 @@ public void register(BuiltinFunctionRepository repository) { private static FunctionResolver match_bool_prefix() { FunctionName name = BuiltinFunctionName.MATCH_BOOL_PREFIX.getName(); - return new RelevanceFunctionResolver(name, STRING); + return new RelevanceFunctionResolver(name); } private static FunctionResolver match(BuiltinFunctionName match) { FunctionName funcName = match.getName(); - return new RelevanceFunctionResolver(funcName, STRING); + return new RelevanceFunctionResolver(funcName); } private static FunctionResolver match_phrase_prefix() { FunctionName funcName = BuiltinFunctionName.MATCH_PHRASE_PREFIX.getName(); - return new RelevanceFunctionResolver(funcName, STRING); + return new RelevanceFunctionResolver(funcName); } private static FunctionResolver match_phrase(BuiltinFunctionName matchPhrase) { FunctionName funcName = matchPhrase.getName(); - return new RelevanceFunctionResolver(funcName, STRING); + return new RelevanceFunctionResolver(funcName); } private static FunctionResolver multi_match(BuiltinFunctionName multiMatchName) { - return new RelevanceFunctionResolver(multiMatchName.getName(), STRUCT); + return new RelevanceFunctionResolver(multiMatchName.getName()); } private static FunctionResolver simple_query_string() { FunctionName funcName = BuiltinFunctionName.SIMPLE_QUERY_STRING.getName(); - return new RelevanceFunctionResolver(funcName, STRUCT); + return new RelevanceFunctionResolver(funcName); } private static FunctionResolver query() { FunctionName funcName = BuiltinFunctionName.QUERY.getName(); - return new RelevanceFunctionResolver(funcName, STRING); + return new RelevanceFunctionResolver(funcName); } private static FunctionResolver query_string() { FunctionName funcName = BuiltinFunctionName.QUERY_STRING.getName(); - return new RelevanceFunctionResolver(funcName, STRUCT); + return new RelevanceFunctionResolver(funcName); } private static FunctionResolver wildcard_query(BuiltinFunctionName wildcardQuery) { FunctionName funcName = wildcardQuery.getName(); - return new RelevanceFunctionResolver(funcName, STRING); + return new RelevanceFunctionResolver(funcName); } public static class OpenSearchFunction extends FunctionExpression { diff --git a/core/src/main/java/org/opensearch/sql/expression/function/RelevanceFunctionResolver.java b/core/src/main/java/org/opensearch/sql/expression/function/RelevanceFunctionResolver.java index 7066622e1b..ef0ac9226c 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/RelevanceFunctionResolver.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/RelevanceFunctionResolver.java @@ -20,9 +20,6 @@ public class RelevanceFunctionResolver @Getter private final FunctionName functionName; - @Getter - private final ExprType declaredFirstParamType; - @Override public Pair resolve(FunctionSignature unresolvedSignature) { if (!unresolvedSignature.getFunctionName().equals(functionName)) { @@ -30,14 +27,6 @@ public Pair resolve(FunctionSignature unreso functionName.getFunctionName(), unresolvedSignature.getFunctionName().getFunctionName())); } List paramTypes = unresolvedSignature.getParamTypeList(); - ExprType providedFirstParamType = paramTypes.get(0); - - // Check if the first parameter is of the specified type. - if (!declaredFirstParamType.equals(providedFirstParamType)) { - throw new SemanticCheckException( - getWrongParameterErrorMessage(0, providedFirstParamType, declaredFirstParamType)); - } - // Check if all but the first parameter are of type STRING. for (int i = 1; i < paramTypes.size(); i++) { ExprType paramType = paramTypes.get(i); diff --git a/core/src/test/java/org/opensearch/sql/analysis/ExpressionAnalyzerTest.java b/core/src/test/java/org/opensearch/sql/analysis/ExpressionAnalyzerTest.java index a69b27fc61..5a8ae6b8cd 100644 --- a/core/src/test/java/org/opensearch/sql/analysis/ExpressionAnalyzerTest.java +++ b/core/src/test/java/org/opensearch/sql/analysis/ExpressionAnalyzerTest.java @@ -374,10 +374,10 @@ public void named_non_parse_expression() { void match_bool_prefix_expression() { assertAnalyzeEqual( DSL.match_bool_prefix( - DSL.namedArgument("field", DSL.literal("fieldA")), + DSL.namedArgument("field", DSL.literal("field_value1")), DSL.namedArgument("query", DSL.literal("sample query"))), AstDSL.function("match_bool_prefix", - AstDSL.unresolvedArg("field", stringLiteral("fieldA")), + AstDSL.unresolvedArg("field", stringLiteral("field_value1")), AstDSL.unresolvedArg("query", stringLiteral("sample query")))); } @@ -418,11 +418,11 @@ void multi_match_expression() { DSL.multi_match( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field", ExprValueUtils.floatValue(1.F)))))), + "field_value1", ExprValueUtils.floatValue(1.F)))))), DSL.namedArgument("query", DSL.literal("sample query"))), AstDSL.function("multi_match", AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of( - "field", 1.F))), + "field_value1", 1.F))), AstDSL.unresolvedArg("query", stringLiteral("sample query")))); } @@ -432,12 +432,12 @@ void multi_match_expression_with_params() { DSL.multi_match( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field", ExprValueUtils.floatValue(1.F)))))), + "field_value1", ExprValueUtils.floatValue(1.F)))))), DSL.namedArgument("query", DSL.literal("sample query")), DSL.namedArgument("analyzer", DSL.literal("keyword"))), AstDSL.function("multi_match", AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of( - "field", 1.F))), + "field_value1", 1.F))), AstDSL.unresolvedArg("query", stringLiteral("sample query")), AstDSL.unresolvedArg("analyzer", stringLiteral("keyword")))); } @@ -448,12 +448,12 @@ void multi_match_expression_two_fields() { DSL.multi_match( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field1", ExprValueUtils.floatValue(1.F), - "field2", ExprValueUtils.floatValue(.3F)))))), + "field_value1", ExprValueUtils.floatValue(1.F), + "field_value2", ExprValueUtils.floatValue(.3F)))))), DSL.namedArgument("query", DSL.literal("sample query"))), AstDSL.function("multi_match", AstDSL.unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of( - "field1", 1.F, "field2", .3F))), + "field_value1", 1.F, "field_value2", .3F))), AstDSL.unresolvedArg("query", stringLiteral("sample query")))); } @@ -463,11 +463,11 @@ void simple_query_string_expression() { DSL.simple_query_string( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field", ExprValueUtils.floatValue(1.F)))))), + "field_value1", ExprValueUtils.floatValue(1.F)))))), DSL.namedArgument("query", DSL.literal("sample query"))), AstDSL.function("simple_query_string", AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of( - "field", 1.F))), + "field_value1", 1.F))), AstDSL.unresolvedArg("query", stringLiteral("sample query")))); } @@ -477,12 +477,12 @@ void simple_query_string_expression_with_params() { DSL.simple_query_string( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field", ExprValueUtils.floatValue(1.F)))))), + "field_value1", ExprValueUtils.floatValue(1.F)))))), DSL.namedArgument("query", DSL.literal("sample query")), DSL.namedArgument("analyzer", DSL.literal("keyword"))), AstDSL.function("simple_query_string", AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of( - "field", 1.F))), + "field_value1", 1.F))), AstDSL.unresolvedArg("query", stringLiteral("sample query")), AstDSL.unresolvedArg("analyzer", stringLiteral("keyword")))); } @@ -493,12 +493,12 @@ void simple_query_string_expression_two_fields() { DSL.simple_query_string( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field1", ExprValueUtils.floatValue(1.F), - "field2", ExprValueUtils.floatValue(.3F)))))), + "field_value1", ExprValueUtils.floatValue(1.F), + "field_value2", ExprValueUtils.floatValue(.3F)))))), DSL.namedArgument("query", DSL.literal("sample query"))), AstDSL.function("simple_query_string", AstDSL.unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of( - "field1", 1.F, "field2", .3F))), + "field_value1", 1.F, "field_value2", .3F))), AstDSL.unresolvedArg("query", stringLiteral("sample query")))); } @@ -517,11 +517,11 @@ void query_string_expression() { DSL.query_string( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field", ExprValueUtils.floatValue(1.F)))))), + "field_value1", ExprValueUtils.floatValue(1.F)))))), DSL.namedArgument("query", DSL.literal("query_value"))), AstDSL.function("query_string", AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of( - "field", 1.F))), + "field_value1", 1.F))), AstDSL.unresolvedArg("query", stringLiteral("query_value")))); } @@ -531,12 +531,12 @@ void query_string_expression_with_params() { DSL.query_string( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field", ExprValueUtils.floatValue(1.F)))))), + "field_value1", ExprValueUtils.floatValue(1.F)))))), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("escape", DSL.literal("false"))), AstDSL.function("query_string", AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of( - "field", 1.F))), + "field_value1", 1.F))), AstDSL.unresolvedArg("query", stringLiteral("query_value")), AstDSL.unresolvedArg("escape", stringLiteral("false")))); } @@ -547,12 +547,12 @@ void query_string_expression_two_fields() { DSL.query_string( DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( - "field1", ExprValueUtils.floatValue(1.F), - "field2", ExprValueUtils.floatValue(.3F)))))), + "field_value1", ExprValueUtils.floatValue(1.F), + "field_value2", ExprValueUtils.floatValue(.3F)))))), DSL.namedArgument("query", DSL.literal("query_value"))), AstDSL.function("query_string", AstDSL.unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of( - "field1", 1.F, "field2", .3F))), + "field_value1", 1.F, "field_value2", .3F))), AstDSL.unresolvedArg("query", stringLiteral("query_value")))); } @@ -588,7 +588,7 @@ void wildcard_query_expression_all_params() { public void match_phrase_prefix_all_params() { assertAnalyzeEqual( DSL.match_phrase_prefix( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", "field_value1"), DSL.namedArgument("query", "search query"), DSL.namedArgument("slop", "3"), DSL.namedArgument("boost", "1.5"), @@ -597,7 +597,7 @@ public void match_phrase_prefix_all_params() { DSL.namedArgument("zero_terms_query", "NONE") ), AstDSL.function("match_phrase_prefix", - unresolvedArg("field", stringLiteral("test")), + unresolvedArg("field", stringLiteral("field_value1")), unresolvedArg("query", stringLiteral("search query")), unresolvedArg("slop", stringLiteral("3")), unresolvedArg("boost", stringLiteral("1.5")), diff --git a/core/src/test/java/org/opensearch/sql/config/TestConfig.java b/core/src/test/java/org/opensearch/sql/config/TestConfig.java index a0ef436162..4159ae12ff 100644 --- a/core/src/test/java/org/opensearch/sql/config/TestConfig.java +++ b/core/src/test/java/org/opensearch/sql/config/TestConfig.java @@ -57,6 +57,8 @@ public class TestConfig { .put("struct_value", ExprCoreType.STRUCT) .put("array_value", ExprCoreType.ARRAY) .put("timestamp_value", ExprCoreType.TIMESTAMP) + .put("field_value1", ExprCoreType.STRING) + .put("field_value2", ExprCoreType.STRING) .build(); @Bean diff --git a/core/src/test/java/org/opensearch/sql/expression/function/RelevanceFunctionResolverTest.java b/core/src/test/java/org/opensearch/sql/expression/function/RelevanceFunctionResolverTest.java index d8547057c4..deba721481 100644 --- a/core/src/test/java/org/opensearch/sql/expression/function/RelevanceFunctionResolverTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/function/RelevanceFunctionResolverTest.java @@ -24,7 +24,7 @@ class RelevanceFunctionResolverTest { @BeforeEach void setUp() { - resolver = new RelevanceFunctionResolver(sampleFuncName, STRING); + resolver = new RelevanceFunctionResolver(sampleFuncName); } @Test @@ -44,15 +44,6 @@ void resolve_invalid_name_test() { exception.getMessage()); } - @Test - void resolve_invalid_first_param_type_test() { - var sig = new FunctionSignature(sampleFuncName, List.of(INTEGER)); - Exception exception = assertThrows(SemanticCheckException.class, - () -> resolver.resolve(sig)); - assertEquals("Expected type STRING instead of INTEGER for parameter #1", - exception.getMessage()); - } - @Test void resolve_invalid_third_param_type_test() { var sig = new FunctionSignature(sampleFuncName, List.of(STRING, STRING, INTEGER, STRING)); diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java index 09e3504e4a..b113e83477 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java @@ -15,6 +15,7 @@ import org.json.JSONObject; import org.junit.Test; import org.opensearch.sql.legacy.SQLIntegTestCase; +import org.opensearch.sql.legacy.utils.StringUtils; public class MatchIT extends SQLIntegTestCase { @Override @@ -36,6 +37,42 @@ public void match_in_having() throws IOException { verifyDataRows(result, rows("Bates")); } + @Test + public void missing_field_test() { + String query = StringUtils.format("SELECT * FROM %s WHERE match(invalid, 'Bates')", TEST_INDEX_ACCOUNT); + final RuntimeException exception = + expectThrows(RuntimeException.class, () -> executeJdbcRequest(query)); + + assertTrue(exception.getMessage() + .contains("can't resolve Symbol(namespace=FIELD_NAME, name=invalid) in type env")); + + assertTrue(exception.getMessage().contains("SemanticCheckException")); + } + + @Test + public void missing_quoted_field_test() { + String query = StringUtils.format("SELECT * FROM %s WHERE match('invalid', 'Bates')", TEST_INDEX_ACCOUNT); + final RuntimeException exception = + expectThrows(RuntimeException.class, () -> executeJdbcRequest(query)); + + assertTrue(exception.getMessage() + .contains("can't resolve Symbol(namespace=FIELD_NAME, name=invalid) in type env")); + + assertTrue(exception.getMessage().contains("SemanticCheckException")); + } + + @Test + public void missing_backtick_field_test() { + String query = StringUtils.format("SELECT * FROM %s WHERE match(`invalid`, 'Bates')", TEST_INDEX_ACCOUNT); + final RuntimeException exception = + expectThrows(RuntimeException.class, () -> executeJdbcRequest(query)); + + assertTrue(exception.getMessage() + .contains("can't resolve Symbol(namespace=FIELD_NAME, name=invalid) in type env")); + + assertTrue(exception.getMessage().contains("SemanticCheckException")); + } + @Test public void matchquery_in_where() throws IOException { JSONObject result = executeJdbcRequest("SELECT firstname FROM " + TEST_INDEX_ACCOUNT + " WHERE matchquery(lastname, 'Bates')"); diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQuery.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQuery.java index a7d7584d4f..ec110dfd8b 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQuery.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQuery.java @@ -10,6 +10,7 @@ import org.opensearch.index.query.QueryBuilder; import org.opensearch.sql.exception.SemanticCheckException; import org.opensearch.sql.expression.NamedArgumentExpression; +import org.opensearch.sql.expression.ReferenceExpression; /** * Base class to represent builder class for relevance queries like match_query, match_bool_prefix, @@ -36,7 +37,7 @@ protected T createQueryBuilder(List arguments) { .orElseThrow(() -> new SemanticCheckException("'query' parameter is missing")); return createBuilder( - field.getValue().valueOf().stringValue(), + ((ReferenceExpression)field.getValue()).getAttr(), query.getValue().valueOf().stringValue()); } diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilderTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilderTest.java index f3e4fe7afd..2ad1f59d39 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilderTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilderTest.java @@ -53,6 +53,7 @@ import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.FunctionExpression; import org.opensearch.sql.expression.LiteralExpression; +import org.opensearch.sql.expression.ReferenceExpression; import org.opensearch.sql.opensearch.storage.serialization.ExpressionSerializer; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -313,7 +314,8 @@ void should_build_match_query_with_default_parameters() { + "}", buildQuery( DSL.match( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query"))))); } @@ -341,7 +343,8 @@ void should_build_match_query_with_custom_parameters() { + "}", buildQuery( DSL.match( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query")), DSL.namedArgument("operator", literal("AND")), DSL.namedArgument("analyzer", literal("keyword")), @@ -360,7 +363,8 @@ void should_build_match_query_with_custom_parameters() { @Test void match_invalid_parameter() { FunctionExpression expr = DSL.match( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query")), DSL.namedArgument("invalid_parameter", literal("invalid_value"))); var msg = assertThrows(SemanticCheckException.class, () -> buildQuery(expr)).getMessage(); @@ -433,7 +437,8 @@ void should_build_match_phrase_query_with_default_parameters() { + "}", buildQuery( DSL.match_phrase( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query"))))); } @@ -625,8 +630,9 @@ void should_build_match_phrase_query_with_custom_parameters() { + "}", buildQuery( DSL.match_phrase( + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("boost", literal("1.2")), - DSL.namedArgument("field", literal("message")), DSL.namedArgument("query", literal("search query")), DSL.namedArgument("analyzer", literal("keyword")), DSL.namedArgument("slop", literal("2")), @@ -636,7 +642,8 @@ void should_build_match_phrase_query_with_custom_parameters() { @Test void wildcard_query_invalid_parameter() { FunctionExpression expr = DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query*")), DSL.namedArgument("invalid_parameter", literal("invalid_value"))); assertThrows(SemanticCheckException.class, () -> buildQuery(expr), @@ -655,7 +662,8 @@ void wildcard_query_convert_sql_wildcard_to_lucene() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query%"))))); assertJsonEquals("{\n" @@ -667,7 +675,8 @@ void wildcard_query_convert_sql_wildcard_to_lucene() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query_"))))); } @@ -682,7 +691,8 @@ void wildcard_query_escape_wildcards_characters() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query\\%"))))); assertJsonEquals("{\n" @@ -694,7 +704,8 @@ void wildcard_query_escape_wildcards_characters() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query\\_"))))); assertJsonEquals("{\n" @@ -706,7 +717,8 @@ void wildcard_query_escape_wildcards_characters() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query\\*"))))); assertJsonEquals("{\n" @@ -718,7 +730,8 @@ void wildcard_query_escape_wildcards_characters() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query\\?"))))); } @@ -733,7 +746,8 @@ void should_build_wildcard_query_with_default_parameters() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query*"))))); } @@ -750,7 +764,8 @@ void should_build_wildcard_query_query_with_custom_parameters() { + " }\n" + "}", buildQuery(DSL.wildcard_query( - DSL.namedArgument("field", literal("field")), + DSL.namedArgument("field", + new ReferenceExpression("field", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query*")), DSL.namedArgument("boost", literal("0.6")), DSL.namedArgument("case_insensitive", literal("true")), @@ -1088,7 +1103,8 @@ void simple_query_string_invalid_parameter() { @Test void match_phrase_invalid_parameter() { FunctionExpression expr = DSL.match_phrase( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query")), DSL.namedArgument("invalid_parameter", literal("invalid_value"))); var msg = assertThrows(SemanticCheckException.class, () -> buildQuery(expr)).getMessage(); @@ -1097,7 +1113,8 @@ void match_phrase_invalid_parameter() { @Test void relevancy_func_invalid_arg_values() { - final var field = DSL.namedArgument("field", literal("message")); + final var field = DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)); final var fields = DSL.namedArgument("fields", DSL.literal( new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of( "field1", ExprValueUtils.floatValue(1.F), @@ -1175,18 +1192,11 @@ void should_build_match_bool_prefix_query_with_default_parameters() { + "}", buildQuery( DSL.match_bool_prefix( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query"))))); } - @Test - void multi_match_missing_fields() { - var msg = assertThrows(SemanticCheckException.class, () -> - DSL.multi_match( - DSL.namedArgument("query", literal("search query")))).getMessage(); - assertEquals("Expected type STRUCT instead of STRING for parameter #1", msg); - } - @Test void multi_match_missing_fields_even_with_struct() { FunctionExpression expr = DSL.multi_match( @@ -1227,7 +1237,8 @@ void should_build_match_phrase_prefix_query_with_default_parameters() { + "}", buildQuery( DSL.match_phrase_prefix( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query"))))); } @@ -1248,7 +1259,8 @@ void should_build_match_phrase_prefix_query_with_non_default_parameters() { + "}", buildQuery( DSL.match_phrase_prefix( - DSL.namedArgument("field", literal("message")), + DSL.namedArgument("field", + new ReferenceExpression("message", OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", literal("search query")), DSL.namedArgument("boost", literal("1.2")), DSL.namedArgument("max_expansions", literal("42")), diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchBoolPrefixQueryTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchBoolPrefixQueryTest.java index 162c55fcaf..34ef29f091 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchBoolPrefixQueryTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchBoolPrefixQueryTest.java @@ -23,8 +23,10 @@ import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.FunctionExpression; import org.opensearch.sql.expression.NamedArgumentExpression; +import org.opensearch.sql.expression.ReferenceExpression; import org.opensearch.sql.expression.env.Environment; import org.opensearch.sql.expression.function.FunctionName; +import org.opensearch.sql.opensearch.data.type.OpenSearchDataType; import org.opensearch.sql.opensearch.storage.script.filter.lucene.relevance.MatchBoolPrefixQuery; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -33,7 +35,8 @@ public class MatchBoolPrefixQueryTest { private final FunctionName matchBoolPrefix = FunctionName.of("match_bool_prefix"); static Stream> generateValidData() { - NamedArgumentExpression field = DSL.namedArgument("field", DSL.literal("field_value")); + NamedArgumentExpression field = DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)); NamedArgumentExpression query = DSL.namedArgument("query", DSL.literal("query_value")); return List.of( DSL.namedArgument("fuzziness", DSL.literal("AUTO")), @@ -58,7 +61,8 @@ public void test_valid_arguments(List validArgs) { @Test public void test_valid_when_two_arguments() { List arguments = List.of( - DSL.namedArgument("field", "field_value"), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "query_value")); Assertions.assertNotNull(matchBoolPrefixQuery.build(new MatchExpression(arguments))); } @@ -80,7 +84,8 @@ public void test_SyntaxCheckException_when_one_argument() { @Test public void test_SemanticCheckException_when_invalid_argument() { List arguments = List.of( - DSL.namedArgument("field", "field_value"), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "query_value"), DSL.namedArgument("unsupported", "unsupported_value")); Assertions.assertThrows(SemanticCheckException.class, diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhrasePrefixQueryTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhrasePrefixQueryTest.java index a0b9e5f318..e02f112677 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhrasePrefixQueryTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhrasePrefixQueryTest.java @@ -20,8 +20,10 @@ import org.opensearch.sql.expression.DSL; import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.FunctionExpression; +import org.opensearch.sql.expression.ReferenceExpression; import org.opensearch.sql.expression.env.Environment; import org.opensearch.sql.expression.function.FunctionName; +import org.opensearch.sql.opensearch.data.type.OpenSearchDataType; import org.opensearch.sql.opensearch.storage.script.filter.lucene.relevance.MatchPhrasePrefixQuery; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -39,7 +41,8 @@ public void test_SyntaxCheckException_when_no_arguments() { @Test public void test_SyntaxCheckException_when_one_argument() { - List arguments = List.of(DSL.namedArgument("field", "test")); + List arguments = List.of(DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD))); assertThrows(SyntaxCheckException.class, () -> matchPhrasePrefixQuery.build(new MatchPhraseExpression(arguments))); } @@ -47,7 +50,8 @@ public void test_SyntaxCheckException_when_one_argument() { @Test public void test_SyntaxCheckException_when_invalid_parameter() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2"), DSL.namedArgument("unsupported", "3")); Assertions.assertThrows(SemanticCheckException.class, @@ -57,7 +61,8 @@ public void test_SyntaxCheckException_when_invalid_parameter() { @Test public void test_analyzer_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("analyzer", "standard") ); @@ -67,7 +72,8 @@ public void test_analyzer_parameter() { @Test public void build_succeeds_with_two_arguments() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2")); Assertions.assertNotNull(matchPhrasePrefixQuery.build(new MatchPhraseExpression(arguments))); } @@ -75,7 +81,8 @@ public void build_succeeds_with_two_arguments() { @Test public void test_slop_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("slop", "2") ); @@ -85,7 +92,8 @@ public void test_slop_parameter() { @Test public void test_zero_terms_query_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "ALL") ); @@ -95,7 +103,8 @@ public void test_zero_terms_query_parameter() { @Test public void test_zero_terms_query_parameter_lower_case() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "all") ); @@ -105,7 +114,8 @@ public void test_zero_terms_query_parameter_lower_case() { @Test public void test_boost_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("boost", "0.1") ); diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhraseQueryTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhraseQueryTest.java index 6a298326b7..dd6296279c 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhraseQueryTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchPhraseQueryTest.java @@ -20,8 +20,10 @@ import org.opensearch.sql.expression.DSL; import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.FunctionExpression; +import org.opensearch.sql.expression.ReferenceExpression; import org.opensearch.sql.expression.env.Environment; import org.opensearch.sql.expression.function.FunctionName; +import org.opensearch.sql.opensearch.data.type.OpenSearchDataType; import org.opensearch.sql.opensearch.storage.script.filter.lucene.relevance.MatchPhraseQuery; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -41,7 +43,8 @@ public void test_SyntaxCheckException_when_no_arguments() { @Test public void test_SyntaxCheckException_when_one_argument() { - List arguments = List.of(DSL.namedArgument("field", "test")); + List arguments = List.of(DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD))); assertThrows(SyntaxCheckException.class, () -> matchPhraseQuery.build(new MatchPhraseExpression(arguments))); } @@ -49,7 +52,8 @@ public void test_SyntaxCheckException_when_one_argument() { @Test public void test_SyntaxCheckException_when_invalid_parameter() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2"), DSL.namedArgument("unsupported", "3")); Assertions.assertThrows(SemanticCheckException.class, @@ -59,7 +63,8 @@ public void test_SyntaxCheckException_when_invalid_parameter() { @Test public void test_analyzer_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("analyzer", "standard") ); @@ -69,7 +74,8 @@ public void test_analyzer_parameter() { @Test public void build_succeeds_with_two_arguments() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2")); Assertions.assertNotNull(matchPhraseQuery.build(new MatchPhraseExpression(arguments))); } @@ -77,7 +83,8 @@ public void build_succeeds_with_two_arguments() { @Test public void test_slop_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("slop", "2") ); @@ -87,7 +94,8 @@ public void test_slop_parameter() { @Test public void test_zero_terms_query_parameter() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "ALL") ); @@ -97,7 +105,8 @@ public void test_zero_terms_query_parameter() { @Test public void test_zero_terms_query_parameter_lower_case() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "all") ); @@ -114,7 +123,8 @@ public void test_SyntaxCheckException_when_no_arguments_match_phrase_syntax() { @Test public void test_SyntaxCheckException_when_one_argument_match_phrase_syntax() { - List arguments = List.of(DSL.namedArgument("field", "test")); + List arguments = List.of(DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD))); assertThrows(SyntaxCheckException.class, () -> matchPhraseQuery.build(new MatchPhraseExpression( arguments, matchPhraseWithUnderscoreName))); @@ -124,7 +134,8 @@ public void test_SyntaxCheckException_when_one_argument_match_phrase_syntax() { @Test public void test_SyntaxCheckException_when_invalid_parameter_match_phrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2"), DSL.namedArgument("unsupported", "3")); Assertions.assertThrows(SemanticCheckException.class, @@ -135,7 +146,8 @@ public void test_SyntaxCheckException_when_invalid_parameter_match_phrase_syntax @Test public void test_analyzer_parameter_match_phrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("analyzer", "standard") ); @@ -146,7 +158,8 @@ public void test_analyzer_parameter_match_phrase_syntax() { @Test public void build_succeeds_with_two_arguments_match_phrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2")); Assertions.assertNotNull(matchPhraseQuery.build(new MatchPhraseExpression( arguments, matchPhraseWithUnderscoreName))); @@ -155,7 +168,8 @@ public void build_succeeds_with_two_arguments_match_phrase_syntax() { @Test public void test_slop_parameter_match_phrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("slop", "2") ); @@ -166,7 +180,8 @@ public void test_slop_parameter_match_phrase_syntax() { @Test public void test_zero_terms_query_parameter_match_phrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "ALL") ); @@ -177,7 +192,8 @@ public void test_zero_terms_query_parameter_match_phrase_syntax() { @Test public void test_zero_terms_query_parameter_lower_case_match_phrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "all") ); @@ -195,7 +211,8 @@ public void test_SyntaxCheckException_when_no_arguments_matchphrase_syntax() { @Test public void test_SyntaxCheckException_when_one_argument_matchphrase_syntax() { - List arguments = List.of(DSL.namedArgument("field", "test")); + List arguments = List.of(DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD))); assertThrows(SyntaxCheckException.class, () -> matchPhraseQuery.build(new MatchPhraseExpression( arguments, matchPhraseQueryName))); @@ -205,7 +222,8 @@ public void test_SyntaxCheckException_when_one_argument_matchphrase_syntax() { @Test public void test_SyntaxCheckException_when_invalid_parameter_matchphrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2"), DSL.namedArgument("unsupported", "3")); Assertions.assertThrows(SemanticCheckException.class, @@ -216,7 +234,8 @@ public void test_SyntaxCheckException_when_invalid_parameter_matchphrase_syntax( @Test public void test_analyzer_parameter_matchphrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("analyzer", "standard") ); @@ -227,7 +246,8 @@ public void test_analyzer_parameter_matchphrase_syntax() { @Test public void build_succeeds_with_two_arguments_matchphrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "test"), + DSL.namedArgument("field", + new ReferenceExpression("test", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "test2")); Assertions.assertNotNull(matchPhraseQuery.build(new MatchPhraseExpression( arguments, matchPhraseQueryName))); @@ -236,7 +256,8 @@ public void build_succeeds_with_two_arguments_matchphrase_syntax() { @Test public void test_slop_parameter_matchphrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("slop", "2") ); @@ -247,7 +268,8 @@ public void test_slop_parameter_matchphrase_syntax() { @Test public void test_zero_terms_query_parameter_matchphrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "ALL") ); @@ -258,7 +280,8 @@ public void test_zero_terms_query_parameter_matchphrase_syntax() { @Test public void test_zero_terms_query_parameter_lower_case_matchphrase_syntax() { List arguments = List.of( - DSL.namedArgument("field", "t1"), + DSL.namedArgument("field", + new ReferenceExpression("t1", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", "t2"), DSL.namedArgument("zero_terms_query", "all") ); diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchQueryTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchQueryTest.java index e18b477745..f7d1f1aa9a 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchQueryTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/MatchQueryTest.java @@ -23,8 +23,10 @@ import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.FunctionExpression; import org.opensearch.sql.expression.NamedArgumentExpression; +import org.opensearch.sql.expression.ReferenceExpression; import org.opensearch.sql.expression.env.Environment; import org.opensearch.sql.expression.function.FunctionName; +import org.opensearch.sql.opensearch.data.type.OpenSearchDataType; import org.opensearch.sql.opensearch.storage.script.filter.lucene.relevance.MatchQuery; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -39,71 +41,85 @@ public class MatchQueryTest { static Stream> generateValidData() { return Stream.of( List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("analyzer", DSL.literal("standard")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("auto_generate_synonyms_phrase_query", DSL.literal("true")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("fuzziness", DSL.literal("AUTO")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("max_expansions", DSL.literal("50")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("prefix_length", DSL.literal("0")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("fuzzy_transpositions", DSL.literal("true")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("fuzzy_rewrite", DSL.literal("constant_score")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("lenient", DSL.literal("false")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("operator", DSL.literal("OR")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("minimum_should_match", DSL.literal("3")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("zero_terms_query", DSL.literal("NONE")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("zero_terms_query", DSL.literal("none")) ), List.of( - DSL.namedArgument("field", DSL.literal("field_value")), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), DSL.namedArgument("query", DSL.literal("query_value")), DSL.namedArgument("boost", DSL.literal("1")) ) @@ -133,7 +149,8 @@ public void test_SyntaxCheckException_when_one_argument() { @Test public void test_SemanticCheckException_when_invalid_parameter() { List arguments = List.of( - namedArgument("field", "field_value"), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), namedArgument("query", "query_value"), namedArgument("unsupported", "unsupported_value")); Assertions.assertThrows(SemanticCheckException.class, @@ -166,7 +183,8 @@ public void test_SyntaxCheckException_when_one_argument_matchquery_syntax() { @Test public void test_SemanticCheckException_when_invalid_parameter_matchquery_syntax() { List arguments = List.of( - namedArgument("field", "field_value"), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), namedArgument("query", "query_value"), namedArgument("unsupported", "unsupported_value")); Assertions.assertThrows(SemanticCheckException.class, @@ -200,7 +218,8 @@ public void test_SyntaxCheckException_when_one_argument_match_query_syntax() { @Test public void test_SemanticCheckException_when_invalid_parameter_match_query_syntax() { List arguments = List.of( - namedArgument("field", "field_value"), + DSL.namedArgument("field", + new ReferenceExpression("field_value", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), namedArgument("query", "query_value"), namedArgument("unsupported", "unsupported_value")); Assertions.assertThrows(SemanticCheckException.class, diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/WildcardQueryTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/WildcardQueryTest.java index ce7a39d91a..684036595c 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/WildcardQueryTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/WildcardQueryTest.java @@ -22,8 +22,10 @@ import org.opensearch.sql.exception.SemanticCheckException; import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.FunctionExpression; +import org.opensearch.sql.expression.ReferenceExpression; import org.opensearch.sql.expression.env.Environment; import org.opensearch.sql.expression.function.FunctionName; +import org.opensearch.sql.opensearch.data.type.OpenSearchDataType; import org.opensearch.sql.opensearch.storage.script.filter.lucene.relevance.WildcardQuery; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -34,7 +36,8 @@ class WildcardQueryTest { static Stream> generateValidData() { return Stream.of( List.of( - namedArgument("field", "title"), + namedArgument("field", + new ReferenceExpression("title", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), namedArgument("query", "query_value*"), namedArgument("boost", "0.7"), namedArgument("case_insensitive", "false"), @@ -59,7 +62,8 @@ public void test_SyntaxCheckException_when_no_arguments() { @Test public void test_SyntaxCheckException_when_one_argument() { - List arguments = List.of(namedArgument("field", "title")); + List arguments = List.of(namedArgument("field", + new ReferenceExpression("title", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD))); assertThrows(SyntaxCheckException.class, () -> wildcardQueryQuery.build(new WildcardQueryExpression(arguments))); } @@ -67,7 +71,8 @@ public void test_SyntaxCheckException_when_one_argument() { @Test public void test_SemanticCheckException_when_invalid_parameter() { List arguments = List.of( - namedArgument("field", "title"), + namedArgument("field", + new ReferenceExpression("title", OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), namedArgument("query", "query_value*"), namedArgument("unsupported", "unsupported_value")); Assertions.assertThrows(SemanticCheckException.class, diff --git a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQueryTest.java b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQueryTest.java index b2d650602b..67f22178bc 100644 --- a/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQueryTest.java +++ b/opensearch/src/test/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/relevance/SingleFieldQueryTest.java @@ -19,6 +19,8 @@ import org.opensearch.sql.data.model.ExprValueUtils; import org.opensearch.sql.expression.DSL; import org.opensearch.sql.expression.LiteralExpression; +import org.opensearch.sql.expression.ReferenceExpression; +import org.opensearch.sql.opensearch.data.type.OpenSearchDataType; class SingleFieldQueryTest { SingleFieldQuery query; @@ -35,12 +37,26 @@ void setUp() { } @Test - void createQueryBuilderTest() { + void createQueryBuilderTestTypeTextKeyword() { String sampleQuery = "sample query"; String sampleField = "fieldA"; query.createQueryBuilder(List.of(DSL.namedArgument("field", - new LiteralExpression(ExprValueUtils.stringValue(sampleField))), + new ReferenceExpression(sampleField, OpenSearchDataType.OPENSEARCH_TEXT_KEYWORD)), + DSL.namedArgument("query", + new LiteralExpression(ExprValueUtils.stringValue(sampleQuery))))); + + verify(query).createBuilder(eq(sampleField), + eq(sampleQuery)); + } + + @Test + void createQueryBuilderTestTypeText() { + String sampleQuery = "sample query"; + String sampleField = "fieldA"; + + query.createQueryBuilder(List.of(DSL.namedArgument("field", + new ReferenceExpression(sampleField, OpenSearchDataType.OPENSEARCH_TEXT)), DSL.namedArgument("query", new LiteralExpression(ExprValueUtils.stringValue(sampleQuery))))); diff --git a/ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.java b/ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.java index d4df4cf7dd..c9823b67f9 100644 --- a/ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.java +++ b/ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.java @@ -368,7 +368,7 @@ private List singleFieldRelevanceArguments( // to skip environment resolving and function signature resolving ImmutableList.Builder builder = ImmutableList.builder(); builder.add(new UnresolvedArgument("field", - new Literal(StringUtils.unquoteText(ctx.field.getText()), DataType.STRING))); + new QualifiedName(StringUtils.unquoteText(ctx.field.getText())))); builder.add(new UnresolvedArgument("query", new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING))); ctx.relevanceArg().forEach(v -> builder.add(new UnresolvedArgument( diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstExpressionBuilderTest.java b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstExpressionBuilderTest.java index cd0787695a..aa573449b6 100644 --- a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstExpressionBuilderTest.java +++ b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstExpressionBuilderTest.java @@ -729,7 +729,7 @@ public void canBuildMatchRelevanceFunctionWithArguments() { relation("test"), function( "match", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("test query")), unresolvedArg("analyzer", stringLiteral("keyword")) ) diff --git a/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java b/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java index 06de8d7d05..20ed1322e0 100644 --- a/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java +++ b/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java @@ -502,7 +502,7 @@ private List singleFieldRelevanceArguments( // to skip environment resolving and function signature resolving ImmutableList.Builder builder = ImmutableList.builder(); builder.add(new UnresolvedArgument("field", - new Literal(StringUtils.unquoteText(ctx.field.getText()), DataType.STRING))); + new QualifiedName(StringUtils.unquoteText(ctx.field.getText())))); builder.add(new UnresolvedArgument("query", new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING))); fillRelevanceArgs(ctx.relevanceArg(), builder); diff --git a/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java b/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java index 8b6cca779c..113a828f0e 100644 --- a/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java +++ b/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java @@ -494,7 +494,7 @@ public void filteredDistinctCount() { public void matchPhraseQueryAllParameters() { assertEquals( AstDSL.function("matchphrasequery", - unresolvedArg("field", stringLiteral("test")), + unresolvedArg("field", qualifiedName("test")), unresolvedArg("query", stringLiteral("search query")), unresolvedArg("slop", stringLiteral("3")), unresolvedArg("analyzer", stringLiteral("standard")), @@ -510,7 +510,7 @@ public void matchPhraseQueryAllParameters() { public void matchPhrasePrefixAllParameters() { assertEquals( AstDSL.function("match_phrase_prefix", - unresolvedArg("field", stringLiteral("test")), + unresolvedArg("field", qualifiedName("test")), unresolvedArg("query", stringLiteral("search query")), unresolvedArg("slop", stringLiteral("3")), unresolvedArg("boost", stringLiteral("1.5")), @@ -527,13 +527,13 @@ public void matchPhrasePrefixAllParameters() { @Test public void relevanceMatch() { assertEquals(AstDSL.function("match", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("search query"))), buildExprAst("match('message', 'search query')") ); assertEquals(AstDSL.function("match", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("search query")), unresolvedArg("analyzer", stringLiteral("keyword")), unresolvedArg("operator", stringLiteral("AND"))), @@ -543,13 +543,13 @@ public void relevanceMatch() { @Test public void relevanceMatchQuery() { assertEquals(AstDSL.function("matchquery", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("search query"))), buildExprAst("matchquery('message', 'search query')") ); assertEquals(AstDSL.function("matchquery", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("search query")), unresolvedArg("analyzer", stringLiteral("keyword")), unresolvedArg("operator", stringLiteral("AND"))), @@ -559,13 +559,13 @@ public void relevanceMatchQuery() { @Test public void relevanceMatch_Query() { assertEquals(AstDSL.function("match_query", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("search query"))), buildExprAst("match_query('message', 'search query')") ); assertEquals(AstDSL.function("match_query", - unresolvedArg("field", stringLiteral("message")), + unresolvedArg("field", qualifiedName("message")), unresolvedArg("query", stringLiteral("search query")), unresolvedArg("analyzer", stringLiteral("keyword")), unresolvedArg("operator", stringLiteral("AND"))), @@ -671,7 +671,7 @@ public void relevanceQuery_string() { @Test public void relevanceWildcard_query() { assertEquals(AstDSL.function("wildcard_query", - unresolvedArg("field", stringLiteral("field")), + unresolvedArg("field", qualifiedName("field")), unresolvedArg("query", stringLiteral("search query*")), unresolvedArg("boost", stringLiteral("1.5")), unresolvedArg("case_insensitive", stringLiteral("true")),