Skip to content

Commit be6214c

Browse files
committed
Adding support for quoted relevance arg parameter keys. Adding multimatchquery alternate syntax support for fields as a list with weights.
Signed-off-by: forestmvey <forestv@bitquilltech.com>
1 parent ea0f277 commit be6214c

File tree

4 files changed

+37
-42
lines changed

4 files changed

+37
-42
lines changed

core/src/main/java/org/opensearch/sql/expression/function/OpenSearchFunctions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private static FunctionResolver match_phrase(BuiltinFunctionName matchPhrase) {
6262
}
6363

6464
private static FunctionResolver multi_match(BuiltinFunctionName matchPhrase) {
65-
FunctionName funcName = matchPhrase.getName();
65+
FunctionName funcName = BuiltinFunctionName.MULTI_MATCH.getName();
6666
return new RelevanceFunctionResolver(funcName, STRUCT);
6767
}
6868

sql/src/main/antlr/OpenSearchSQLParser.g4

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,7 @@ multiFieldRelevanceFunction
348348
LT_SQR_PRTHS field=relevanceFieldAndWeight (COMMA field=relevanceFieldAndWeight)* RT_SQR_PRTHS
349349
COMMA query=relevanceQuery (COMMA relevanceArg)* RR_BRACKET
350350
| multiFieldRelevanceFunctionName LR_BRACKET
351-
alternateMultiMatchQuery COMMA alternateMultiMatchField
352-
(COMMA alternateMultiMatchOptionalArg)* RR_BRACKET
351+
alternateMultiMatchQuery COMMA alternateMultiMatchField (COMMA relevanceArg)* RR_BRACKET
353352
;
354353

355354
convertedDataType
@@ -454,6 +453,7 @@ functionArg
454453

455454
relevanceArg
456455
: relevanceArgName EQUAL_SYMBOL relevanceArgValue
456+
| argName=stringLiteral EQUAL_SYMBOL argVal=relevanceArgValue
457457
;
458458

459459
highlightArg
@@ -514,11 +514,6 @@ alternateMultiMatchArgVal
514514
| stringLiteral
515515
;
516516

517-
alternateMultiMatchOptionalArg
518-
: relevanceArg
519-
| argName=stringLiteral EQUAL_SYMBOL argVal=relevanceArgValue
520-
;
521-
522517
alternateMultiMatchQuery
523518
: argName=alternateMultiMatchArgName EQUAL_SYMBOL argVal=alternateMultiMatchArgVal
524519
;

sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
import com.google.common.collect.ImmutableMap;
5353
import java.util.Arrays;
5454
import java.util.Collections;
55+
import java.util.HashMap;
5556
import java.util.List;
57+
import java.util.Map;
5658
import java.util.stream.Collectors;
5759
import org.antlr.v4.runtime.RuleContext;
5860
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -79,6 +81,7 @@
7981
import org.opensearch.sql.ast.expression.When;
8082
import org.opensearch.sql.ast.expression.WindowFunction;
8183
import org.opensearch.sql.ast.tree.Sort.SortOption;
84+
import org.opensearch.sql.catalog.model.auth.AuthenticationType;
8285
import org.opensearch.sql.common.utils.StringUtils;
8386
import org.opensearch.sql.exception.SemanticCheckException;
8487
import org.opensearch.sql.expression.function.BuiltinFunctionName;
@@ -403,14 +406,11 @@ public UnresolvedExpression visitMultiFieldRelevanceFunction(
403406
MultiFieldRelevanceFunctionContext ctx) {
404407
// To support alternate syntax for MULTI_MATCH like
405408
// 'MULTI_MATCH('query'='query_val', 'fields'='*fields_val')'
406-
if ((StringUtils.unquoteText(ctx.multiFieldRelevanceFunctionName().getText().toUpperCase())
407-
.equals(BuiltinFunctionName.MULTI_MATCH.toString())
408-
|| StringUtils.unquoteText(ctx.multiFieldRelevanceFunctionName().getText().toUpperCase())
409-
.equals(BuiltinFunctionName.MULTIMATCH.toString())
410-
|| StringUtils.unquoteText(ctx.multiFieldRelevanceFunctionName().getText().toUpperCase())
411-
.equals(BuiltinFunctionName.MULTIMATCHQUERY.toString()))
412-
&& ! ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchQueryContext.class)
413-
.isEmpty()) {
409+
String funcName = StringUtils.unquoteText(ctx.multiFieldRelevanceFunctionName().getText());
410+
if ((funcName.equalsIgnoreCase(BuiltinFunctionName.MULTI_MATCH.toString())
411+
|| funcName.equalsIgnoreCase(BuiltinFunctionName.MULTIMATCH.toString())
412+
|| funcName.equalsIgnoreCase(BuiltinFunctionName.MULTIMATCHQUERY.toString()))
413+
&& ! ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchQueryContext.class).isEmpty()) {
414414
return new Function(
415415
ctx.multiFieldRelevanceFunctionName().getText().toLowerCase(),
416416
alternateMultiMatchArguments(ctx));
@@ -456,9 +456,13 @@ private QualifiedName visitIdentifiers(List<IdentContext> identifiers) {
456456

457457
private void fillRelevanceArgs(List<OpenSearchSQLParser.RelevanceArgContext> args,
458458
ImmutableList.Builder<UnresolvedExpression> builder) {
459-
args.forEach(v -> builder.add(new UnresolvedArgument(
460-
v.relevanceArgName().getText().toLowerCase(), new Literal(StringUtils.unquoteText(
461-
v.relevanceArgValue().getText()), DataType.STRING))));
459+
// To support old syntax we must support argument keys as quoted strings.
460+
args.forEach(v -> builder.add(v.relevanceArgName() != null
461+
? new UnresolvedArgument(v.relevanceArgName().getText().toLowerCase(),
462+
new Literal(StringUtils.unquoteText(v.relevanceArgValue().getText()),
463+
DataType.STRING))
464+
: new UnresolvedArgument(StringUtils.unquoteText(v.argName.getText()).toLowerCase(),
465+
new Literal(StringUtils.unquoteText(v.argVal.getText()), DataType.STRING))));
462466
}
463467

464468
private List<UnresolvedExpression> noFieldRelevanceArguments(
@@ -516,13 +520,19 @@ private List<UnresolvedExpression> alternateMultiMatchArguments(
516520
// all the arguments are defaulted to string values
517521
// to skip environment resolving and function signature resolving
518522
ImmutableList.Builder<UnresolvedExpression> builder = ImmutableList.builder();
519-
ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchFieldContext.class)
520-
.stream().findFirst().ifPresent(
521-
arg ->
522-
builder.add(new UnresolvedArgument("fields",
523-
new RelevanceFieldList(
524-
ImmutableMap.of(StringUtils.unquoteText(arg.argVal.getText()), 1F))))
525-
);
523+
Map<String, Float> fieldAndWeightMap = new HashMap<>();
524+
525+
String[] fieldAndWeights = StringUtils.unquoteText(
526+
ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchFieldContext.class)
527+
.stream().findFirst().get().argVal.getText()).split(",");
528+
529+
for (var fieldAndWeight : fieldAndWeights) {
530+
String[] splitFieldAndWeights = fieldAndWeight.split("\\^");
531+
fieldAndWeightMap.put(splitFieldAndWeights[0],
532+
splitFieldAndWeights.length > 1 ? Float.parseFloat(splitFieldAndWeights[1]) : 1F);
533+
}
534+
builder.add(new UnresolvedArgument("fields",
535+
new RelevanceFieldList(fieldAndWeightMap)));
526536

527537
ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchQueryContext.class)
528538
.stream().findFirst().ifPresent(
@@ -531,14 +541,7 @@ private List<UnresolvedExpression> alternateMultiMatchArguments(
531541
new Literal(StringUtils.unquoteText(arg.argVal.getText()), DataType.STRING)))
532542
);
533543

