Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ public class OpenSearchFunctions {
*/
public void register(BuiltinFunctionRepository repository) {
repository.register(match_bool_prefix());
repository.register(match());
repository.register(match(BuiltinFunctionName.MATCH));
repository.register(match(BuiltinFunctionName.MATCHQUERY));
repository.register(match(BuiltinFunctionName.MATCH_QUERY));
repository.register(multi_match());
repository.register(simple_query_string());
repository.register(query());
Expand All @@ -44,8 +46,8 @@ private static FunctionResolver match_bool_prefix() {
return new RelevanceFunctionResolver(name, STRING);
}

private static FunctionResolver match() {
FunctionName funcName = BuiltinFunctionName.MATCH.getName();
private static FunctionResolver match(BuiltinFunctionName match) {
FunctionName funcName = match.getName();
return new RelevanceFunctionResolver(funcName, STRING);
}

Expand Down
89 changes: 89 additions & 0 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2730,6 +2730,95 @@ Another example to show how to set custom values for the optional parameters::
+------------+


MATCHQUERY
-----

Description
>>>>>>>>>>>

``matchquery(field_expression, query_expression[, option=<option_value>]*)``

The matchquery function maps to the match query used in search engine, to return the documents that match a provided text, number, date or boolean value with a given field. This is alternate syntax for the `match`_ function. Available parameters include:

- analyzer
- auto_generate_synonyms_phrase
- fuzziness
- max_expansions
- prefix_length
- fuzzy_transpositions
- fuzzy_rewrite
- lenient
- operator
- minimum_should_match
- zero_terms_query
- boost

Example with only ``field`` and ``query`` expressions, and all other parameters are set default values::

os> SELECT lastname, address FROM accounts WHERE match(address, 'Street');
fetched rows / total rows = 2/2
+------------+--------------------+
| lastname | address |
|------------+--------------------|
| Bond | 671 Bristol Street |
| Bates | 789 Madison Street |
+------------+--------------------+

Another example to show how to set custom values for the optional parameters::

os> SELECT lastname FROM accounts WHERE match(firstname, 'Hattie', operator='AND', boost=2.0);
fetched rows / total rows = 1/1
+------------+
| lastname |
|------------|
| Bond |
+------------+

MATCH_QUERY
-----

Description
>>>>>>>>>>>

``match(field_expression, query_expression[, option=<option_value>]*)``

The match function maps to the match query used in search engine, to return the documents that match a provided text, number, date or boolean value with a given field. This is alternate syntax for the `match`_ function. Available parameters include:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here as above for matchquery

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just add a sentence like:

For backward compatibility, matchphrase is also supported and mapped to match_phrase query as well.

but using matchquery and match_query

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cbccd33


- analyzer
- auto_generate_synonyms_phrase
- fuzziness
- max_expansions
- prefix_length
- fuzzy_transpositions
- fuzzy_rewrite
- lenient
- operator
- minimum_should_match
- zero_terms_query
- boost

Example with only ``field`` and ``query`` expressions, and all other parameters are set default values::

os> SELECT lastname, address FROM accounts WHERE match(address, 'Street');
fetched rows / total rows = 2/2
+------------+--------------------+
| lastname | address |
|------------+--------------------|
| Bond | 671 Bristol Street |
| Bates | 789 Madison Street |
+------------+--------------------+

Another example to show how to set custom values for the optional parameters::

os> SELECT lastname FROM accounts WHERE match(firstname, 'Hattie', operator='AND', boost=2.0);
fetched rows / total rows = 1/1
+------------+
| lastname |
|------------|
| Bond |
+------------+


MATCH_PHRASE
------------

Expand Down
28 changes: 28 additions & 0 deletions integ-test/src/test/java/org/opensearch/sql/sql/MatchIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,32 @@ public void match_in_having() throws IOException {
verifySchema(result, schema("lastname", "text"));
verifyDataRows(result, rows("Bates"));
}

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

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

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

@Test
public void match_query_in_having() throws IOException {
JSONObject result = executeJdbcRequest("SELECT lastname FROM " + TEST_INDEX_ACCOUNT + " HAVING match_query(firstname, 'Nanette')");
verifySchema(result, schema("lastname", "text"));
verifyDataRows(result, rows("Bates"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
public class MatchQueryTest {
private final DSL dsl = new ExpressionConfig().dsl(new ExpressionConfig().functionRepository());
private final MatchQuery matchQuery = new MatchQuery();
private final FunctionName match = FunctionName.of("match");
private final FunctionName matchName = FunctionName.of("match");
private final FunctionName matchQueryName = FunctionName.of("matchquery");
private final FunctionName matchQueryWithUnderscoreName = FunctionName.of("match_query");
private final FunctionName[] functionNames =
{matchName,matchQueryName, matchQueryWithUnderscoreName};

static Stream<List<Expression>> generateValidData() {
final DSL dsl = new ExpressionConfig().dsl(new ExpressionConfig().functionRepository());
Expand Down Expand Up @@ -112,21 +116,27 @@ static Stream<List<Expression>> generateValidData() {
@ParameterizedTest
@MethodSource("generateValidData")
public void test_valid_parameters(List<Expression> validArgs) {
Assertions.assertNotNull(matchQuery.build(new MatchExpression(validArgs)));
for (FunctionName funcName : functionNames) {
Assertions.assertNotNull(matchQuery.build(new MatchExpression(validArgs, funcName)));
}
}

@Test
public void test_SyntaxCheckException_when_no_arguments() {
List<Expression> arguments = List.of();
assertThrows(SyntaxCheckException.class,
() -> matchQuery.build(new MatchExpression(arguments)));
for (FunctionName funcName : functionNames) {
assertThrows(SyntaxCheckException.class,
() -> matchQuery.build(new MatchExpression(arguments, funcName)));
}
}

@Test
public void test_SyntaxCheckException_when_one_argument() {
List<Expression> arguments = List.of(namedArgument("field", "field_value"));
assertThrows(SyntaxCheckException.class,
() -> matchQuery.build(new MatchExpression(arguments)));
for (FunctionName funcName : functionNames) {
assertThrows(SyntaxCheckException.class,
() -> matchQuery.build(new MatchExpression(arguments, funcName)));
}
}

@Test
Expand All @@ -135,17 +145,19 @@ public void test_SemanticCheckException_when_invalid_parameter() {
namedArgument("field", "field_value"),
namedArgument("query", "query_value"),
namedArgument("unsupported", "unsupported_value"));
Assertions.assertThrows(SemanticCheckException.class,
() -> matchQuery.build(new MatchExpression(arguments)));
for (FunctionName funcName : functionNames) {
Assertions.assertThrows(SemanticCheckException.class,
() -> matchQuery.build(new MatchExpression(arguments, funcName)));
}
}

private NamedArgumentExpression namedArgument(String name, String value) {
return dsl.namedArgument(name, DSL.literal(value));
}

private class MatchExpression extends FunctionExpression {
public MatchExpression(List<Expression> arguments) {
super(MatchQueryTest.this.match, arguments);
public MatchExpression(List<Expression> arguments, FunctionName funcName) {
super(funcName, arguments);
}

@Override
Expand Down
5 changes: 3 additions & 2 deletions sql/src/main/antlr/OpenSearchSQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,8 @@ systemFunctionName
;

singleFieldRelevanceFunctionName
: MATCH | MATCH_PHRASE | MATCHPHRASE
: MATCH | MATCHQUERY | MATCH_QUERY
| MATCH_PHRASE | MATCHPHRASE
| MATCH_BOOL_PREFIX | MATCH_PHRASE_PREFIX
;

Expand All @@ -436,7 +437,7 @@ multiFieldRelevanceFunctionName
;

legacyRelevanceFunctionName
: QUERY | MATCH_QUERY | MATCHQUERY
: QUERY
;

functionArgs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,28 @@ public void can_parse_match_relevance_function() {
assertNotNull(parser.parse("SELECT * FROM test WHERE match(`column`, \"this is a test\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match(`column`, 'this is a test')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match(column, 100500)"));
}

@Test
public void can_parse_matchquery_relevance_function() {
assertNotNull(parser.parse("SELECT * FROM test WHERE matchquery(column, \"this is a test\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE matchquery(column, 'this is a test')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE matchquery(`column`, \"this is a test\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE matchquery(`column`, 'this is a test')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE matchquery(column, 100500)"));
}

@Test
public void can_parse_match_query_relevance_function() {
assertNotNull(parser.parse("SELECT * FROM test WHERE match_query(column, \"this is a test\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match_query(column, 'this is a test')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match_query(`column`, \"this is a test\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match_query(`column`, 'this is a test')"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match_query(column, 100500)"));
}

@Test
public void can_parse_match_phrase_relevance_function() {
assertNotNull(
parser.parse("SELECT * FROM test WHERE match_phrase(column, \"this is a test\")"));
assertNotNull(parser.parse("SELECT * FROM test WHERE match_phrase(column, 'this is a test')"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,38 @@ public void relevanceMatch() {
buildExprAst("match('message', 'search query', analyzer='keyword', operator='AND')"));
}

@Test
public void relevanceMatchQuery() {
assertEquals(AstDSL.function("matchquery",
unresolvedArg("field", stringLiteral("message")),
unresolvedArg("query", stringLiteral("search query"))),
buildExprAst("matchquery('message', 'search query')")
);

assertEquals(AstDSL.function("matchquery",
unresolvedArg("field", stringLiteral("message")),
unresolvedArg("query", stringLiteral("search query")),
unresolvedArg("analyzer", stringLiteral("keyword")),
unresolvedArg("operator", stringLiteral("AND"))),
buildExprAst("matchquery('message', 'search query', analyzer='keyword', operator='AND')"));
}

@Test
public void relevanceMatch_Query() {
assertEquals(AstDSL.function("match_query",
unresolvedArg("field", stringLiteral("message")),
unresolvedArg("query", stringLiteral("search query"))),
buildExprAst("match_query('message', 'search query')")
);

assertEquals(AstDSL.function("match_query",
unresolvedArg("field", stringLiteral("message")),
unresolvedArg("query", stringLiteral("search query")),
unresolvedArg("analyzer", stringLiteral("keyword")),
unresolvedArg("operator", stringLiteral("AND"))),
buildExprAst("match_query('message', 'search query', analyzer='keyword', operator='AND')"));
}

@Test
public void relevanceMulti_match() {
assertEquals(AstDSL.function("multi_match",
Expand Down