Skip to content

Commit 0fd7f2f

Browse files
authored
Support In clause in SQL and PPL (opensearch-project#420)
Signed-off-by: penghuo <[email protected]>
1 parent 1a2bfe2 commit 0fd7f2f

File tree

14 files changed

+284
-22
lines changed

14 files changed

+284
-22
lines changed

core/src/main/java/org/opensearch/sql/analysis/ExpressionAnalyzer.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.opensearch.sql.ast.expression.EqualTo;
2727
import org.opensearch.sql.ast.expression.Field;
2828
import org.opensearch.sql.ast.expression.Function;
29+
import org.opensearch.sql.ast.expression.In;
2930
import org.opensearch.sql.ast.expression.Interval;
3031
import org.opensearch.sql.ast.expression.Literal;
3132
import org.opensearch.sql.ast.expression.Not;
@@ -177,6 +178,24 @@ public Expression visitWindowFunction(WindowFunction node, AnalysisContext conte
177178
return expr;
178179
}
179180

181+
@Override
182+
public Expression visitIn(In node, AnalysisContext context) {
183+
return visitIn(node.getField(), node.getValueList(), context);
184+
}
185+
186+
private Expression visitIn(
187+
UnresolvedExpression field, List<UnresolvedExpression> valueList, AnalysisContext context) {
188+
if (valueList.size() == 1) {
189+
return visitCompare(new Compare("=", field, valueList.get(0)), context);
190+
} else if (valueList.size() > 1) {
191+
return dsl.or(
192+
visitCompare(new Compare("=", field, valueList.get(0)), context),
193+
visitIn(field, valueList.subList(1, valueList.size()), context));
194+
} else {
195+
throw new SemanticCheckException("Values in In clause should not be empty");
196+
}
197+
}
198+
180199
@Override
181200
public Expression visitCompare(Compare node, AnalysisContext context) {
182201
FunctionName functionName = FunctionName.of(node.getOperator());

core/src/main/java/org/opensearch/sql/ast/dsl/AstDSL.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ public static UnresolvedExpression in(
279279
return new In(field, Arrays.asList(valueList));
280280
}
281281

282+
public static UnresolvedExpression in(
283+
UnresolvedExpression field, List<UnresolvedExpression> valueList) {
284+
return new In(field, valueList);
285+
}
286+
282287
public static UnresolvedExpression compare(
283288
String operator, UnresolvedExpression left, UnresolvedExpression right) {
284289
return new Compare(operator, left, right);

core/src/test/java/org/opensearch/sql/analysis/ExpressionAnalyzerTest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,23 @@
1818
import static org.opensearch.sql.data.model.ExprValueUtils.integerValue;
1919
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
2020
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
21-
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
2221
import static org.opensearch.sql.data.type.ExprCoreType.STRUCT;
2322

23+
import java.util.Collections;
2424
import org.junit.jupiter.api.Test;
2525
import org.junit.jupiter.api.extension.ExtendWith;
2626
import org.opensearch.sql.analysis.symbol.Namespace;
2727
import org.opensearch.sql.analysis.symbol.Symbol;
2828
import org.opensearch.sql.ast.dsl.AstDSL;
2929
import org.opensearch.sql.ast.expression.AllFields;
3030
import org.opensearch.sql.ast.expression.DataType;
31-
import org.opensearch.sql.ast.expression.Literal;
3231
import org.opensearch.sql.ast.expression.SpanUnit;
3332
import org.opensearch.sql.ast.expression.UnresolvedExpression;
3433
import org.opensearch.sql.common.antlr.SyntaxCheckException;
3534
import org.opensearch.sql.data.model.ExprValueUtils;
3635
import org.opensearch.sql.exception.SemanticCheckException;
3736
import org.opensearch.sql.expression.DSL;
3837
import org.opensearch.sql.expression.Expression;
39-
import org.opensearch.sql.expression.NamedExpression;
4038
import org.opensearch.sql.expression.config.ExpressionConfig;
4139
import org.opensearch.sql.expression.window.aggregation.AggregateWindowFunction;
4240
import org.springframework.context.annotation.Configuration;
@@ -319,6 +317,21 @@ void visit_span() {
319317
);
320318
}
321319

320+
@Test
321+
void visit_in() {
322+
assertAnalyzeEqual(
323+
dsl.or(
324+
dsl.equal(DSL.ref("integer_value", INTEGER), DSL.literal(1)),
325+
dsl.or(
326+
dsl.equal(DSL.ref("integer_value", INTEGER), DSL.literal(2)),
327+
dsl.equal(DSL.ref("integer_value", INTEGER), DSL.literal(3)))),
328+
AstDSL.in(field("integer_value"), intLiteral(1), intLiteral(2), intLiteral(3)));
329+
330+
assertThrows(
331+
SemanticCheckException.class,
332+
() -> analyze(AstDSL.in(field("integer_value"), Collections.emptyList())));
333+
}
334+
322335
protected Expression analyze(UnresolvedExpression unresolvedExpression) {
323336
return expressionAnalyzer.analyze(unresolvedExpression, analysisContext);
324337
}

docs/category.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"user/ppl/functions/datetime.rst",
2222
"user/ppl/functions/string.rst",
2323
"user/ppl/functions/condition.rst",
24-
"user/ppl/functions/relevance.rst"
24+
"user/ppl/functions/relevance.rst",
25+
"user/ppl/functions/expressions.rst"
2526
],
2627
"sql_cli": [
2728
"user/dql/expressions.rst",
@@ -36,4 +37,4 @@
3637
"user/dql/aggregations.rst",
3738
"user/dql/complex.rst"
3839
]
39-
}
40+
}

