Skip to content

Commit 7ab5465

Browse files
authored
Merge pull request #1245 from Bit-Quill/backport/backport-1166-to-2.x
[Backport 2.x] Add Alternate Syntax For Match_Query And Other Functions
2 parents 3ab1f78 + 8a67667 commit 7ab5465

File tree

9 files changed

+323
-5
lines changed

9 files changed

+323
-5
lines changed

docs/user/dql/functions.rst

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,6 +3044,16 @@ Another example to show how to set custom values for the optional parameters::
30443044
| Bond |
30453045
+------------+
30463046

3047+
The matchquery function also supports an alternative syntax::
3048+
3049+
os> SELECT firstname FROM accounts WHERE firstname = matchquery('Hattie');
3050+
fetched rows / total rows = 1/1
3051+
+-------------+
3052+
| firstname |
3053+
|-------------|
3054+
| Hattie |
3055+
+-------------+
3056+
30473057
MATCH_QUERY
30483058
-----
30493059

@@ -3073,6 +3083,16 @@ Another example to show how to set custom values for the optional parameters::
30733083
| Bond |
30743084
+------------+
30753085

3086+
The match_query function also supports an alternative syntax::
3087+
3088+
os> SELECT firstname FROM accounts WHERE firstname = match_query('Hattie');
3089+
fetched rows / total rows = 1/1
3090+
+-------------+
3091+
| firstname |
3092+
|-------------|
3093+
| Hattie |
3094+
+-------------+
3095+
30763096

30773097
MATCH_PHRASE
30783098
------------
@@ -3112,6 +3132,23 @@ Another example to show how to set custom values for the optional parameters::
31123132
| Alan Alexander Milne | Winnie-the-Pooh |
31133133
+----------------------+--------------------------+
31143134

3135+
The match_phrase function also supports an alternative syntax::
3136+
3137+
os> SELECT firstname FROM accounts WHERE firstname = match_phrase('Hattie');
3138+
fetched rows / total rows = 1/1
3139+
+-------------+
3140+
| firstname |
3141+
|-------------|
3142+
| Hattie |
3143+
+-------------+
3144+
3145+
os> SELECT firstname FROM accounts WHERE firstname = matchphrase('Hattie');
3146+
fetched rows / total rows = 1/1
3147+
+-------------+
3148+
| firstname |
3149+
|-------------|
3150+
| Hattie |
3151+
+-------------+
31153152

31163153
MATCH_BOOL_PREFIX
31173154
-----
@@ -3255,6 +3292,24 @@ Another example to show how to set custom values for the optional parameters::
32553292
| 1 | The House at Pooh Corner | Alan Alexander Milne |
32563293
+------+--------------------------+----------------------+
32573294

3295+
The multi_match function also supports an alternative syntax::
3296+
3297+
os> SELECT firstname FROM accounts WHERE firstname = multi_match('Hattie');
3298+
fetched rows / total rows = 1/1
3299+
+-------------+
3300+
| firstname |
3301+
|-------------|
3302+
| Hattie |
3303+
+-------------+
3304+
3305+
os> SELECT firstname FROM accounts WHERE firstname = multimatch('Hattie');
3306+
fetched rows / total rows = 1/1
3307+
+-------------+
3308+
| firstname |
3309+
|-------------|
3310+
| Hattie |
3311+
+-------------+
3312+
32583313
SIMPLE_QUERY_STRING
32593314
-------------------
32603315

integ-test/src/test/java/org/opensearch/sql/legacy/MethodQueryIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void matchQueryTest() throws IOException {
5454
"select address from %s where address= matchQuery('880 Holmes Lane') limit 3",
5555
TestsConstants.TEST_INDEX_ACCOUNT));
5656
Assert.assertThat(result,
57-
containsString("{\"match\":{\"address\":{\"query\":\"880 Holmes Lane\""));
57+
containsString("{\\\"match\\\":{\\\"address\\\":{\\\"query\\\":\\\"880 Holmes Lane\\\""));
5858
}
5959

