Skip to content

[Calcite Engine] Support In expression #3429

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

Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -32,6 +32,7 @@
import org.opensearch.sql.ast.expression.Compare;
import org.opensearch.sql.ast.expression.EqualTo;
import org.opensearch.sql.ast.expression.Function;
import org.opensearch.sql.ast.expression.In;
import org.opensearch.sql.ast.expression.Let;
import org.opensearch.sql.ast.expression.Literal;
import org.opensearch.sql.ast.expression.Not;
Expand Down Expand Up @@ -139,6 +140,16 @@ public RexNode visitNot(Not node, CalcitePlanContext context) {
return context.relBuilder.not(expr);
}

@Override
public RexNode visitIn(In node, CalcitePlanContext context) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Calcite will optimize In expression to equal comparison if there is only 1 element in value list. We don't need to do such optimization ourself here like v2.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't need to do such optimization ourself here like v2.

Do u mean we push down IN to OpenSearch as terms query, so Calcite optimized is not needed?

final RexNode field = analyze(node.getField(), context);
return context.rexBuilder.makeIn(
field,
node.getValueList().stream()
.map(value -> analyze(value, context))
.collect(Collectors.toList()));
}

@Override
public RexNode visitCompare(Compare node, CalcitePlanContext context) {
final RelDataType booleanType =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@
import org.junit.Ignore;
import org.opensearch.sql.ppl.WhereCommandIT;

@Ignore("Not all boolean functions are supported in Calcite now")
public class CalciteWhereCommandIT extends WhereCommandIT {
@Override
public void init() throws IOException {
enableCalcite();
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we disableCalcite also? otherwise it may impact other tests?

Copy link
Collaborator Author

@qianheng-aws qianheng-aws Mar 18, 2025

Choose a reason for hiding this comment

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

We have exclude 'org/opensearch/sql/calcite/remote/**' in build.gradle, it won't really run in CI. The parent class WhereCommandIT is the suite for test cases without calcite enabled.

disallowCalciteFallback();
super.init();
}

@Ignore("https://github.com/opensearch-project/sql/issues/3428")
Copy link
Collaborator

Choose a reason for hiding this comment

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

#3428 is LIKE function, why releated to testIsNotNull?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this test case contains a like function as well.

"source=%s | where isnotnull(age) and like(firstname, 'Ambe_') | fields firstname"

Copy link
Member

Choose a reason for hiding this comment

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

WhereCommandIT is an existed ppl IT which is extended by CalciteWhereCommandIT

@Override
public void testIsNotNullFunction() throws IOException {}
;
Copy link
Member

Choose a reason for hiding this comment

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

remove this ;


@Ignore("https://github.com/opensearch-project/sql/issues/3333")
@Override
public void testWhereWithMetadataFields() throws IOException {}
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,20 @@ public void testWhereWithMetadataFields() throws IOException {
String.format("source=%s | where _id='1' | fields firstname", TEST_INDEX_ACCOUNT));
verifyDataRows(result, rows("Amber"));
}

@Test
public void testWhereWithIn() throws IOException {
JSONObject result =
executeQuery(
String.format(
"source=%s | where firstname in ('Amber') | fields firstname", TEST_INDEX_ACCOUNT));
Copy link
Member

Choose a reason for hiding this comment

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

need a test for

where age in (36, 36.0, '36')

verifyDataRows(result, rows("Amber"));

result =
executeQuery(
String.format(
"source=%s | where firstname in ('Amber', 'Dale') | fields firstname",
TEST_INDEX_ACCOUNT));
verifyDataRows(result, rows("Amber"), rows("Dale"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.opensearch.sql.ast.expression.Compare;
import org.opensearch.sql.ast.expression.Field;
import org.opensearch.sql.ast.expression.Function;
import org.opensearch.sql.ast.expression.In;
import org.opensearch.sql.ast.expression.Interval;
import org.opensearch.sql.ast.expression.Let;
import org.opensearch.sql.ast.expression.Literal;
Expand Down Expand Up @@ -386,6 +387,12 @@ public String visitCompare(Compare node, String context) {
return StringUtils.format("%s %s %s", left, node.getOperator(), right);
}

@Override
public String visitIn(In node, String context) {
String field = analyze(node.getField(), context);
return StringUtils.format("%s in (%s)", field, MASK_LITERAL);
}

@Override
public String visitField(Field node, String context) {
return node.getField().toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ public void testFilterQueryWithOr2() {
verifyPPLToSparkSQL(root, expectedSparkSql);
}

@Test
public void testFilterQueryWithIn() {
String ppl = "source=scott.products_temporal | where ID in ('1000', '2000')";
RelNode root = getRelNode(ppl);
String expectedLogical =
"LogicalFilter(condition=[SEARCH($0, Sarg['1000', '2000']:CHAR(4))])\n"
+ " LogicalTableScan(table=[[scott, products_temporal]])\n";
verifyLogical(root, expectedLogical);

String expectedSparkSql =
"SELECT *\nFROM `scott`.`products_temporal`\nWHERE `ID` IN ('1000', '2000')";
verifyPPLToSparkSQL(root, expectedSparkSql);
}

@Test
public void testQueryWithFields() {
String ppl = "source=products_temporal | fields SUPPLIER, ID";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ public void testNotExpression() {
assertEquals("source=t | where not a = ***", anonymize("source=t | where not a=1 "));
}

@Test
public void testInExpression() {
assertEquals("source=t | where a in (***)", anonymize("source=t | where a in (1, 2, 3) "));
Copy link
Member

Choose a reason for hiding this comment

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

add a test for

where a not in (1, 2, 3)

Copy link
Collaborator Author

@qianheng-aws qianheng-aws Mar 17, 2025

Choose a reason for hiding this comment

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

"not in" is not supported in our g4, which mean v2 engine don't support it either. Need to add that implementation for v2 engine as well.

}

@Test
public void testQualifiedName() {
assertEquals("source=t | fields + field0", anonymize("source=t | fields field0"));
Expand Down
Loading