docs/user/dql/expressions.rst

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ Operators
128128
+----------------+----------------------------------------+
129129
| REGEXP | String matches regular expression test |
130130
+----------------+----------------------------------------+
131-
131+
| IN | IN value list test |
132+
+----------------+----------------------------------------+
133+
| NOT IN | NOT IN value list test |
134+
+----------------+----------------------------------------+
132135

133136
Basic Comparison Operator
134137
-------------------------
@@ -183,6 +186,19 @@ expr REGEXP pattern. The expr is string value, pattern is supports regular expre
183186
| 1 | 0 |
184187
+------------------------+------------------+
185188

189+
IN value list test
190+
------------------
191+
192+
Here is an example for IN value test::
193+
194+
os> SELECT 1 in (1, 2), 3 not in (1, 2);
195+
fetched rows / total rows = 1/1
196+
+---------------+-------------------+
197+
| 1 in (1, 2) | 3 not in (1, 2) |
198+
|---------------+-------------------|
199+
| True | True |
200+
+---------------+-------------------+
201+
186202
Function Call
187203
=============
188204

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
===========
2+
Expressions
3+
===========
4+
5+
.. rubric:: Table of contents
6+
7+
.. contents::
8+
:local:
9+
:depth: 3
10+
11+
12+
Introduction
13+
============
14+
15+
Expressions, particularly value expressions, are those which return a scalar value. Expressions have different types and forms. For example, there are literal values as atom expression and arithmetic, predicate and function expression built on top of them. And also expressions can be used in different clauses, such as using arithmetic expression in ``Filter``, ``Stats`` command.
16+
17+
Arithmetic Operators
18+
====================
19+
20+
Description
21+
-----------
22+
23+
Operators
24+
`````````
25+
26+
Arithmetic expression is an expression formed by numeric literals and binary arithmetic operators as follows:
27+
28+
1. ``+``: Add.
29+
2. ``-``: Subtract.
30+
3. ``*``: Multiply.
31+
4. ``/``: Divide. For integers, the result is an integer with fractional part discarded.
32+
5. ``%``: Modulo. This can be used with integers only with remainder of the division as result.
33+
34+
Precedence
35+
``````````
36+
37+
Parentheses can be used to control the precedence of arithmetic operators. Otherwise, operators of higher precedence is performed first.
38+
39+
Type Conversion
40+
```````````````
41+
42+
Implicit type conversion is performed when looking up operator signature. For example, an integer ``+`` a real number matches signature ``+(double,double)`` which results in a real number. This rule also applies to function call discussed below.
43+
44+
Examples
45+
--------
46+
47+
Here is an example for different type of arithmetic expressions::
48+
49+
os> source=accounts | where age > (25 + 5) | fields age ;
50+
fetched rows / total rows = 3/3
51+
+-------+
52+
| age |
53+
|-------|
54+
| 32 |
55+
| 36 |
56+
| 33 |
57+
+-------+
58+
59+
Predicate Operators
60+
===================
61+
62+
Description
63+
-----------
64+
65+
Predicate operator is an expression that evaluated to be ture. The MISSING and NULL value comparison has following the rule. MISSING value only equal to MISSING value and less than all the other values. NULL value equals to NULL value, large than MISSING value, but less than all the other values.
66+
67+
Operators
68+
`````````
69+
70+
+----------------+----------------------------------------+
71+
| name | description |
72+
+----------------+----------------------------------------+
73+
| > | Greater than operator |
74+
+----------------+----------------------------------------+
75+
| >= | Greater than or equal operator |
76+
+----------------+----------------------------------------+
77+
| < | Less than operator |
78+
+----------------+----------------------------------------+
79+
| != | Not equal operator |
80+
+----------------+----------------------------------------+
81+
| <= | Less than or equal operator |
82+
+----------------+----------------------------------------+
83+
| = | Equal operator |
84+
+----------------+----------------------------------------+
85+
| LIKE | Simple Pattern matching |
86+
+----------------+----------------------------------------+
87+
| IN | NULL value test |
88+
+----------------+----------------------------------------+
89+
| AND | AND operator |
90+
+----------------+----------------------------------------+
91+
| OR | OR operator |
92+
+----------------+----------------------------------------+
93+
| XOR | XOR operator |
94+
+----------------+----------------------------------------+
95+
| NOT | NOT NULL value test |
96+
+----------------+----------------------------------------+
97+
98+
Examples
99+
--------
100+
101+
Basic Predicate Operator
102+
````````````````````````
103+
104+
Here is an example for comparison operators::
105+
106+
os> source=accounts | where age > 33 | fields age ;
107+
fetched rows / total rows = 1/1
108+
+-------+
109+
| age |
110+
|-------|
111+
| 36 |
112+
+-------+
113+
114+
115+
IN
116+
``
117+
118+
IN operator test field in value lists::
119+
120+
os> source=accounts | where age in (32, 33) | fields age ;
121+
fetched rows / total rows = 2/2
122+
+-------+
123+
| age |
124+
|-------|
125+
| 32 |
126+
| 33 |
127+
+-------+
128+
129+
130+
OR
131+
``
132+
133+
OR operator ::
134+
135+
os> source=accounts | where age = 32 OR age = 33 | fields age ;
136+
fetched rows / total rows = 2/2
137+
+-------+
138+
| age |
139+
|-------|
140+
| 32 |
141+
| 33 |
142+
+-------+
143+
144+
145+
NOT
146+
```
147+
148+
NOT operator ::
149+
150+
os> source=accounts | where not age in (32, 33) | fields age ;
151+
fetched rows / total rows = 2/2
152+
+-------+
153+
| age |
154+
|-------|
155+
| 36 |
156+
| 28 |
157+
+-------+
158+