534-
// To support old syntax we must support argument keys as quoted strings.
535-
ctx.getRuleContexts(OpenSearchSQLParser.AlternateMultiMatchOptionalArgContext.class)
536-
.forEach(v -> builder.add(v.relevanceArg() != null
537-
? new UnresolvedArgument(v.relevanceArg().relevanceArgName().getText().toLowerCase(),
538-
new Literal(StringUtils.unquoteText(v.relevanceArg().relevanceArgValue().getText()),
539-
DataType.STRING))
540-
: new UnresolvedArgument(StringUtils.unquoteText(v.argName.getText()).toLowerCase(),
541-
new Literal(StringUtils.unquoteText(v.argVal.getText()), DataType.STRING))));
544+
fillRelevanceArgs(ctx.relevanceArg(), builder);
542545

543546
return builder.build();
544547
}

sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
package org.opensearch.sql.sql.parser;
88

99
import static org.junit.jupiter.api.Assertions.assertEquals;
10-
import static org.junit.jupiter.api.Assertions.assertThrows;
1110
import static org.opensearch.sql.ast.dsl.AstDSL.aggregate;
1211
import static org.opensearch.sql.ast.dsl.AstDSL.and;
1312
import static org.opensearch.sql.ast.dsl.AstDSL.booleanLiteral;
@@ -38,7 +37,6 @@
3837
import java.util.HashMap;
3938
import org.antlr.v4.runtime.CommonTokenStream;
4039
import org.apache.commons.lang3.tuple.ImmutablePair;
41-
import org.junit.jupiter.api.Assertions;
4240
import org.junit.jupiter.api.Test;
4341
import org.opensearch.sql.ast.Node;
4442
import org.opensearch.sql.ast.dsl.AstDSL;
@@ -48,7 +46,6 @@
4846
import org.opensearch.sql.ast.tree.Sort.SortOption;
4947
import org.opensearch.sql.common.antlr.CaseInsensitiveCharStream;
5048
import org.opensearch.sql.common.antlr.SyntaxAnalysisErrorListener;
51-
import org.opensearch.sql.exception.SemanticCheckException;
5249
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLLexer;
5350
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser;
5451

@@ -504,25 +501,25 @@ public void relevanceMulti_match() {
504501
unresolvedArg("analyzer", stringLiteral("keyword")),
505502
unresolvedArg("operator", stringLiteral("AND"))),
506503
buildExprAst("multi_match(['field1', 'field2' ^ 3.2], 'search query',"
507-
+ "analyzer='keyword', operator='AND')"));
504+
+ "analyzer='keyword', 'operator'='AND')"));
508505
}
509506

510507
@Test
511508
public void relevanceMultimatch_alternate_parameter_syntax() {
512509
assertEquals(AstDSL.function("multimatch",
513510
unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
514-
"field", 1F))),
511+
"field1", 1F, "field2", 2F))),
515512
unresolvedArg("query", stringLiteral("search query"))),
516-
buildExprAst("multimatch(query='search query', fields='field')")
513+
buildExprAst("multimatch(query='search query', fields=['field1^1.0,field2^2.0'])")
517514
);
518515

519516
assertEquals(AstDSL.function("multimatch",
520517
unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
521-
"field", 1F))),
518+
"field1", 1F, "field2", 2F))),
522519
unresolvedArg("query", stringLiteral("search query")),
523520
unresolvedArg("analyzer", stringLiteral("keyword")),
524521
unresolvedArg("operator", stringLiteral("AND"))),
525-
buildExprAst("multimatch(query='search query', fields='field',"
522+
buildExprAst("multimatch(query='search query', fields=['field1^1.0,field2^2.0'],"
526523
+ "analyzer='keyword', operator='AND')"));
527524
}
528525

0 commit comments

Comments
 (0)