diff --git a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java
index cc3db47982..2696ca62b5 100644
--- a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java
+++ b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java
@@ -221,7 +221,9 @@ public enum BuiltinFunctionName {
QUERY(FunctionName.of("query")),
MATCH_QUERY(FunctionName.of("match_query")),
MATCHQUERY(FunctionName.of("matchquery")),
- MULTI_MATCH(FunctionName.of("multi_match"));
+ MULTI_MATCH(FunctionName.of("multi_match")),
+ MULTIMATCH(FunctionName.of("multimatch")),
+ MULTIMATCHQUERY(FunctionName.of("multimatchquery"));
private final FunctionName name;
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 97afe3675e..1364559482 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
@@ -28,7 +28,9 @@ public class OpenSearchFunctions {
public void register(BuiltinFunctionRepository repository) {
repository.register(match_bool_prefix());
repository.register(match());
- repository.register(multi_match());
+ repository.register(multi_match(BuiltinFunctionName.MULTI_MATCH));
+ repository.register(multi_match(BuiltinFunctionName.MULTIMATCH));
+ repository.register(multi_match(BuiltinFunctionName.MULTIMATCHQUERY));
repository.register(simple_query_string());
repository.register(query());
repository.register(query_string());
@@ -59,9 +61,8 @@ private static FunctionResolver match_phrase(BuiltinFunctionName matchPhrase) {
return new RelevanceFunctionResolver(funcName, STRING);
}
- private static FunctionResolver multi_match() {
- FunctionName funcName = BuiltinFunctionName.MULTI_MATCH.getName();
- return new RelevanceFunctionResolver(funcName, STRUCT);
+ private static FunctionResolver multi_match(BuiltinFunctionName multiMatchName) {
+ return new RelevanceFunctionResolver(multiMatchName.getName(), STRUCT);
}
private static FunctionResolver simple_query_string() {
diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/MultiMatchIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/MultiMatchIT.java
index ba62e6629f..24ce45fd20 100644
--- a/integ-test/src/test/java/org/opensearch/sql/sql/MultiMatchIT.java
+++ b/integ-test/src/test/java/org/opensearch/sql/sql/MultiMatchIT.java
@@ -6,6 +6,8 @@
package org.opensearch.sql.sql;
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BEER;
+import static org.opensearch.sql.util.MatcherUtils.rows;
+import static org.opensearch.sql.util.MatcherUtils.verifyDataRows;
import java.io.IOException;
import org.json.JSONObject;
@@ -27,38 +29,99 @@ public void init() throws IOException {
*/
@Test
- public void test_mandatory_params() throws IOException {
+ public void test_mandatory_params() {
String query = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE multi_match([\\\"Tags\\\" ^ 1.5, Title, `Body` 4.2], 'taste')";
- var result = new JSONObject(executeQuery(query, "jdbc"));
+ JSONObject result = executeJdbcRequest(query);
assertEquals(16, result.getInt("total"));
}
@Test
- public void test_all_params() throws IOException {
+ public void test_all_params() {
String query = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE multi_match(['Body', Tags], 'taste beer', operator='and', analyzer=english,"
+ "auto_generate_synonyms_phrase_query=true, boost = 0.77, cutoff_frequency=0.33,"
+ "fuzziness = 'AUTO:1,5', fuzzy_transpositions = false, lenient = true, max_expansions = 25,"
+ "minimum_should_match = '2<-25% 9<-3', prefix_length = 7, tie_breaker = 0.3,"
+ "type = most_fields, slop = 2, zero_terms_query = 'ALL');";
- var result = new JSONObject(executeQuery(query, "jdbc"));
+ JSONObject result = executeJdbcRequest(query);
assertEquals(10, result.getInt("total"));
}
@Test
- public void verify_wildcard_test() throws IOException {
+ public void verify_wildcard_test() {
String query1 = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE multi_match(['Tags'], 'taste')";
- var result1 = new JSONObject(executeQuery(query1, "jdbc"));
+ JSONObject result1 = executeJdbcRequest(query1);
String query2 = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE multi_match(['T*'], 'taste')";
- var result2 = new JSONObject(executeQuery(query2, "jdbc"));
+ JSONObject result2 = executeJdbcRequest(query2);
assertNotEquals(result2.getInt("total"), result1.getInt("total"));
String query = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE multi_match(['*Date'], '2014-01-22');";
- var result = new JSONObject(executeQuery(query, "jdbc"));
+ JSONObject result = executeJdbcRequest(query);
assertEquals(10, result.getInt("total"));
}
+
+ @Test
+ public void test_multimatch_alternate_parameter_syntax() {
+ String query = "SELECT Tags FROM " + TEST_INDEX_BEER
+ + " WHERE multimatch('query'='taste', 'fields'='Tags')";
+ JSONObject result = executeJdbcRequest(query);
+ assertEquals(8, result.getInt("total"));
+ }
+
+ @Test
+ public void test_multimatchquery_alternate_parameter_syntax() {
+ String query = "SELECT Tags FROM " + TEST_INDEX_BEER
+ + " WHERE multimatchquery(query='cicerone', fields='Tags')";
+ JSONObject result = executeJdbcRequest(query);
+ assertEquals(2, result.getInt("total"));
+ verifyDataRows(result, rows("serving cicerone restaurants"),
+ rows("taste cicerone"));
+ }
+
+ @Test
+ public void test_quoted_multi_match_alternate_parameter_syntax() {
+ String query = "SELECT Tags FROM " + TEST_INDEX_BEER
+ + " WHERE multi_match('query'='cicerone', 'fields'='Tags')";
+ JSONObject result = executeJdbcRequest(query);
+ assertEquals(2, result.getInt("total"));
+ verifyDataRows(result, rows("serving cicerone restaurants"),
+ rows("taste cicerone"));
+ }
+
+ @Test
+ public void test_multi_match_alternate_parameter_syntax() {
+ String query = "SELECT Tags FROM " + TEST_INDEX_BEER
+ + " WHERE multi_match(query='cicerone', fields='Tags')";
+ JSONObject result = executeJdbcRequest(query);
+ assertEquals(2, result.getInt("total"));
+ verifyDataRows(result, rows("serving cicerone restaurants"),
+ rows("taste cicerone"));
+ }
+
+ @Test
+ public void test_wildcard_multi_match_alternate_parameter_syntax() {
+ String query = "SELECT Body FROM " + TEST_INDEX_BEER
+ + " WHERE multi_match(query='IPA', fields='B*') LIMIT 1";
+ JSONObject result = executeJdbcRequest(query);
+ verifyDataRows(result, rows("
I know what makes an IPA an IPA, but what are the unique" +
+ " characteristics of it's common variants? To be specific, the ones I'm interested in are Double IPA" +
+ " and Black IPA, but general differences between any other styles would be welcome too.
\n"));
+ }
+
+ @Test
+ public void test_all_params_multimatchquery_alternate_parameter_syntax() {
+ String query = "SELECT Id FROM " + TEST_INDEX_BEER
+ + " WHERE multimatchquery(query='cicerone', fields='Tags', 'operator'='or', analyzer=english,"
+ + "auto_generate_synonyms_phrase_query=true, boost = 0.77, cutoff_frequency=0.33,"
+ + "fuzziness = 'AUTO:1,5', fuzzy_transpositions = false, lenient = true, max_expansions = 25,"
+ + "minimum_should_match = '2<-25% 9<-3', prefix_length = 7, tie_breaker = 0.3,"
+ + "type = most_fields, slop = 2, zero_terms_query = 'ALL');";
+
+ JSONObject result = executeJdbcRequest(query);
+ assertEquals(2, result.getInt("total"));
+ }
}
diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilder.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilder.java
index ab8fb562da..b754ea7112 100644
--- a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilder.java
+++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/FilterQueryBuilder.java
@@ -65,6 +65,8 @@ public class FilterQueryBuilder extends ExpressionNodeVisitor(ImmutableMap.of(
"title", ExprValueUtils.floatValue(1.F),
@@ -129,27 +131,69 @@ static Stream> generateValidData() {
@ParameterizedTest
@MethodSource("generateValidData")
- public void test_valid_parameters(List validArgs) {
+ public void test_valid_parameters_multiMatch(List validArgs) {
Assertions.assertNotNull(multiMatchQuery.build(
new MultiMatchExpression(validArgs)));
}
+ @ParameterizedTest
+ @MethodSource("generateValidData")
+ public void test_valid_parameters_multi_match(List validArgs) {
+ Assertions.assertNotNull(multiMatchQuery.build(
+ new MultiMatchExpression(validArgs, snakeCaseMultiMatchName)));
+ }
+
+ @ParameterizedTest
+ @MethodSource("generateValidData")
+ public void test_valid_parameters_multiMatchQuery(List validArgs) {
+ Assertions.assertNotNull(multiMatchQuery.build(
+ new MultiMatchExpression(validArgs, multiMatchQueryName)));
+ }
+
@Test
- public void test_SyntaxCheckException_when_no_arguments() {
+ public void test_SyntaxCheckException_when_no_arguments_multiMatch() {
List arguments = List.of();
assertThrows(SyntaxCheckException.class,
() -> multiMatchQuery.build(new MultiMatchExpression(arguments)));
}
@Test
- public void test_SyntaxCheckException_when_one_argument() {
+ public void test_SyntaxCheckException_when_no_arguments_multi_match() {
+ List arguments = List.of();
+ assertThrows(SyntaxCheckException.class,
+ () -> multiMatchQuery.build(new MultiMatchExpression(arguments, multiMatchName)));
+ }
+
+ @Test
+ public void test_SyntaxCheckException_when_no_arguments_multiMatchQuery() {
+ List arguments = List.of();
+ assertThrows(SyntaxCheckException.class,
+ () -> multiMatchQuery.build(new MultiMatchExpression(arguments, multiMatchQueryName)));
+ }
+
+ @Test
+ public void test_SyntaxCheckException_when_one_argument_multiMatch() {
List arguments = List.of(namedArgument("fields", fields_value));
assertThrows(SyntaxCheckException.class,
() -> multiMatchQuery.build(new MultiMatchExpression(arguments)));
}
@Test
- public void test_SemanticCheckException_when_invalid_parameter() {
+ public void test_SyntaxCheckException_when_one_argument_multi_match() {
+ List arguments = List.of(namedArgument("fields", fields_value));
+ assertThrows(SyntaxCheckException.class,
+ () -> multiMatchQuery.build(new MultiMatchExpression(arguments, snakeCaseMultiMatchName)));
+ }
+
+ @Test
+ public void test_SyntaxCheckException_when_one_argument_multiMatchQuery() {
+ List arguments = List.of(namedArgument("fields", fields_value));
+ assertThrows(SyntaxCheckException.class,
+ () -> multiMatchQuery.build(new MultiMatchExpression(arguments, multiMatchQueryName)));
+ }
+
+ @Test
+ public void test_SemanticCheckException_when_invalid_parameter_multiMatch() {
List arguments = List.of(
namedArgument("fields", fields_value),
namedArgument("query", query_value),
@@ -158,15 +202,40 @@ public void test_SemanticCheckException_when_invalid_parameter() {
() -> multiMatchQuery.build(new MultiMatchExpression(arguments)));
}
+ @Test
+ public void test_SemanticCheckException_when_invalid_parameter_multi_match() {
+ List arguments = List.of(
+ namedArgument("fields", fields_value),
+ namedArgument("query", query_value),
+ DSL.namedArgument("unsupported", "unsupported_value"));
+ Assertions.assertThrows(SemanticCheckException.class,
+ () -> multiMatchQuery.build(new MultiMatchExpression(arguments, snakeCaseMultiMatchName)));
+ }
+
+ @Test
+ public void test_SemanticCheckException_when_invalid_parameter_multiMatchQuery() {
+ List arguments = List.of(
+ namedArgument("fields", fields_value),
+ namedArgument("query", query_value),
+ DSL.namedArgument("unsupported", "unsupported_value"));
+ Assertions.assertThrows(SemanticCheckException.class,
+ () -> multiMatchQuery.build(new MultiMatchExpression(arguments, multiMatchQueryName)));
+ }
+
private NamedArgumentExpression namedArgument(String name, LiteralExpression value) {
return DSL.namedArgument(name, value);
}
private class MultiMatchExpression extends FunctionExpression {
public MultiMatchExpression(List arguments) {
- super(MultiMatchTest.this.multiMatch, arguments);
+ super(multiMatchName, arguments);
}
+ public MultiMatchExpression(List arguments, FunctionName funcName) {
+ super(funcName, arguments);
+ }
+
+
@Override
public ExprValue valueOf(Environment valueEnv) {
throw new UnsupportedOperationException("Invalid function call, "
diff --git a/sql/src/main/antlr/OpenSearchSQLLexer.g4 b/sql/src/main/antlr/OpenSearchSQLLexer.g4
index 9e0a409401..3df9cd95ba 100644
--- a/sql/src/main/antlr/OpenSearchSQLLexer.g4
+++ b/sql/src/main/antlr/OpenSearchSQLLexer.g4
@@ -305,6 +305,7 @@ MINUTE_OF_HOUR: 'MINUTE_OF_HOUR';
MONTH_OF_YEAR: 'MONTH_OF_YEAR';
MULTIMATCH: 'MULTIMATCH';
MULTI_MATCH: 'MULTI_MATCH';
+MULTIMATCHQUERY: 'MULTIMATCHQUERY';
NESTED: 'NESTED';
PERCENTILES: 'PERCENTILES';
REGEXP_QUERY: 'REGEXP_QUERY';
diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4
index b3fd29b342..da30059d6f 100644
--- a/sql/src/main/antlr/OpenSearchSQLParser.g4
+++ b/sql/src/main/antlr/OpenSearchSQLParser.g4
@@ -347,6 +347,8 @@ multiFieldRelevanceFunction
: multiFieldRelevanceFunctionName LR_BRACKET
LT_SQR_PRTHS field=relevanceFieldAndWeight (COMMA field=relevanceFieldAndWeight)* RT_SQR_PRTHS
COMMA query=relevanceQuery (COMMA relevanceArg)* RR_BRACKET
+ | multiFieldRelevanceFunctionName LR_BRACKET
+ alternateMultiMatchQuery COMMA alternateMultiMatchField (COMMA relevanceArg)* RR_BRACKET
;
convertedDataType
@@ -431,6 +433,8 @@ singleFieldRelevanceFunctionName
multiFieldRelevanceFunctionName
: MULTI_MATCH
+ | MULTIMATCH
+ | MULTIMATCHQUERY
| SIMPLE_QUERY_STRING
| QUERY_STRING
;
@@ -449,6 +453,7 @@ functionArg
relevanceArg
: relevanceArgName EQUAL_SYMBOL relevanceArgValue
+ | argName=stringLiteral EQUAL_SYMBOL argVal=relevanceArgValue
;
highlightArg
@@ -498,3 +503,18 @@ highlightArgValue
: stringLiteral
;
+alternateMultiMatchArgName
+ : FIELDS
+ | QUERY
+ | stringLiteral
+ ;
+
+alternateMultiMatchQuery
+ : argName=alternateMultiMatchArgName EQUAL_SYMBOL argVal=relevanceArgValue
+ ;
+
+alternateMultiMatchField
+ : argName=alternateMultiMatchArgName EQUAL_SYMBOL argVal=relevanceArgValue
+ | argName=alternateMultiMatchArgName EQUAL_SYMBOL
+ LT_SQR_PRTHS argVal=relevanceArgValue RT_SQR_PRTHS
+ ;
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 131b6d9116..1879d62142 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
@@ -52,7 +52,9 @@
import com.google.common.collect.ImmutableMap;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.RuleContext;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -80,6 +82,7 @@
import org.opensearch.sql.ast.expression.WindowFunction;
import org.opensearch.sql.ast.tree.Sort.SortOption;
import org.opensearch.sql.common.utils.StringUtils;
+import org.opensearch.sql.expression.function.BuiltinFunctionName;
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser;
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AndExpressionContext;
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.ColumnNameContext;
@@ -399,9 +402,22 @@ public UnresolvedExpression visitSingleFieldRelevanceFunction(
@Override
public UnresolvedExpression visitMultiFieldRelevanceFunction(
MultiFieldRelevanceFunctionContext ctx) {
- return new Function(
- ctx.multiFieldRelevanceFunctionName().getText().toLowerCase(),
- multiFieldRelevanceArguments(ctx));
+ // To support alternate syntax for MULTI_MATCH like
+ // 'MULTI_MATCH('query'='query_val', 'fields'='*fields_val')'
+ String funcName = StringUtils.unquoteText(ctx.multiFieldRelevanceFunctionName().getText());
+ if ((funcName.equalsIgnoreCase(BuiltinFunctionName.MULTI_MATCH.toString())
+ || funcName.equalsIgnoreCase(BuiltinFunctionName.MULTIMATCH.toString())
+ || funcName.equalsIgnoreCase(BuiltinFunctionName.MULTIMATCHQUERY.toString()))
+ && ! ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchQueryContext.class)
+ .isEmpty()) {
+ return new Function(
+ ctx.multiFieldRelevanceFunctionName().getText().toLowerCase(),
+ alternateMultiMatchArguments(ctx));
+ } else {
+ return new Function(
+ ctx.multiFieldRelevanceFunctionName().getText().toLowerCase(),
+ multiFieldRelevanceArguments(ctx));
+ }
}
private Function visitFunction(String functionName, FunctionArgsContext args) {
@@ -439,9 +455,13 @@ private QualifiedName visitIdentifiers(List identifiers) {
private void fillRelevanceArgs(List args,
ImmutableList.Builder builder) {
- args.forEach(v -> builder.add(new UnresolvedArgument(
- v.relevanceArgName().getText().toLowerCase(), new Literal(StringUtils.unquoteText(
- v.relevanceArgValue().getText()), DataType.STRING))));
+ // To support old syntax we must support argument keys as quoted strings.
+ args.forEach(v -> builder.add(v.argName == null
+ ? new UnresolvedArgument(v.relevanceArgName().getText().toLowerCase(),
+ new Literal(StringUtils.unquoteText(v.relevanceArgValue().getText()),
+ DataType.STRING))
+ : new UnresolvedArgument(StringUtils.unquoteText(v.argName.getText()).toLowerCase(),
+ new Literal(StringUtils.unquoteText(v.argVal.getText()), DataType.STRING))));
}
private List noFieldRelevanceArguments(
@@ -487,4 +507,41 @@ private List multiFieldRelevanceArguments(
fillRelevanceArgs(ctx.relevanceArg(), builder);
return builder.build();
}
+
+ /**
+ * Adds support for multi_match alternate syntax like
+ * MULTI_MATCH('query'='Dale', 'fields'='*name').
+ * @param ctx : Context for multi field relevance function.
+ * @return : Returns list of all arguments for relevance function.
+ */
+ private List alternateMultiMatchArguments(
+ OpenSearchSQLParser.MultiFieldRelevanceFunctionContext ctx) {
+ // all the arguments are defaulted to string values
+ // to skip environment resolving and function signature resolving
+ ImmutableList.Builder builder = ImmutableList.builder();
+ Map fieldAndWeightMap = new HashMap<>();
+
+ String[] fieldAndWeights = StringUtils.unquoteText(
+ ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchFieldContext.class)
+ .stream().findFirst().get().argVal.getText()).split(",");
+
+ for (var fieldAndWeight : fieldAndWeights) {
+ String[] splitFieldAndWeights = fieldAndWeight.split("\\^");
+ fieldAndWeightMap.put(splitFieldAndWeights[0],
+ splitFieldAndWeights.length > 1 ? Float.parseFloat(splitFieldAndWeights[1]) : 1F);
+ }
+ builder.add(new UnresolvedArgument("fields",
+ new RelevanceFieldList(fieldAndWeightMap)));
+
+ ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchQueryContext.class)
+ .stream().findFirst().ifPresent(
+ arg ->
+ builder.add(new UnresolvedArgument("query",
+ new Literal(StringUtils.unquoteText(arg.argVal.getText()), DataType.STRING)))
+ );
+
+ fillRelevanceArgs(ctx.relevanceArg(), builder);
+
+ return builder.build();
+ }
}
diff --git a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java
index 6b78376d45..c5676c2b6e 100644
--- a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java
+++ b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java
@@ -193,6 +193,16 @@ public void can_parse_now_like_functions(String name, Boolean hasFsp, Boolean ha
@Test
public void can_parse_multi_match_relevance_function() {
+ assertNotNull(parser.parse(
+ "SELECT id FROM test WHERE multimatch(\"fields\"=\"field\", query=\"query\")"));
+ assertNotNull(parser.parse(
+ "SELECT id FROM test WHERE multimatchquery(fields=\"field\", \"query\"=\"query\")"));
+ assertNotNull(parser.parse(
+ "SELECT id FROM test WHERE multi_match(\"fields\"=\"field\", \"query\"=\"query\")"));
+ assertNotNull(parser.parse(
+ "SELECT id FROM test WHERE multi_match(\'fields\'=\'field\', \'query\'=\'query\')"));
+ assertNotNull(parser.parse(
+ "SELECT id FROM test WHERE multi_match(fields=\'field\', query=\'query\')"));
assertNotNull(parser.parse(
"SELECT id FROM test WHERE multi_match(['address'], 'query')"));
assertNotNull(parser.parse(
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 cb00ea2f18..8db5ae79c9 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
@@ -501,9 +501,47 @@ public void relevanceMulti_match() {
unresolvedArg("analyzer", stringLiteral("keyword")),
unresolvedArg("operator", stringLiteral("AND"))),
buildExprAst("multi_match(['field1', 'field2' ^ 3.2], 'search query',"
+ + "analyzer='keyword', 'operator'='AND')"));
+ }
+
+ @Test
+ public void relevanceMultimatch_alternate_parameter_syntax() {
+ assertEquals(AstDSL.function("multimatch",
+ unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
+ "field1", 1F, "field2", 2F))),
+ unresolvedArg("query", stringLiteral("search query"))),
+ buildExprAst("multimatch(query='search query', fields=['field1^1.0,field2^2.0'])")
+ );
+
+ assertEquals(AstDSL.function("multimatch",
+ unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
+ "field1", 1F, "field2", 2F))),
+ unresolvedArg("query", stringLiteral("search query")),
+ unresolvedArg("analyzer", stringLiteral("keyword")),
+ unresolvedArg("operator", stringLiteral("AND"))),
+ buildExprAst("multimatch(query='search query', fields=['field1^1.0,field2^2.0'],"
+ "analyzer='keyword', operator='AND')"));
}
+ @Test
+ public void relevanceMultimatchquery_alternate_parameter_syntax() {
+ assertEquals(AstDSL.function("multimatchquery",
+ unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
+ "field", 1F))),
+ unresolvedArg("query", stringLiteral("search query"))),
+ buildExprAst("multimatchquery(query='search query', fields='field')")
+ );
+
+ assertEquals(AstDSL.function("multimatchquery",
+ unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
+ "field", 1F))),
+ unresolvedArg("query", stringLiteral("search query")),
+ unresolvedArg("analyzer", stringLiteral("keyword")),
+ unresolvedArg("operator", stringLiteral("AND"))),
+ buildExprAst("multimatchquery(query='search query', fields='field',"
+ + "analyzer='keyword', 'operator'='AND')"));
+ }
+
@Test
public void relevanceSimple_query_string() {
assertEquals(AstDSL.function("simple_query_string",