Skip to content

Commit

Permalink
Add Alternate Syntax For Match_Query And Other Functions (#1166)
Browse files Browse the repository at this point in the history
Added Tests And Implementation For Match_Query, Match_Phrase, and Multi_Match Functions

Signed-off-by: GabeFernandez310 <[email protected]>

Signed-off-by: GabeFernandez310 <[email protected]>
(cherry picked from commit b919ba0)
  • Loading branch information
GabeFernandez310 authored and github-actions[bot] committed Jan 6, 2023
1 parent de79815 commit c7b90ec
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 4 deletions.
55 changes: 55 additions & 0 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3001,6 +3001,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 @@ -3030,6 +3040,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 @@ -3069,6 +3089,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 @@ -3212,6 +3249,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 @@ -103,7 +103,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 @@ -116,4 +116,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));
}
}
31 changes: 31 additions & 0 deletions integ-test/src/test/java/org/opensearch/sql/sql/MultiMatchIT.java
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 @@ -485,6 +498,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 @@ -433,6 +433,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 @@ -454,6 +462,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<FunctionArgContext> arg) {
return new Function(
Expand Down Expand Up @@ -510,6 +526,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(
MultiFieldRelevanceFunctionContext ctx) {
Expand Down Expand Up @@ -565,4 +593,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 @@ -509,6 +509,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

0 comments on commit c7b90ec

Please sign in to comment.