docs/user/ppl/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ The query start with search command and then flowing a set of command delimited
6060

6161
* **Functions**
6262

63+
- `Expressions <functions/expressions.rst>`_
64+
6365
- `Math Functions <functions/math.rst>`_
6466

6567
- `Date and Time Functions <functions/datetime.rst>`_
@@ -82,4 +84,4 @@ The query start with search command and then flowing a set of command delimited
8284

8385
* **Limitations**
8486

85-
- `Limitations <limitations/limitations.rst>`_
87+
- `Limitations <limitations/limitations.rst>`_

integ-test/src/test/java/org/opensearch/sql/legacy/CsvFormatResponseIT.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,10 @@ public void aggAfterTwoTermsGroupBy() throws Exception {
384384
List<String> lines = csvResult.getLines();
385385
Assert.assertEquals(4, lines.size());
386386
assertThat(lines, containsInAnyOrder(
387-
equalTo("31.0"),
388-
equalTo("28.0"),
389-
equalTo("21.0"),
390-
equalTo("24.0")));
387+
equalTo("31"),
388+
equalTo("28"),
389+
equalTo("21"),
390+
equalTo("24")));
391391
}
392392

393393
@Test
@@ -398,15 +398,15 @@ public void multipleAggAfterTwoTermsGroupBy() throws Exception {
398398
CSVResult csvResult = executeCsvRequest(query, false);
399399
List<String> headers = csvResult.getHeaders();
400400
Assert.assertEquals(2, headers.size());
401-
assertThat(headers, contains(equalTo("COUNT(*)"), equalTo("SUM(balance)")));
401+
assertThat(headers, contains(equalTo("COUNT(*)"), equalTo("sum(balance)")));
402402

403403
List<String> lines = csvResult.getLines();
404404
Assert.assertEquals(4, lines.size());
405405
assertThat(lines, containsInAnyOrder(
406-
equalTo("31.0,647425.0"),
407-
equalTo("28.0,678337.0"),
408-
equalTo("21.0,505660.0"),
409-
equalTo("24.0,472771.0")));
406+
equalTo("31,647425"),
407+
equalTo("28,678337"),
408+
equalTo("21,505660"),
409+
equalTo("24,472771")));
410410
}
411411

412412
@Test

ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
import java.util.stream.Collectors;
4949
import org.antlr.v4.runtime.ParserRuleContext;
5050
import org.antlr.v4.runtime.RuleContext;
51-
import org.antlr.v4.runtime.Token;
5251
import org.opensearch.sql.ast.expression.AggregateFunction;
5352
import org.opensearch.sql.ast.expression.Alias;
5453
import org.opensearch.sql.ast.expression.AllFields;
@@ -72,7 +71,6 @@
7271
import org.opensearch.sql.ast.expression.UnresolvedExpression;
7372
import org.opensearch.sql.ast.expression.Xor;
7473
import org.opensearch.sql.common.utils.StringUtils;
75-
import org.opensearch.sql.ppl.antlr.parser.OpenSearchPPLParser;
7674
import org.opensearch.sql.ppl.antlr.parser.OpenSearchPPLParserBaseVisitor;
7775
import org.opensearch.sql.ppl.utils.ArgumentFactory;
7876

ppl/src/test/java/org/opensearch/sql/ppl/parser/AstExpressionBuilderTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import static org.opensearch.sql.ast.dsl.AstDSL.agg;
1111
import static org.opensearch.sql.ast.dsl.AstDSL.aggregate;
1212
import static org.opensearch.sql.ast.dsl.AstDSL.alias;
13-
import static org.opensearch.sql.ast.dsl.AstDSL.allFields;
1413
import static org.opensearch.sql.ast.dsl.AstDSL.and;
1514
import static org.opensearch.sql.ast.dsl.AstDSL.argument;
1615
import static org.opensearch.sql.ast.dsl.AstDSL.booleanLiteral;

0 commit comments

Comments
 (0)