Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Alternate Syntax For Match_Query And Other Functions #1166

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2888,6 +2888,16 @@ Another example to show how to set custom values for the optional parameters::
| Bond |
+------------+

The matchquery function also supports an alternative syntax::

os> SELECT firstname FROM accounts WHERE firstname = matchquery('Hattie');
fetched rows / total rows = 1/1
+-------------+
| firstname |
|-------------|
| Hattie |
+-------------+

MATCH_QUERY
-----

Expand Down Expand Up @@ -2917,6 +2927,16 @@ Another example to show how to set custom values for the optional parameters::
| Bond |
+------------+

The match_query function also supports an alternative syntax::

os> SELECT firstname FROM accounts WHERE firstname = match_query('Hattie');
fetched rows / total rows = 1/1
+-------------+
| firstname |
|-------------|
| Hattie |
+-------------+


MATCH_PHRASE
------------
Expand Down Expand Up @@ -2956,6 +2976,23 @@ Another example to show how to set custom values for the optional parameters::
| Alan Alexander Milne | Winnie-the-Pooh |
+----------------------+--------------------------+

The match_phrase function also supports an alternative syntax::

os> SELECT firstname FROM accounts WHERE firstname = match_phrase('Hattie');
fetched rows / total rows = 1/1
+-------------+
| firstname |
|-------------|
| Hattie |
+-------------+

os> SELECT firstname FROM accounts WHERE firstname = matchphrase('Hattie');
fetched rows / total rows = 1/1
+-------------+
| firstname |
|-------------|
| Hattie |
+-------------+

MATCH_BOOL_PREFIX
-----
Expand Down Expand Up @@ -3099,6 +3136,24 @@ Another example to show how to set custom values for the optional parameters::
| 1 | The House at Pooh Corner | Alan Alexander Milne |
+------+--------------------------+----------------------+

The multi_match function also supports an alternative syntax::

os> SELECT firstname FROM accounts WHERE firstname = multi_match('Hattie');
fetched rows / total rows = 1/1
+-------------+
| firstname |
|-------------|
| Hattie |
+-------------+

os> SELECT firstname FROM accounts WHERE firstname = multimatch('Hattie');
fetched rows / total rows = 1/1
+-------------+
| firstname |
|-------------|
| Hattie |
+-------------+

SIMPLE_QUERY_STRING
-------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void matchQueryTest() throws IOException {
"select address from %s where address= matchQuery('880 Holmes Lane') limit 3",
TestsConstants.TEST_INDEX_ACCOUNT));
Assert.assertThat(result,
containsString("{\"match\":{\"address\":{\"query\":\"880 Holmes Lane\""));
containsString("{\\\"match\\\":{\\\"address\\\":{\\\"query\\\":\\\"880 Holmes Lane\\\""));
}