6060
/**

integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public void match_query_in_having() throws IOException {
103103
}
104104

105105
@Test
106-
public void alternate_syntaxes_return_the_same_results() throws IOException {
106+
public void match_aliases_return_the_same_results() throws IOException {
107107
String query1 = "SELECT lastname FROM "
108108
+ TEST_INDEX_ACCOUNT + " HAVING match(firstname, 'Nanette')";
109109
JSONObject result1 = executeJdbcRequest(query1);
@@ -116,4 +116,35 @@ public void alternate_syntaxes_return_the_same_results() throws IOException {
116116
assertEquals(result1.getInt("total"), result2.getInt("total"));
117117
assertEquals(result1.getInt("total"), result3.getInt("total"));
118118
}
119+
120+
@Test
121+
public void match_query_alternate_syntax() throws IOException {
122+
JSONObject result = executeJdbcRequest(
123+
"SELECT lastname FROM " + TEST_INDEX_ACCOUNT + " WHERE lastname = match_query('Bates')");
124+
verifySchema(result, schema("lastname", "text"));
125+
verifyDataRows(result, rows("Bates"));
126+
}
127+
128+
@Test
129+
public void matchquery_alternate_syntax() throws IOException {
130+
JSONObject result = executeJdbcRequest(
131+
"SELECT lastname FROM " + TEST_INDEX_ACCOUNT + " WHERE lastname = matchquery('Bates')");
132+
verifySchema(result, schema("lastname", "text"));
133+
verifyDataRows(result, rows("Bates"));
134+
}
135+
136+
@Test
137+
public void match_alternate_syntaxes_return_the_same_results() throws IOException {
138+
String query1 = "SELECT * FROM "
139+
+ TEST_INDEX_ACCOUNT + " WHERE match(firstname, 'Nanette')";
140+
JSONObject result1 = executeJdbcRequest(query1);
141+
String query2 = "SELECT * FROM "
142+
+ TEST_INDEX_ACCOUNT + " WHERE firstname = match_query('Nanette')";
143+
JSONObject result2 = executeJdbcRequest(query2);
144+
String query3 = "SELECT * FROM "
145+
+ TEST_INDEX_ACCOUNT + " WHERE firstname = matchquery('Nanette')";
146+
JSONObject result3 = executeJdbcRequest(query3);
147+
assertEquals(result1.getInt("total"), result2.getInt("total"));
148+
assertEquals(result1.getInt("total"), result3.getInt("total"));
149+
}
119150
}

integ-test/src/test/java/org/opensearch/sql/sql/MatchPhraseIT.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void test_match_phrase_with_slop() throws IOException {
5151
}
5252

5353
@Test
54-
public void test_alternate_syntax_for_match_phrase_returns_same_result() throws IOException {
54+
public void test_aliases_for_match_phrase_returns_same_result() throws IOException {
5555
String query1 = "SELECT phrase FROM %s WHERE matchphrase(phrase, 'quick fox')";
5656
String query2 = "SELECT phrase FROM %s WHERE match_phrase(phrase, 'quick fox')";
5757
String query3 = "SELECT phrase FROM %s WHERE matchphrasequery(phrase, 'quick fox')";
@@ -61,4 +61,30 @@ public void test_alternate_syntax_for_match_phrase_returns_same_result() throws
6161
assertTrue(result1.similar(result2));
6262
assertTrue(result1.similar(result3));
6363
}
64+
65+
@Test
66+
public void match_phrase_alternate_syntax() throws IOException {
67+
String query = "SELECT phrase FROM %s WHERE phrase = match_phrase('quick fox')";
68+
JSONObject result = executeJdbcRequest(String.format(query, TEST_INDEX_PHRASE));
69+
verifyDataRows(result, rows("quick fox"), rows("quick fox here"));
70+
}
71+
72+
@Test
73+
public void matchphrase_alternate_syntax() throws IOException {
74+
String query = "SELECT phrase FROM %s WHERE phrase = matchphrase('quick fox')";
75+
JSONObject result = executeJdbcRequest(String.format(query, TEST_INDEX_PHRASE));
76+
verifyDataRows(result, rows("quick fox"), rows("quick fox here"));
77+
}
78+
79+
@Test
80+
public void match_phrase_alternate_syntaxes_return_the_same_results() throws IOException {
81+
String query1 = "SELECT phrase FROM %s WHERE matchphrase(phrase, 'quick fox')";
82+
String query2 = "SELECT phrase FROM %s WHERE phrase = matchphrase('quick fox')";
83+
String query3 = "SELECT phrase FROM %s WHERE phrase = match_phrase('quick fox')";
84+
JSONObject result1 = executeJdbcRequest(String.format(query1, TEST_INDEX_PHRASE));
85+
JSONObject result2 = executeJdbcRequest(String.format(query2, TEST_INDEX_PHRASE));
86+
JSONObject result3 = executeJdbcRequest(String.format(query3, TEST_INDEX_PHRASE));
87+
assertTrue(result1.similar(result2));
88+
assertTrue(result1.similar(result3));
89+
}
6490
}

integ-test/src/test/java/org/opensearch/sql/sql/MultiMatchIT.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,35 @@ public void test_all_params_multimatchquery_alternate_parameter_syntax() {
124124
JSONObject result = executeJdbcRequest(query);
125125
assertEquals(2, result.getInt("total"));
126126
}
127+
128+
@Test
129+
public void multi_match_alternate_syntax() throws IOException {
130+
String query = "SELECT Id FROM " + TEST_INDEX_BEER
131+
+ " WHERE CreationDate = multi_match('2014-01-22');";
132+
var result = new JSONObject(executeQuery(query, "jdbc"));
133+
assertEquals(8, result.getInt("total"));
134+
}
135+
136+
@Test
137+
public void multimatch_alternate_syntax() throws IOException {
138+
String query = "SELECT Id FROM " + TEST_INDEX_BEER
139+
+ " WHERE CreationDate = multimatch('2014-01-22');";
140+
var result = new JSONObject(executeQuery(query, "jdbc"));
141+
assertEquals(8, result.getInt("total"));
142+
}
143+
144+
@Test
145+
public void multi_match_alternate_syntaxes_return_the_same_results() throws IOException {
146+
String query1 = "SELECT Id FROM " + TEST_INDEX_BEER
147+
+ " WHERE multi_match(['CreationDate'], '2014-01-22');";
148+
String query2 = "SELECT Id FROM " + TEST_INDEX_BEER
149+
+ " WHERE CreationDate = multi_match('2014-01-22');";
150+
String query3 = "SELECT Id FROM " + TEST_INDEX_BEER
151+
+ " WHERE CreationDate = multimatch('2014-01-22');";
152+
var result1 = new JSONObject(executeQuery(query1, "jdbc"));
153+
var result2 = new JSONObject(executeQuery(query2, "jdbc"));
154+
var result3 = new JSONObject(executeQuery(query3, "jdbc"));
155+
assertEquals(result1.getInt("total"), result2.getInt("total"));
156+
assertEquals(result1.getInt("total"), result3.getInt("total"));
157+
}
127158
}

sql/src/main/antlr/OpenSearchSQLParser.g4

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ positionFunction
328328
: POSITION LR_BRACKET functionArg IN functionArg RR_BRACKET
329329
;
330330

331+
matchQueryAltSyntaxFunction
332+
: field=relevanceField EQUAL_SYMBOL MATCH_QUERY LR_BRACKET query=relevanceQuery RR_BRACKET
333+
;
334+
331335
scalarFunctionName
332336
: mathematicalFunctionName
333337
| dateTimeFunctionName
@@ -345,7 +349,8 @@ specificFunction
345349
;
346350

347351
relevanceFunction
348-
: noFieldRelevanceFunction | singleFieldRelevanceFunction | multiFieldRelevanceFunction
352+
: noFieldRelevanceFunction | singleFieldRelevanceFunction | multiFieldRelevanceFunction | altSingleFieldRelevanceFunction | altMultiFieldRelevanceFunction
353+
349354
;
350355

351356
noFieldRelevanceFunction
@@ -367,6 +372,14 @@ multiFieldRelevanceFunction
367372
alternateMultiMatchQuery COMMA alternateMultiMatchField (COMMA relevanceArg)* RR_BRACKET
368373
;
369374

375+
altSingleFieldRelevanceFunction
376+
: field=relevanceField EQUAL_SYMBOL altSyntaxFunctionName=altSingleFieldRelevanceFunctionName LR_BRACKET query=relevanceQuery (COMMA relevanceArg)* RR_BRACKET
377+
;
378+
379+
altMultiFieldRelevanceFunction
380+
: field=relevanceField EQUAL_SYMBOL altSyntaxFunctionName=altMultiFieldRelevanceFunctionName LR_BRACKET query=relevanceQuery (COMMA relevanceArg)* RR_BRACKET
381+
;
382+
370383
convertedDataType
371384
: typeName=DATE
372385
| typeName=TIME
@@ -487,6 +500,18 @@ multiFieldRelevanceFunctionName
487500
| QUERY_STRING
488501
;
489502

503+
altSingleFieldRelevanceFunctionName
504+
: MATCH_QUERY
505+
| MATCHQUERY
506+
| MATCH_PHRASE
507+
| MATCHPHRASE
508+
;
509+
510+
altMultiFieldRelevanceFunctionName
511+
: MULTI_MATCH
512+
| MULTIMATCH
513+
;
514+
490515
functionArgs
491516
: (functionArg (COMMA functionArg)*)?
492517
;

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
import static org.opensearch.sql.expression.function.BuiltinFunctionName.NOT_LIKE;
1717
import static org.opensearch.sql.expression.function.BuiltinFunctionName.POSITION;
1818
import static org.opensearch.sql.expression.function.BuiltinFunctionName.REGEXP;
19+
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AltMultiFieldRelevanceFunctionContext;
20+
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AltSingleFieldRelevanceFunctionContext;
1921
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AlternateMultiMatchFieldContext;
20-
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AlternateMultiMatchQueryContext;
2122
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.BetweenPredicateContext;
2223
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.BinaryComparisonPredicateContext;
2324
import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.BooleanContext;
@@ -96,6 +97,7 @@
9697
import org.opensearch.sql.ast.tree.Sort.SortOption;
9798
import org.opensearch.sql.common.utils.StringUtils;
9899
import org.opensearch.sql.expression.function.BuiltinFunctionName;
100+
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AlternateMultiMatchQueryContext;
99101
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AndExpressionContext;
100102
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.ColumnNameContext;
101103
import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.IdentContext;
@@ -433,6 +435,14 @@ public UnresolvedExpression visitSingleFieldRelevanceFunction(
433435
singleFieldRelevanceArguments(ctx));
434436
}
435437

438+
@Override
439+
public UnresolvedExpression visitAltSingleFieldRelevanceFunction(
440+
AltSingleFieldRelevanceFunctionContext ctx) {
441+
return new Function(
442+
ctx.altSyntaxFunctionName.getText().toLowerCase(),
443+
altSingleFieldRelevanceFunctionArguments(ctx));
444+
}
445+
436446
@Override
437447
public UnresolvedExpression visitMultiFieldRelevanceFunction(
438448
MultiFieldRelevanceFunctionContext ctx) {
@@ -454,6 +464,14 @@ public UnresolvedExpression visitMultiFieldRelevanceFunction(
454464
}
455465
}
456466

467+
@Override
468+
public UnresolvedExpression visitAltMultiFieldRelevanceFunction(
469+
AltMultiFieldRelevanceFunctionContext ctx) {
470+
return new Function(
471+
ctx.altSyntaxFunctionName.getText().toLowerCase(),
472+
altMultiFieldRelevanceFunctionArguments(ctx));
473+
}
474+
457475
private Function buildFunction(String functionName,
458476
List<FunctionArgContext> arg) {
459477
return new Function(
@@ -510,6 +528,18 @@ private List<UnresolvedExpression> singleFieldRelevanceArguments(
510528
}
511529

512530

531+
private List<UnresolvedExpression> altSingleFieldRelevanceFunctionArguments(
532+
AltSingleFieldRelevanceFunctionContext ctx) {
533+
// all the arguments are defaulted to string values
534+
// to skip environment resolving and function signature resolving
535+
ImmutableList.Builder<UnresolvedExpression> builder = ImmutableList.builder();
536+
builder.add(new UnresolvedArgument("field",
537+
new QualifiedName(StringUtils.unquoteText(ctx.field.getText()))));
538+
builder.add(new UnresolvedArgument("query",
539+
new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING)));
540+
fillRelevanceArgs(ctx.relevanceArg(), builder);
541+
return builder.build();
542+
}
513543

514544
private List<UnresolvedExpression> multiFieldRelevanceArguments(
515545
MultiFieldRelevanceFunctionContext ctx) {
@@ -565,4 +595,19 @@ private List<UnresolvedExpression> alternateMultiMatchArguments(
565595

566596
return builder.build();
567597
}
598+
599+
private List<UnresolvedExpression> altMultiFieldRelevanceFunctionArguments(
600+
AltMultiFieldRelevanceFunctionContext ctx) {
601+
// all the arguments are defaulted to string values
602+
// to skip environment resolving and function signature resolving
603+
var map = new HashMap<String, Float>();
604+
map.put(ctx.field.getText(), 1F);
605+
ImmutableList.Builder<UnresolvedExpression> builder = ImmutableList.builder();
606+
var fields = new RelevanceFieldList(map);
607+
builder.add(new UnresolvedArgument("fields", fields));
608+
builder.add(new UnresolvedArgument("query",
609+
new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING)));
610+
fillRelevanceArgs(ctx.relevanceArg(), builder);
611+
return builder.build();
612+
}
568613
}

sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,30 @@ private static Stream<String> matchPhraseComplexQueries() {
509509
);
510510
}
511511

512+
@Test
513+
public void canParseMatchQueryAlternateSyntax() {
514+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchquery('query')"));
515+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchquery(\"query\")"));
516+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_query('query')"));
517+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_query(\"query\")"));
518+
}
519+
520+
@Test
521+
public void canParseMatchPhraseAlternateSyntax() {
522+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_phrase('query')"));
523+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_phrase(\"query\")"));
524+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchphrase('query')"));
525+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchphrase(\"query\")"));
526+
}
527+
528+
@Test
529+
public void canParseMultiMatchAlternateSyntax() {
530+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multi_match('query')"));
531+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multi_match(\"query\")"));
532+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multimatch('query')"));
533+
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multimatch(\"query\")"));
534+
}
535+
512536
private static Stream<String> matchPhraseQueryComplexQueries() {
513537
return Stream.of(
514538
"SELECT * FROM t WHERE matchphrasequery(c, 3)",

0 commit comments

Comments
 (0)