Skip to content

Commit 63401da

Browse files
yuancuexpani
authored andcommitted
Support millisecond span (opensearch-project#4672)
* Support millisecond span Signed-off-by: Yuanchun Shen <[email protected]> * Update per funciton tests Signed-off-by: Yuanchun Shen <[email protected]> --------- Signed-off-by: Yuanchun Shen <[email protected]>
1 parent 642e6b0 commit 63401da

File tree

13 files changed

+180
-47
lines changed

13 files changed

+180
-47
lines changed

core/src/main/java/org/opensearch/sql/ast/expression/IntervalUnit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
@RequiredArgsConstructor
1515
public enum IntervalUnit {
1616
UNKNOWN,
17-
1817
MICROSECOND,
18+
MILLISECOND,
1919
SECOND,
2020
MINUTE,
2121
HOUR,

core/src/main/java/org/opensearch/sql/ast/expression/SpanUnit.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
public enum SpanUnit {
1616
UNKNOWN("unknown"),
1717
NONE(""),
18+
MICROSECOND("us"),
19+
US("us"),
1820
MILLISECOND("ms"),
1921
MS("ms"),
2022
SECONDS("s"),

core/src/main/java/org/opensearch/sql/ast/tree/Timechart.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import static org.opensearch.sql.ast.dsl.AstDSL.eval;
1111
import static org.opensearch.sql.ast.dsl.AstDSL.function;
1212
import static org.opensearch.sql.ast.dsl.AstDSL.stringLiteral;
13-
import static org.opensearch.sql.ast.expression.IntervalUnit.SECOND;
13+
import static org.opensearch.sql.ast.expression.IntervalUnit.MILLISECOND;
1414
import static org.opensearch.sql.ast.tree.Timechart.PerFunctionRateExprBuilder.sum;
1515
import static org.opensearch.sql.ast.tree.Timechart.PerFunctionRateExprBuilder.timestampadd;
1616
import static org.opensearch.sql.ast.tree.Timechart.PerFunctionRateExprBuilder.timestampdiff;
@@ -112,11 +112,13 @@ private UnresolvedPlan transformPerFunction() {
112112
Span span = (Span) this.binExpression;
113113
Field spanStartTime = AstDSL.field(IMPLICIT_FIELD_TIMESTAMP);
114114
Function spanEndTime = timestampadd(span.getUnit(), span.getValue(), spanStartTime);
115-
Function spanSeconds = timestampdiff(SECOND, spanStartTime, spanEndTime);
116-
115+
Function spanMillis = timestampdiff(MILLISECOND, spanStartTime, spanEndTime);
116+
final int SECOND_IN_MILLISECOND = 1000;
117117
return eval(
118118
timechart(AstDSL.alias(perFunc.aggName, sum(perFunc.aggArg))),
119-
let(perFunc.aggName).multiply(perFunc.seconds).dividedBy(spanSeconds));
119+
let(perFunc.aggName)
120+
.multiply(perFunc.seconds * SECOND_IN_MILLISECOND)
121+
.dividedBy(spanMillis));
120122
}
121123

122124
private Timechart timechart(UnresolvedExpression newAggregateFunction) {

core/src/main/java/org/opensearch/sql/calcite/ExtendedRexBuilder.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,38 +54,59 @@ public RelDataType commonType(RexNode... nodes) {
5454
public SqlIntervalQualifier createIntervalUntil(SpanUnit unit) {
5555
TimeUnit timeUnit;
5656
switch (unit) {
57+
case MICROSECOND:
58+
case US:
59+
timeUnit = TimeUnit.MICROSECOND;
60+
break;
5761
case MILLISECOND:
5862
case MS:
5963
timeUnit = TimeUnit.MILLISECOND;
6064
break;
65+
case SECONDS:
6166
case SECOND:
67+
case SECS:
68+
case SEC:
6269
case S:
6370
timeUnit = TimeUnit.SECOND;
6471
break;
72+
case MINUTES:
6573
case MINUTE:
74+
case MINS:
75+
case MIN:
6676
case m:
6777
timeUnit = TimeUnit.MINUTE;
6878
break;
79+
case HOURS:
6980
case HOUR:
81+
case HRS:
82+
case HR:
7083
case H:
7184
timeUnit = TimeUnit.HOUR;
7285
break;
86+
case DAYS:
7387
case DAY:
7488
case D:
7589
timeUnit = TimeUnit.DAY;
7690
break;
91+
case WEEKS:
7792
case WEEK:
7893
case W:
7994
timeUnit = TimeUnit.WEEK;
8095
break;
96+
case MONTHS:
8197
case MONTH:
98+
case MON:
8299
case M:
83100
timeUnit = TimeUnit.MONTH;
84101
break;
102+
case QUARTERS:
85103
case QUARTER:
104+
case QTRS:
105+
case QTR:
86106
case Q:
87107
timeUnit = TimeUnit.QUARTER;
88108
break;
109+
case YEARS:
89110
case YEAR:
90111
case Y:
91112
timeUnit = TimeUnit.YEAR;

core/src/main/java/org/opensearch/sql/calcite/utils/PlanUtils.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public interface PlanUtils {
6868

6969
static SpanUnit intervalUnitToSpanUnit(IntervalUnit unit) {
7070
return switch (unit) {
71-
case MICROSECOND -> SpanUnit.MILLISECOND;
71+
case MICROSECOND -> SpanUnit.MICROSECOND;
72+
case MILLISECOND -> SpanUnit.MILLISECOND;
7273
case SECOND -> SpanUnit.SECOND;
7374
case MINUTE -> SpanUnit.MINUTE;
7475
case HOUR -> SpanUnit.HOUR;
@@ -84,9 +85,12 @@ static SpanUnit intervalUnitToSpanUnit(IntervalUnit unit) {
8485

8586
static IntervalUnit spanUnitToIntervalUnit(SpanUnit unit) {
8687
switch (unit) {
88+
case MICROSECOND:
89+
case US:
90+
return IntervalUnit.MICROSECOND;
8791
case MILLISECOND:
8892
case MS:
89-
return IntervalUnit.MICROSECOND;
93+
return IntervalUnit.MILLISECOND;
9094
case SECOND:
9195
case SECONDS:
9296
case SEC:

core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunctions.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static java.time.temporal.ChronoUnit.DAYS;
99
import static java.time.temporal.ChronoUnit.HOURS;
1010
import static java.time.temporal.ChronoUnit.MICROS;
11+
import static java.time.temporal.ChronoUnit.MILLIS;
1112
import static java.time.temporal.ChronoUnit.MINUTES;
1213
import static java.time.temporal.ChronoUnit.MONTHS;
1314
import static java.time.temporal.ChronoUnit.SECONDS;
@@ -1896,6 +1897,9 @@ public static ExprValue exprTimestampAdd(
18961897
case "MICROSECOND":
18971898
temporalUnit = MICROS;
18981899
break;
1900+
case "MILLISECOND":
1901+
temporalUnit = MILLIS;
1902+
break;
18991903
case "SECOND":
19001904
temporalUnit = SECONDS;
19011905
break;
@@ -1935,10 +1939,13 @@ public static ExprValue exprTimestampAddForTimeType(
19351939

19361940
private ExprValue getTimeDifference(String part, LocalDateTime startTime, LocalDateTime endTime) {
19371941
long returnVal;
1938-
switch (part) {
1942+
switch (part.toUpperCase(Locale.ROOT)) {
19391943
case "MICROSECOND":
19401944
returnVal = MICROS.between(startTime, endTime);
19411945
break;
1946+
case "MILLISECOND":
1947+
returnVal = MILLIS.between(startTime, endTime);
1948+
break;
19421949
case "SECOND":
19431950
returnVal = SECONDS.between(startTime, endTime);
19441951
break;

core/src/test/java/org/opensearch/sql/ast/tree/TimechartTest.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ void should_transform_per_second_for_different_spans(
5454
let(
5555
"per_second(bytes)",
5656
divide(
57-
multiply("per_second(bytes)", 1.0),
57+
multiply("per_second(bytes)", 1000.0),
5858
timestampdiff(
59-
"SECOND",
59+
"MILLISECOND",
6060
"@timestamp",
6161
timestampadd(expectedIntervalUnit, spanValue, "@timestamp")))),
6262
timechart(span(spanValue, spanUnit), alias("per_second(bytes)", sum("bytes")))));
@@ -73,9 +73,9 @@ void should_transform_per_minute_for_different_spans(
7373
let(
7474
"per_minute(bytes)",
7575
divide(
76-
multiply("per_minute(bytes)", 60.0),
76+
multiply("per_minute(bytes)", 60000.0),
7777
timestampdiff(
78-
"SECOND",
78+
"MILLISECOND",
7979
"@timestamp",
8080
timestampadd(expectedIntervalUnit, spanValue, "@timestamp")))),
8181
timechart(span(spanValue, spanUnit), alias("per_minute(bytes)", sum("bytes")))));
@@ -92,9 +92,9 @@ void should_transform_per_hour_for_different_spans(
9292
let(
9393
"per_hour(bytes)",
9494
divide(
95-
multiply("per_hour(bytes)", 3600.0),
95+
multiply("per_hour(bytes)", 3600000.0),
9696
timestampdiff(
97-
"SECOND",
97+
"MILLISECOND",
9898
"@timestamp",
9999
timestampadd(expectedIntervalUnit, spanValue, "@timestamp")))),
100100
timechart(span(spanValue, spanUnit), alias("per_hour(bytes)", sum("bytes")))));
@@ -111,9 +111,9 @@ void should_transform_per_day_for_different_spans(
111111
let(
112112
"per_day(bytes)",
113113
divide(
114-
multiply("per_day(bytes)", 86400.0),
114+
multiply("per_day(bytes)", 8.64E7),
115115
timestampdiff(
116-
"SECOND",
116+
"MILLISECOND",
117117
"@timestamp",
118118
timestampadd(expectedIntervalUnit, spanValue, "@timestamp")))),
119119
timechart(span(spanValue, spanUnit), alias("per_day(bytes)", sum("bytes")))));
@@ -149,9 +149,9 @@ void should_preserve_all_fields_during_per_function_transformation() {
149149
let(
150150
"per_second(bytes)",
151151
divide(
152-
multiply("per_second(bytes)", 1.0),
152+
multiply("per_second(bytes)", 1000.0),
153153
timestampdiff(
154-
"SECOND", "@timestamp", timestampadd("MINUTE", 5, "@timestamp")))),
154+
"MILLISECOND", "@timestamp", timestampadd("MINUTE", 5, "@timestamp")))),
155155
expected));
156156
}
157157

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteExplainIT.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,8 @@ public void testExplainTimechartPerSecond() throws IOException {
444444
var result = explainQueryToString("source=events | timechart span=2m per_second(cpu_usage)");
445445
assertTrue(
446446
result.contains(
447-
"per_second(cpu_usage)=[DIVIDE(*($1, 1.0E0), "
448-
+ "TIMESTAMPDIFF('SECOND':VARCHAR, $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
447+
"per_second(cpu_usage)=[DIVIDE(*($1, 1000.0E0), TIMESTAMPDIFF('MILLISECOND':VARCHAR,"
448+
+ " $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
449449
assertTrue(result.contains("per_second(cpu_usage)=[SUM($0)]"));
450450
}
451451

@@ -454,8 +454,8 @@ public void testExplainTimechartPerMinute() throws IOException {
454454
var result = explainQueryToString("source=events | timechart span=2m per_minute(cpu_usage)");
455455
assertTrue(
456456
result.contains(
457-
"per_minute(cpu_usage)=[DIVIDE(*($1, 60.0E0), "
458-
+ "TIMESTAMPDIFF('SECOND':VARCHAR, $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
457+
"per_minute(cpu_usage)=[DIVIDE(*($1, 60000.0E0), TIMESTAMPDIFF('MILLISECOND':VARCHAR,"
458+
+ " $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
459459
assertTrue(result.contains("per_minute(cpu_usage)=[SUM($0)]"));
460460
}
461461

@@ -464,8 +464,8 @@ public void testExplainTimechartPerHour() throws IOException {
464464
var result = explainQueryToString("source=events | timechart span=2m per_hour(cpu_usage)");
465465
assertTrue(
466466
result.contains(
467-
"per_hour(cpu_usage)=[DIVIDE(*($1, 3600.0E0), "
468-
+ "TIMESTAMPDIFF('SECOND':VARCHAR, $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
467+
"per_hour(cpu_usage)=[DIVIDE(*($1, 3600000.0E0), TIMESTAMPDIFF('MILLISECOND':VARCHAR,"
468+
+ " $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
469469
assertTrue(result.contains("per_hour(cpu_usage)=[SUM($0)]"));
470470
}
471471

@@ -474,8 +474,8 @@ public void testExplainTimechartPerDay() throws IOException {
474474
var result = explainQueryToString("source=events | timechart span=2m per_day(cpu_usage)");
475475
assertTrue(
476476
result.contains(
477-
"per_day(cpu_usage)=[DIVIDE(*($1, 86400.0E0), "
478-
+ "TIMESTAMPDIFF('SECOND':VARCHAR, $0, TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
477+
"per_day(cpu_usage)=[DIVIDE(*($1, 8.64E7), TIMESTAMPDIFF('MILLISECOND':VARCHAR, $0,"
478+
+ " TIMESTAMPADD('MINUTE':VARCHAR, 2, $0)))]"));
479479
assertTrue(result.contains("per_day(cpu_usage)=[SUM($0)]"));
480480
}
481481

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
setup:
2+
- do:
3+
indices.create:
4+
index: test_data_2023
5+
body:
6+
mappings:
7+
properties:
8+
"@timestamp":
9+
type: date
10+
"packets":
11+
type: integer
12+
- do:
13+
bulk:
14+
index: test_data_2023
15+
refresh: true
16+
body:
17+
- '{"index":{}}'
18+
- '{"@timestamp":"2023-10-08T10:00:00.000Z","packets":10}'
19+
- '{"index":{}}'
20+
- '{"@timestamp":"2023-10-08T10:00:00.500Z","packets":15}'
21+
- '{"index":{}}'
22+
- '{"@timestamp":"2023-10-08T10:00:01.000Z","packets":20}'
23+
- '{"index":{}}'
24+
- '{"@timestamp":"2023-10-08T10:00:01.500Z","packets":25}'
25+
- '{"index":{}}'
26+
- '{"@timestamp":"2023-10-08T10:00:02.000Z","packets":30}'
27+
28+
---
29+
"timechart with millisecond span":
30+
- skip:
31+
features:
32+
- headers
33+
- allowed_warnings
34+
- do:
35+
headers:
36+
Content-Type: 'application/json'
37+
ppl:
38+
body:
39+
query: source=test_data_2023 | timechart span=500ms count()
40+
41+
- match: { total: 5 }
42+
- match: { "schema": [ { "name": "@timestamp", "type": "timestamp" }, { "name": "count", "type": "bigint" }] }
43+
- match: {"datarows": [["2023-10-08 10:00:00", 1], ["2023-10-08 10:00:00.5", 1], ["2023-10-08 10:00:01", 1], ["2023-10-08 10:00:01.5", 1], ["2023-10-08 10:00:02", 1]]}
44+
45+
---
46+
"timechart with millisecond span and per_second function":
47+
- skip:
48+
features:
49+
- headers
50+
- allowed_warnings
51+
- do:
52+
headers:
53+
Content-Type: 'application/json'
54+
ppl:
55+
body:
56+
query: source=test_data_2023 | timechart span=1000ms per_second(packets)
57+
58+
- match: { total: 3 }
59+
- match: { "schema": [ { "name": "@timestamp", "type": "timestamp" }, { "name": "per_second(packets)", "type": "double" }] }
60+
- match: {"datarows": [["2023-10-08 10:00:00", 25.0], ["2023-10-08 10:00:01", 45.0], ["2023-10-08 10:00:02", 30.0]]}
61+
62+
---
63+
"timechart with milliseconds":
64+
- skip:
65+
features:
66+
- headers
67+
- allowed_warnings
68+
- do:
69+
headers:
70+
Content-Type: 'application/json'
71+
ppl:
72+
body:
73+
query: source=test_data_2023 | timechart span=250milliseconds count()
74+
75+
- match: { total: 5 }
76+
- match: { "schema": [ { "name": "@timestamp", "type": "timestamp" }, { "name": "count", "type": "bigint" }] }
77+
78+
---
79+
"timechart with second span for comparison":
80+
- skip:
81+
features:
82+
- headers
83+
- allowed_warnings
84+
- do:
85+
headers:
86+
Content-Type: 'application/json'
87+
ppl:
88+
body:
89+
query: source=test_data_2023 | timechart span=1s count()
90+
91+
- match: { total: 3 }
92+
- match: { "schema": [ { "name": "@timestamp", "type": "timestamp" }, { "name": "count", "type": "bigint" }] }
93+
- match: {"datarows": [["2023-10-08 10:00:00", 2], ["2023-10-08 10:00:01", 2], ["2023-10-08 10:00:02", 1]]}

ppl/src/main/antlr/OpenSearchPPLLexer.g4

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ HOUR_MINUTE: 'HOUR_MINUTE';
169169
HOUR_OF_DAY: 'HOUR_OF_DAY';
170170
HOUR_SECOND: 'HOUR_SECOND';
171171
INTERVAL: 'INTERVAL';
172+
MILLISECOND: 'MILLISECOND';
172173
MICROSECOND: 'MICROSECOND';
173174
MINUTE: 'MINUTE';
174175
MINUTE_MICROSECOND: 'MINUTE_MICROSECOND';
@@ -502,7 +503,8 @@ ALIGNTIME: 'ALIGNTIME';
502503
PERCENTILE_SHORTCUT: PERC(INTEGER_LITERAL | DECIMAL_LITERAL) | 'P'(INTEGER_LITERAL | DECIMAL_LITERAL);
503504

504505
SPANLENGTH: [0-9]+ (
505-
'US'|'MS'|'CS'|'DS'
506+
'US' |'CS'|'DS'
507+
|'MS'|'MILLISECOND'|'MILLISECONDS'
506508
|'S'|'SEC'|'SECS'|'SECOND'|'SECONDS'
507509
|'MIN'|'MINS'|'MINUTE'|'MINUTES'
508510
|'H'|'HR'|'HRS'|'HOUR'|'HOURS'

0 commit comments

Comments
 (0)