/**
Expand Down
33 changes: 32 additions & 1 deletion integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void match_query_in_having() throws IOException {
}

@Test
public void alternate_syntaxes_return_the_same_results() throws IOException {
public void match_aliases_return_the_same_results() throws IOException {
String query1 = "SELECT lastname FROM "
+ TEST_INDEX_ACCOUNT + " HAVING match(firstname, 'Nanette')";
JSONObject result1 = executeJdbcRequest(query1);
Expand All @@ -79,4 +79,35 @@ public void alternate_syntaxes_return_the_same_results() throws IOException {
assertEquals(result1.getInt("total"), result2.getInt("total"));
assertEquals(result1.getInt("total"), result3.getInt("total"));
}

@Test
public void match_query_alternate_syntax() throws IOException {
JSONObject result = executeJdbcRequest(
"SELECT lastname FROM " + TEST_INDEX_ACCOUNT + " WHERE lastname = match_query('Bates')");
verifySchema(result, schema("lastname", "text"));
verifyDataRows(result, rows("Bates"));
}

@Test
public void matchquery_alternate_syntax() throws IOException {
JSONObject result = executeJdbcRequest(
"SELECT lastname FROM " + TEST_INDEX_ACCOUNT + " WHERE lastname = matchquery('Bates')");
verifySchema(result, schema("lastname", "text"));
verifyDataRows(result, rows("Bates"));
}

@Test
public void match_alternate_syntaxes_return_the_same_results() throws IOException {
String query1 = "SELECT * FROM "
+ TEST_INDEX_ACCOUNT + " WHERE match(firstname, 'Nanette')";
JSONObject result1 = executeJdbcRequest(query1);
String query2 = "SELECT * FROM "
+ TEST_INDEX_ACCOUNT + " WHERE firstname = match_query('Nanette')";
JSONObject result2 = executeJdbcRequest(query2);
String query3 = "SELECT * FROM "
+ TEST_INDEX_ACCOUNT + " WHERE firstname = matchquery('Nanette')";
JSONObject result3 = executeJdbcRequest(query3);
assertEquals(result1.getInt("total"), result2.getInt("total"));
assertEquals(result1.getInt("total"), result3.getInt("total"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void test_match_phrase_with_slop() throws IOException {
}

@Test
public void test_alternate_syntax_for_match_phrase_returns_same_result() throws IOException {
public void test_aliases_for_match_phrase_returns_same_result() throws IOException {
String query1 = "SELECT phrase FROM %s WHERE matchphrase(phrase, 'quick fox')";
String query2 = "SELECT phrase FROM %s WHERE match_phrase(phrase, 'quick fox')";
String query3 = "SELECT phrase FROM %s WHERE matchphrasequery(phrase, 'quick fox')";
Expand All @@ -61,4 +61,30 @@ public void test_alternate_syntax_for_match_phrase_returns_same_result() throws
assertTrue(result1.similar(result2));
assertTrue(result1.similar(result3));
}

@Test
public void match_phrase_alternate_syntax() throws IOException {
String query = "SELECT phrase FROM %s WHERE phrase = match_phrase('quick fox')";
JSONObject result = executeJdbcRequest(String.format(query, TEST_INDEX_PHRASE));
verifyDataRows(result, rows("quick fox"), rows("quick fox here"));
}

@Test
public void matchphrase_alternate_syntax() throws IOException {
String query = "SELECT phrase FROM %s WHERE phrase = matchphrase('quick fox')";
JSONObject result = executeJdbcRequest(String.format(query, TEST_INDEX_PHRASE));
verifyDataRows(result, rows("quick fox"), rows("quick fox here"));
}

@Test
public void match_phrase_alternate_syntaxes_return_the_same_results() throws IOException {
String query1 = "SELECT phrase FROM %s WHERE matchphrase(phrase, 'quick fox')";
String query2 = "SELECT phrase FROM %s WHERE phrase = matchphrase('quick fox')";
String query3 = "SELECT phrase FROM %s WHERE phrase = match_phrase('quick fox')";
JSONObject result1 = executeJdbcRequest(String.format(query1, TEST_INDEX_PHRASE));
JSONObject result2 = executeJdbcRequest(String.format(query2, TEST_INDEX_PHRASE));
JSONObject result3 = executeJdbcRequest(String.format(query3, TEST_INDEX_PHRASE));
assertTrue(result1.similar(result2));
assertTrue(result1.similar(result3));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,35 @@ public void test_all_params_multimatchquery_alternate_parameter_syntax() {
JSONObject result = executeJdbcRequest(query);
assertEquals(2, result.getInt("total"));
}

@Test
public void multi_match_alternate_syntax() throws IOException {
String query = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE CreationDate = multi_match('2014-01-22');";
var result = new JSONObject(executeQuery(query, "jdbc"));
assertEquals(8, result.getInt("total"));
}

@Test
public void multimatch_alternate_syntax() throws IOException {
String query = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE CreationDate = multimatch('2014-01-22');";
var result = new JSONObject(executeQuery(query, "jdbc"));
assertEquals(8, result.getInt("total"));
}

@Test
public void multi_match_alternate_syntaxes_return_the_same_results() throws IOException {
String query1 = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE multi_match(['CreationDate'], '2014-01-22');";
String query2 = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE CreationDate = multi_match('2014-01-22');";
String query3 = "SELECT Id FROM " + TEST_INDEX_BEER
+ " WHERE CreationDate = multimatch('2014-01-22');";
var result1 = new JSONObject(executeQuery(query1, "jdbc"));
var result2 = new JSONObject(executeQuery(query2, "jdbc"));
var result3 = new JSONObject(executeQuery(query3, "jdbc"));
assertEquals(result1.getInt("total"), result2.getInt("total"));
assertEquals(result1.getInt("total"), result3.getInt("total"));
}
}
27 changes: 26 additions & 1 deletion sql/src/main/antlr/OpenSearchSQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ positionFunction
: POSITION LR_BRACKET functionArg IN functionArg RR_BRACKET
;

matchQueryAltSyntaxFunction
: field=relevanceField EQUAL_SYMBOL MATCH_QUERY LR_BRACKET query=relevanceQuery RR_BRACKET
;

scalarFunctionName
: mathematicalFunctionName
| dateTimeFunctionName
Expand All @@ -345,7 +349,8 @@ specificFunction
;

relevanceFunction
: noFieldRelevanceFunction | singleFieldRelevanceFunction | multiFieldRelevanceFunction
: noFieldRelevanceFunction | singleFieldRelevanceFunction | multiFieldRelevanceFunction | altSingleFieldRelevanceFunction | altMultiFieldRelevanceFunction

;

noFieldRelevanceFunction
Expand All @@ -367,6 +372,14 @@ multiFieldRelevanceFunction
alternateMultiMatchQuery COMMA alternateMultiMatchField (COMMA relevanceArg)* RR_BRACKET
;

altSingleFieldRelevanceFunction
: field=relevanceField EQUAL_SYMBOL altSyntaxFunctionName=altSingleFieldRelevanceFunctionName LR_BRACKET query=relevanceQuery (COMMA relevanceArg)* RR_BRACKET
;

altMultiFieldRelevanceFunction
: field=relevanceField EQUAL_SYMBOL altSyntaxFunctionName=altMultiFieldRelevanceFunctionName LR_BRACKET query=relevanceQuery (COMMA relevanceArg)* RR_BRACKET
;

convertedDataType
: typeName=DATE
| typeName=TIME
Expand Down Expand Up @@ -484,6 +497,18 @@ multiFieldRelevanceFunctionName
| QUERY_STRING
;

altSingleFieldRelevanceFunctionName
: MATCH_QUERY
| MATCHQUERY
| MATCH_PHRASE
| MATCHPHRASE
;

altMultiFieldRelevanceFunctionName
: MULTI_MATCH
| MULTIMATCH
;

functionArgs
: (functionArg (COMMA functionArg)*)?
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,14 @@ public UnresolvedExpression visitSingleFieldRelevanceFunction(
singleFieldRelevanceArguments(ctx));
}

@Override
public UnresolvedExpression visitAltSingleFieldRelevanceFunction(
OpenSearchSQLParser.AltSingleFieldRelevanceFunctionContext ctx) {
return new Function(
ctx.altSyntaxFunctionName.getText().toLowerCase(),
altSingleFieldRelevanceFunctionArguments(ctx));
}

@Override
public UnresolvedExpression visitMultiFieldRelevanceFunction(
MultiFieldRelevanceFunctionContext ctx) {
Expand All @@ -427,6 +435,14 @@ public UnresolvedExpression visitMultiFieldRelevanceFunction(
}
}

@Override
public UnresolvedExpression visitAltMultiFieldRelevanceFunction(
OpenSearchSQLParser.AltMultiFieldRelevanceFunctionContext ctx) {
return new Function(
ctx.altSyntaxFunctionName.getText().toLowerCase(),
altMultiFieldRelevanceFunctionArguments(ctx));
}

private Function buildFunction(String functionName,
List<OpenSearchSQLParser.FunctionArgContext> arg) {
return new Function(
Expand Down Expand Up @@ -483,6 +499,18 @@ private List<UnresolvedExpression> singleFieldRelevanceArguments(
}


private List<UnresolvedExpression> altSingleFieldRelevanceFunctionArguments(
OpenSearchSQLParser.AltSingleFieldRelevanceFunctionContext ctx) {
// all the arguments are defaulted to string values
// to skip environment resolving and function signature resolving
ImmutableList.Builder<UnresolvedExpression> builder = ImmutableList.builder();
builder.add(new UnresolvedArgument("field",
new Literal(StringUtils.unquoteText(ctx.field.getText()), DataType.STRING)));
builder.add(new UnresolvedArgument("query",
new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING)));
fillRelevanceArgs(ctx.relevanceArg(), builder);
return builder.build();
}

private List<UnresolvedExpression> multiFieldRelevanceArguments(
OpenSearchSQLParser.MultiFieldRelevanceFunctionContext ctx) {
Expand Down Expand Up @@ -538,4 +566,19 @@ private List<UnresolvedExpression> alternateMultiMatchArguments(

return builder.build();
}

private List<UnresolvedExpression> altMultiFieldRelevanceFunctionArguments(
OpenSearchSQLParser.AltMultiFieldRelevanceFunctionContext ctx) {
// all the arguments are defaulted to string values
// to skip environment resolving and function signature resolving
var map = new HashMap<String, Float>();
map.put(ctx.field.getText(), 1F);
ImmutableList.Builder<UnresolvedExpression> builder = ImmutableList.builder();
var fields = new RelevanceFieldList(map);
builder.add(new UnresolvedArgument("fields", fields));
builder.add(new UnresolvedArgument("query",
new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING)));
fillRelevanceArgs(ctx.relevanceArg(), builder);
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,30 @@ private static Stream<String> matchPhraseComplexQueries() {
);
}

@Test
public void canParseMatchQueryAlternateSyntax() {
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchquery('query')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchquery(\"query\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_query('query')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_query(\"query\")"));
}

@Test
public void canParseMatchPhraseAlternateSyntax() {
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_phrase('query')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = match_phrase(\"query\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchphrase('query')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = matchphrase(\"query\")"));
}

@Test
public void canParseMultiMatchAlternateSyntax() {
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multi_match('query')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multi_match(\"query\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multimatch('query')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE Field = multimatch(\"query\")"));
}

private static Stream<String> matchPhraseQueryComplexQueries() {
return Stream.of(
"SELECT * FROM t WHERE matchphrasequery(c, 3)",
Expand Down
Loading