Skip to content

Commit c5ae56f

Browse files
authored
Register missing SQL V2 relevance functions in Calcite function table (#5440)
* feat(calcite): Register missing SQL V2 relevance functions in Calcite function table Add SQL V2 relevance functions and aliases to PPLFuncImpTable so CalciteRelNodeVisitor can resolve them from SQL V2 AstBuilder. Aliases normalize to canonical operators (e.g. matchquery -> match). New functions: query, wildcard_query Aliases: wildcardquery, match_query, matchquery, matchphrase, matchphrasequery, multimatch, multimatchquery Not included: score/scorequery/score_query (needs dedicated visitor). Signed-off-by: Chen Dai <daichen@amazon.com> --------- Signed-off-by: Chen Dai <daichen@amazon.com>
1 parent 1efb6c3 commit c5ae56f

3 files changed

Lines changed: 112 additions & 0 deletions

File tree

api/src/test/java/org/opensearch/sql/api/UnifiedRelevanceSearchSqlV2Test.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,95 @@ public void matchCombinedWithBooleanFilter() {
132132
LogicalTableScan(table=[[catalog, employees]])
133133
""");
134134
}
135+
136+
@Test
137+
public void matchQuery() {
138+
givenQuery("SELECT * FROM catalog.employees WHERE match_query(name, 'John')")
139+
.assertPlan(
140+
"""
141+
LogicalFilter(condition=[match(MAP('field', $1), MAP('query', 'John':VARCHAR))])
142+
LogicalTableScan(table=[[catalog, employees]])
143+
""");
144+
}
145+
146+
@Test
147+
public void matchquery() {
148+
givenQuery("SELECT * FROM catalog.employees WHERE matchquery(name, 'John')")
149+
.assertPlan(
150+
"""
151+
LogicalFilter(condition=[match(MAP('field', $1), MAP('query', 'John':VARCHAR))])
152+
LogicalTableScan(table=[[catalog, employees]])
153+
""");
154+
}
155+
156+
@Test
157+
public void matchphrase() {
158+
givenQuery("SELECT * FROM catalog.employees WHERE matchphrase(name, 'John Doe')")
159+
.assertPlan(
160+
"""
161+
LogicalFilter(condition=[match_phrase(MAP('field', $1), MAP('query', 'John Doe':VARCHAR))])
162+
LogicalTableScan(table=[[catalog, employees]])
163+
""");
164+
}
165+
166+
@Test
167+
public void matchphrasequery() {
168+
givenQuery("SELECT * FROM catalog.employees WHERE matchphrasequery(name, 'John Doe')")
169+
.assertPlan(
170+
"""
171+
LogicalFilter(condition=[match_phrase(MAP('field', $1), MAP('query', 'John Doe':VARCHAR))])
172+
LogicalTableScan(table=[[catalog, employees]])
173+
""");
174+
}
175+
176+
@Test
177+
public void multimatch() {
178+
givenQuery("SELECT * FROM catalog.employees WHERE multimatch(['name', 'department'], 'John')")
179+
.assertPlan(
180+
"""
181+
LogicalFilter(condition=[multi_match(MAP('fields', MAP('name':VARCHAR, 1.0E0:DOUBLE, 'department':VARCHAR, 1.0E0:DOUBLE)), MAP('query', 'John':VARCHAR))])
182+
LogicalTableScan(table=[[catalog, employees]])
183+
""");
184+
}
185+
186+
@Test
187+
public void multimatchquery() {
188+
givenQuery(
189+
"SELECT * FROM catalog.employees WHERE multimatchquery(['name', 'department'], 'John')")
190+
.assertPlan(
191+
"""
192+
LogicalFilter(condition=[multi_match(MAP('fields', MAP('name':VARCHAR, 1.0E0:DOUBLE, 'department':VARCHAR, 1.0E0:DOUBLE)), MAP('query', 'John':VARCHAR))])
193+
LogicalTableScan(table=[[catalog, employees]])
194+
""");
195+
}
196+
197+
@Test
198+
public void query() {
199+
givenQuery("SELECT * FROM catalog.employees WHERE query('name:John')")
200+
.assertPlan(
201+
"""
202+
LogicalFilter(condition=[query(MAP('query', 'name:John':VARCHAR))])
203+
LogicalTableScan(table=[[catalog, employees]])
204+
""");
205+
}
206+
207+
@Test
208+
public void wildcardQuery() {
209+
givenQuery("SELECT * FROM catalog.employees WHERE wildcard_query(name, 'John*')")
210+
.assertPlan(
211+
"""
212+
LogicalFilter(condition=[wildcard_query(MAP('field', $1), MAP('query', 'John*':VARCHAR))])
213+
LogicalTableScan(table=[[catalog, employees]])
214+
""");
215+
}
216+
217+
@Test
218+
public void wildcardquery() {
219+
givenQuery("SELECT * FROM catalog.employees WHERE wildcardquery(name, 'John*')")
220+
.assertPlan(
221+
"""
222+
LogicalFilter(condition=[wildcard_query(MAP('field', $1), MAP('query', 'John*':VARCHAR))])
223+
LogicalTableScan(table=[[catalog, employees]])
224+
""");
225+
}
135226
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ public class PPLBuiltinOperators extends ReflectiveSqlOperatorTable {
424424
RELEVANCE_QUERY_FUNCTION_INSTANCE.toUDF("query_string", false);
425425
public static final SqlOperator MULTI_MATCH =
426426
RELEVANCE_QUERY_FUNCTION_INSTANCE.toUDF("multi_match", false);
427+
public static final SqlOperator QUERY = RELEVANCE_QUERY_FUNCTION_INSTANCE.toUDF("query");
428+
public static final SqlOperator WILDCARD_QUERY =
429+
RELEVANCE_QUERY_FUNCTION_INSTANCE.toUDF("wildcard_query");
427430
public static final SqlOperator NUMBER_TO_STRING =
428431
new NumberToStringFunction().toUDF("NUMBER_TO_STRING");
429432
public static final SqlOperator TONUMBER = new ToNumberFunction().toUDF("TONUMBER");

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,13 @@
133133
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MAP_CONCAT;
134134
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MAP_REMOVE;
135135
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCH;
136+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCHPHRASE;
137+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCHPHRASEQUERY;
138+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCHQUERY;
136139
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCH_BOOL_PREFIX;
137140
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCH_PHRASE;
138141
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCH_PHRASE_PREFIX;
142+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MATCH_QUERY;
139143
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MAX;
140144
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MD5;
141145
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MEDIAN;
@@ -154,6 +158,8 @@
154158
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MONTHNAME;
155159
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MONTH_OF_YEAR;
156160
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MSTIME;
161+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MULTIMATCH;
162+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MULTIMATCHQUERY;
157163
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MULTIPLY;
158164
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MULTIPLYFUNCTION;
159165
import static org.opensearch.sql.expression.function.BuiltinFunctionName.MULTI_MATCH;
@@ -178,6 +184,7 @@
178184
import static org.opensearch.sql.expression.function.BuiltinFunctionName.POW;
179185
import static org.opensearch.sql.expression.function.BuiltinFunctionName.POWER;
180186
import static org.opensearch.sql.expression.function.BuiltinFunctionName.QUARTER;
187+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.QUERY;
181188
import static org.opensearch.sql.expression.function.BuiltinFunctionName.QUERY_STRING;
182189
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RADIANS;
183190
import static org.opensearch.sql.expression.function.BuiltinFunctionName.RAND;
@@ -254,6 +261,8 @@
254261
import static org.opensearch.sql.expression.function.BuiltinFunctionName.WEEKOFYEAR;
255262
import static org.opensearch.sql.expression.function.BuiltinFunctionName.WEEK_OF_YEAR;
256263
import static org.opensearch.sql.expression.function.BuiltinFunctionName.WIDTH_BUCKET;
264+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.WILDCARDQUERY;
265+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.WILDCARD_QUERY;
257266
import static org.opensearch.sql.expression.function.BuiltinFunctionName.XOR;
258267
import static org.opensearch.sql.expression.function.BuiltinFunctionName.YEAR;
259268
import static org.opensearch.sql.expression.function.BuiltinFunctionName.YEARWEEK;
@@ -908,6 +917,15 @@ void populate() {
908917
registerOperator(SIMPLE_QUERY_STRING, PPLBuiltinOperators.SIMPLE_QUERY_STRING);
909918
registerOperator(QUERY_STRING, PPLBuiltinOperators.QUERY_STRING);
910919
registerOperator(MULTI_MATCH, PPLBuiltinOperators.MULTI_MATCH);
920+
registerOperator(QUERY, PPLBuiltinOperators.QUERY);
921+
registerOperator(WILDCARD_QUERY, PPLBuiltinOperators.WILDCARD_QUERY);
922+
registerOperator(WILDCARDQUERY, PPLBuiltinOperators.WILDCARD_QUERY);
923+
registerOperator(MATCH_QUERY, PPLBuiltinOperators.MATCH);
924+
registerOperator(MATCHQUERY, PPLBuiltinOperators.MATCH);
925+
registerOperator(MATCHPHRASE, PPLBuiltinOperators.MATCH_PHRASE);
926+
registerOperator(MATCHPHRASEQUERY, PPLBuiltinOperators.MATCH_PHRASE);
927+
registerOperator(MULTIMATCH, PPLBuiltinOperators.MULTI_MATCH);
928+
registerOperator(MULTIMATCHQUERY, PPLBuiltinOperators.MULTI_MATCH);
911929
registerOperator(REX_EXTRACT, PPLBuiltinOperators.REX_EXTRACT);
912930
registerOperator(REX_EXTRACT_MULTI, PPLBuiltinOperators.REX_EXTRACT_MULTI);
913931
registerOperator(REX_OFFSET, PPLBuiltinOperators.REX_OFFSET);

0 commit comments

Comments
 (0)