mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-20 03:45:02 +00:00
SQL: use calendar interval of 1y instead of fixed interval for grouping by YEAR and HISTOGRAMs (#47558)
(cherry picked from commit 55f5463eee4ecea3537df4b34645f1d87472a802)
This commit is contained in:
parent
54c2aec38a
commit
75a7daae73
@ -86,6 +86,16 @@ the multiple of a day. E.g.: for `HISTOGRAM(CAST(birth_date AS DATE), INTERVAL '
|
|||||||
actually used will be `INTERVAL '2' DAY`. If the interval specified is less than 1 day, e.g.:
|
actually used will be `INTERVAL '2' DAY`. If the interval specified is less than 1 day, e.g.:
|
||||||
`HISTOGRAM(CAST(birth_date AS DATE), INTERVAL '20' HOUR)` then the interval used will be `INTERVAL '1' DAY`.
|
`HISTOGRAM(CAST(birth_date AS DATE), INTERVAL '20' HOUR)` then the interval used will be `INTERVAL '1' DAY`.
|
||||||
|
|
||||||
|
[IMPORTANT]
|
||||||
|
All intervals specified for a date/time HISTOGRAM will use a <<search-aggregations-bucket-datehistogram-aggregation,fixed interval>>
|
||||||
|
in their `date_histogram` aggregation definition, with the notable exception of `INTERVAL '1' YEAR` where a calendar interval is used.
|
||||||
|
The choice for a calendar interval was made for having a more intuitive result for YEAR groupings. Calendar intervals consider a one year
|
||||||
|
bucket as the one starting on January 1st that specific year, whereas a fixed interval one-year-bucket considers one year as a number
|
||||||
|
of milliseconds (for example, `31536000000ms` corresponding to 365 days, 24 hours per day, 60 minutes per hour etc.). With fixed intervals,
|
||||||
|
the day of February 5th, 2019 for example, belongs to a bucket that starts on December 20th, 2018 and {es} (and implicitly {es-sql}) would
|
||||||
|
have returned the year 2018 for a date that's actually in 2019. With calendar interval this behavior is more intuitive, having the day of
|
||||||
|
February 5th, 2019 actually belonging to the 2019 year bucket.
|
||||||
|
|
||||||
[IMPORTANT]
|
[IMPORTANT]
|
||||||
Histogram in SQL cannot be applied applied on **TIME** type.
|
Histogram in SQL cannot be applied applied on **TIME** type.
|
||||||
E.g.: `HISTOGRAM(CAST(birth_date AS TIME), INTERVAL '10' MINUTES)` is currently not supported.
|
E.g.: `HISTOGRAM(CAST(birth_date AS TIME), INTERVAL '10' MINUTES)` is currently not supported.
|
||||||
|
@ -273,47 +273,46 @@ histogramDateTime
|
|||||||
schema::h:ts|c:l
|
schema::h:ts|c:l
|
||||||
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) as c FROM test_emp GROUP BY h;
|
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) as c FROM test_emp GROUP BY h;
|
||||||
|
|
||||||
h | c
|
h | c
|
||||||
--------------------+---------------
|
------------------------+---------------
|
||||||
null |10
|
null |10
|
||||||
1951-04-11T00:00:00Z|1
|
1952-01-01T00:00:00.000Z|8
|
||||||
1952-04-05T00:00:00Z|10
|
1953-01-01T00:00:00.000Z|11
|
||||||
1953-03-31T00:00:00Z|10
|
1954-01-01T00:00:00.000Z|8
|
||||||
1954-03-26T00:00:00Z|7
|
1955-01-01T00:00:00.000Z|4
|
||||||
1955-03-21T00:00:00Z|4
|
1956-01-01T00:00:00.000Z|5
|
||||||
1956-03-15T00:00:00Z|4
|
1957-01-01T00:00:00.000Z|4
|
||||||
1957-03-10T00:00:00Z|6
|
1958-01-01T00:00:00.000Z|7
|
||||||
1958-03-05T00:00:00Z|6
|
1959-01-01T00:00:00.000Z|9
|
||||||
1959-02-28T00:00:00Z|9
|
1960-01-01T00:00:00.000Z|8
|
||||||
1960-02-23T00:00:00Z|7
|
1961-01-01T00:00:00.000Z|8
|
||||||
1961-02-17T00:00:00Z|8
|
1962-01-01T00:00:00.000Z|6
|
||||||
1962-02-12T00:00:00Z|6
|
1963-01-01T00:00:00.000Z|7
|
||||||
1963-02-07T00:00:00Z|7
|
1964-01-01T00:00:00.000Z|4
|
||||||
1964-02-02T00:00:00Z|5
|
1965-01-01T00:00:00.000Z|1
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
histogramDateTimeWithCountAndOrder
|
histogramDateTimeWithCountAndOrder
|
||||||
schema::h:ts|c:l
|
schema::h:ts|c:l
|
||||||
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) as c FROM test_emp GROUP BY h ORDER BY h DESC;
|
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) as c FROM test_emp GROUP BY h ORDER BY h DESC;
|
||||||
|
|
||||||
h | c
|
h | c
|
||||||
--------------------+---------------
|
------------------------+---------------
|
||||||
1964-02-02T00:00:00Z|5
|
1965-01-01T00:00:00.000Z|1
|
||||||
1963-02-07T00:00:00Z|7
|
1964-01-01T00:00:00.000Z|4
|
||||||
1962-02-12T00:00:00Z|6
|
1963-01-01T00:00:00.000Z|7
|
||||||
1961-02-17T00:00:00Z|8
|
1962-01-01T00:00:00.000Z|6
|
||||||
1960-02-23T00:00:00Z|7
|
1961-01-01T00:00:00.000Z|8
|
||||||
1959-02-28T00:00:00Z|9
|
1960-01-01T00:00:00.000Z|8
|
||||||
1958-03-05T00:00:00Z|6
|
1959-01-01T00:00:00.000Z|9
|
||||||
1957-03-10T00:00:00Z|6
|
1958-01-01T00:00:00.000Z|7
|
||||||
1956-03-15T00:00:00Z|4
|
1957-01-01T00:00:00.000Z|4
|
||||||
1955-03-21T00:00:00Z|4
|
1956-01-01T00:00:00.000Z|5
|
||||||
1954-03-26T00:00:00Z|7
|
1955-01-01T00:00:00.000Z|4
|
||||||
1953-03-31T00:00:00Z|10
|
1954-01-01T00:00:00.000Z|8
|
||||||
1952-04-05T00:00:00Z|10
|
1953-01-01T00:00:00.000Z|11
|
||||||
1951-04-11T00:00:00Z|1
|
1952-01-01T00:00:00.000Z|8
|
||||||
null |10
|
null |10
|
||||||
;
|
;
|
||||||
|
|
||||||
histogramDateTimeWithMonthOnTop
|
histogramDateTimeWithMonthOnTop
|
||||||
@ -369,23 +368,23 @@ histogramGroupByWithoutAlias
|
|||||||
schema::h:ts|c:l
|
schema::h:ts|c:l
|
||||||
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) as c FROM test_emp GROUP BY HISTOGRAM(birth_date, INTERVAL 1 YEAR) ORDER BY h DESC;
|
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) as c FROM test_emp GROUP BY HISTOGRAM(birth_date, INTERVAL 1 YEAR) ORDER BY h DESC;
|
||||||
|
|
||||||
h | c
|
h | c
|
||||||
--------------------+---------------
|
------------------------+---------------
|
||||||
1964-02-02T00:00:00Z|5
|
1965-01-01T00:00:00.000Z|1
|
||||||
1963-02-07T00:00:00Z|7
|
1964-01-01T00:00:00.000Z|4
|
||||||
1962-02-12T00:00:00Z|6
|
1963-01-01T00:00:00.000Z|7
|
||||||
1961-02-17T00:00:00Z|8
|
1962-01-01T00:00:00.000Z|6
|
||||||
1960-02-23T00:00:00Z|7
|
1961-01-01T00:00:00.000Z|8
|
||||||
1959-02-28T00:00:00Z|9
|
1960-01-01T00:00:00.000Z|8
|
||||||
1958-03-05T00:00:00Z|6
|
1959-01-01T00:00:00.000Z|9
|
||||||
1957-03-10T00:00:00Z|6
|
1958-01-01T00:00:00.000Z|7
|
||||||
1956-03-15T00:00:00Z|4
|
1957-01-01T00:00:00.000Z|4
|
||||||
1955-03-21T00:00:00Z|4
|
1956-01-01T00:00:00.000Z|5
|
||||||
1954-03-26T00:00:00Z|7
|
1955-01-01T00:00:00.000Z|4
|
||||||
1953-03-31T00:00:00Z|10
|
1954-01-01T00:00:00.000Z|8
|
||||||
1952-04-05T00:00:00Z|10
|
1953-01-01T00:00:00.000Z|11
|
||||||
1951-04-11T00:00:00Z|1
|
1952-01-01T00:00:00.000Z|8
|
||||||
null |10
|
null |10
|
||||||
;
|
;
|
||||||
|
|
||||||
countAll
|
countAll
|
||||||
|
@ -811,23 +811,23 @@ schema::h:ts|c:l
|
|||||||
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) AS c FROM emp GROUP BY h;
|
SELECT HISTOGRAM(birth_date, INTERVAL 1 YEAR) AS h, COUNT(*) AS c FROM emp GROUP BY h;
|
||||||
|
|
||||||
|
|
||||||
h | c
|
h | c
|
||||||
--------------------+---------------
|
------------------------+---------------
|
||||||
null |10
|
null |10
|
||||||
1951-04-11T00:00:00Z|1
|
1952-01-01T00:00:00.000Z|8
|
||||||
1952-04-05T00:00:00Z|10
|
1953-01-01T00:00:00.000Z|11
|
||||||
1953-03-31T00:00:00Z|10
|
1954-01-01T00:00:00.000Z|8
|
||||||
1954-03-26T00:00:00Z|7
|
1955-01-01T00:00:00.000Z|4
|
||||||
1955-03-21T00:00:00Z|4
|
1956-01-01T00:00:00.000Z|5
|
||||||
1956-03-15T00:00:00Z|4
|
1957-01-01T00:00:00.000Z|4
|
||||||
1957-03-10T00:00:00Z|6
|
1958-01-01T00:00:00.000Z|7
|
||||||
1958-03-05T00:00:00Z|6
|
1959-01-01T00:00:00.000Z|9
|
||||||
1959-02-28T00:00:00Z|9
|
1960-01-01T00:00:00.000Z|8
|
||||||
1960-02-23T00:00:00Z|7
|
1961-01-01T00:00:00.000Z|8
|
||||||
1961-02-17T00:00:00Z|8
|
1962-01-01T00:00:00.000Z|6
|
||||||
1962-02-12T00:00:00Z|6
|
1963-01-01T00:00:00.000Z|7
|
||||||
1963-02-07T00:00:00Z|7
|
1964-01-01T00:00:00.000Z|4
|
||||||
1964-02-02T00:00:00Z|5
|
1965-01-01T00:00:00.000Z|1
|
||||||
|
|
||||||
// end::histogramDateTime
|
// end::histogramDateTime
|
||||||
;
|
;
|
||||||
|
@ -101,13 +101,13 @@ SELECT MIN(salary) mi, MAX(salary) ma, YEAR(hire_date) year, ROUND(AVG(languages
|
|||||||
|
|
||||||
mi:i | ma:i | year:i |ROUND(AVG(languages), 1):d|TRUNCATE(AVG(languages), 1):d| COUNT(*):l
|
mi:i | ma:i | year:i |ROUND(AVG(languages), 1):d|TRUNCATE(AVG(languages), 1):d| COUNT(*):l
|
||||||
---------------+---------------+---------------+--------------------------+-----------------------------+---------------
|
---------------+---------------+---------------+--------------------------+-----------------------------+---------------
|
||||||
25324 |70011 |1986 |3.0 |3.0 |15
|
25324 |70011 |1987 |3.0 |3.0 |15
|
||||||
25945 |73578 |1987 |2.9 |2.8 |9
|
25945 |73578 |1988 |2.9 |2.8 |9
|
||||||
25976 |74970 |1988 |3.0 |3.0 |13
|
25976 |74970 |1989 |3.0 |3.0 |13
|
||||||
31120 |71165 |1989 |3.1 |3.0 |12
|
31120 |71165 |1990 |3.1 |3.0 |12
|
||||||
30404 |58715 |1992 |3.0 |3.0 |3
|
30404 |58715 |1993 |3.0 |3.0 |3
|
||||||
35742 |67492 |1993 |2.8 |2.7 |4
|
35742 |67492 |1994 |2.8 |2.7 |4
|
||||||
45656 |45656 |1995 |3.0 |3.0 |1
|
45656 |45656 |1996 |3.0 |3.0 |1
|
||||||
;
|
;
|
||||||
|
|
||||||
minMaxRoundWithHavingRound
|
minMaxRoundWithHavingRound
|
||||||
@ -115,17 +115,17 @@ SELECT MIN(salary) mi, MAX(salary) ma, YEAR(hire_date) year, ROUND(AVG(languages
|
|||||||
|
|
||||||
mi:i | ma:i | year:i |ROUND(AVG(languages),1):d| COUNT(*):l
|
mi:i | ma:i | year:i |ROUND(AVG(languages),1):d| COUNT(*):l
|
||||||
---------------+---------------+---------------+-------------------------+---------------
|
---------------+---------------+---------------+-------------------------+---------------
|
||||||
26436 |74999 |1984 |3.1 |11
|
26436 |74999 |1985 |3.1 |11
|
||||||
31897 |61805 |1985 |3.5 |11
|
31897 |61805 |1986 |3.5 |11
|
||||||
25324 |70011 |1986 |3.0 |15
|
25324 |70011 |1987 |3.0 |15
|
||||||
25945 |73578 |1987 |2.9 |9
|
25945 |73578 |1988 |2.9 |9
|
||||||
25976 |74970 |1988 |3.0 |13
|
25976 |74970 |1989 |3.0 |13
|
||||||
31120 |71165 |1989 |3.1 |12
|
31120 |71165 |1990 |3.1 |12
|
||||||
32568 |65030 |1990 |3.3 |6
|
32568 |65030 |1991 |3.3 |6
|
||||||
27215 |60781 |1991 |4.1 |8
|
27215 |60781 |1992 |4.1 |8
|
||||||
30404 |58715 |1992 |3.0 |3
|
30404 |58715 |1993 |3.0 |3
|
||||||
35742 |67492 |1993 |2.8 |4
|
35742 |67492 |1994 |2.8 |4
|
||||||
45656 |45656 |1995 |3.0 |1
|
45656 |45656 |1996 |3.0 |1
|
||||||
;
|
;
|
||||||
|
|
||||||
groupByAndOrderByTruncateWithPositiveParameter
|
groupByAndOrderByTruncateWithPositiveParameter
|
||||||
|
@ -22,7 +22,13 @@ public abstract class DateTimeHistogramFunction extends DateTimeFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used for aggregration (date histogram)
|
* used for aggregation (date histogram)
|
||||||
*/
|
*/
|
||||||
public abstract long interval();
|
public long fixedInterval() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String calendarInterval() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||||
|
|
||||||
|
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
|
||||||
import org.elasticsearch.xpack.sql.tree.Source;
|
|
||||||
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.Source;
|
||||||
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the year from a datetime.
|
* Extract the year from a datetime.
|
||||||
*/
|
*/
|
||||||
public class Year extends DateTimeHistogramFunction {
|
public class Year extends DateTimeHistogramFunction {
|
||||||
|
|
||||||
private static long YEAR_IN_MILLIS = TimeUnit.DAYS.toMillis(1) * 365L;
|
public static String YEAR_INTERVAL = DateHistogramInterval.YEAR.toString();
|
||||||
|
|
||||||
public Year(Source source, Expression field, ZoneId zoneId) {
|
public Year(Source source, Expression field, ZoneId zoneId) {
|
||||||
super(source, field, zoneId, DateTimeExtractor.YEAR);
|
super(source, field, zoneId, DateTimeExtractor.YEAR);
|
||||||
@ -45,7 +45,7 @@ public class Year extends DateTimeHistogramFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long interval() {
|
public String calendarInterval() {
|
||||||
return YEAR_IN_MILLIS;
|
return YEAR_INTERVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,11 @@ import org.elasticsearch.xpack.sql.expression.function.grouping.Histogram;
|
|||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeHistogramFunction;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeHistogramFunction;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Year;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.geo.GeoShape;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.geo.GeoShape;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.geo.StDistance;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.geo.StDistance;
|
||||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.literal.IntervalYearMonth;
|
||||||
import org.elasticsearch.xpack.sql.expression.literal.Intervals;
|
import org.elasticsearch.xpack.sql.expression.literal.Intervals;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate;
|
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate;
|
||||||
@ -109,6 +111,7 @@ import org.elasticsearch.xpack.sql.util.DateUtils;
|
|||||||
import org.elasticsearch.xpack.sql.util.ReflectionUtils;
|
import org.elasticsearch.xpack.sql.util.ReflectionUtils;
|
||||||
|
|
||||||
import java.time.OffsetTime;
|
import java.time.OffsetTime;
|
||||||
|
import java.time.Period;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -279,7 +282,11 @@ final class QueryTranslator {
|
|||||||
// dates are handled differently because of date histograms
|
// dates are handled differently because of date histograms
|
||||||
if (exp instanceof DateTimeHistogramFunction) {
|
if (exp instanceof DateTimeHistogramFunction) {
|
||||||
DateTimeHistogramFunction dthf = (DateTimeHistogramFunction) exp;
|
DateTimeHistogramFunction dthf = (DateTimeHistogramFunction) exp;
|
||||||
key = new GroupByDateHistogram(aggId, nameOf(exp), dthf.interval(), dthf.zoneId());
|
if (dthf.calendarInterval() != null) {
|
||||||
|
key = new GroupByDateHistogram(aggId, nameOf(exp), dthf.calendarInterval(), dthf.zoneId());
|
||||||
|
} else {
|
||||||
|
key = new GroupByDateHistogram(aggId, nameOf(exp), dthf.fixedInterval(), dthf.zoneId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// all other scalar functions become a script
|
// all other scalar functions become a script
|
||||||
else if (exp instanceof ScalarFunction) {
|
else if (exp instanceof ScalarFunction) {
|
||||||
@ -294,19 +301,33 @@ final class QueryTranslator {
|
|||||||
|
|
||||||
// date histogram
|
// date histogram
|
||||||
if (h.dataType().isDateBased()) {
|
if (h.dataType().isDateBased()) {
|
||||||
long intervalAsMillis = Intervals.inMillis(h.interval());
|
Object value = h.interval().value();
|
||||||
|
if (value instanceof IntervalYearMonth
|
||||||
// When the histogram in SQL is applied on DATE type instead of DATETIME, the interval
|
&& ((IntervalYearMonth) value).interval().equals(Period.of(1, 0, 0))) {
|
||||||
// specified is truncated to the multiple of a day. If the interval specified is less
|
String calendarInterval = Year.YEAR_INTERVAL;
|
||||||
// than 1 day, then the interval used will be `INTERVAL '1' DAY`.
|
|
||||||
if (h.dataType() == DATE) {
|
// When the histogram is `INTERVAL '1' YEAR`, the interval used in the ES date_histogram will be
|
||||||
intervalAsMillis = DateUtils.minDayInterval(intervalAsMillis);
|
// a calendar_interval with value "1y". All other intervals will be fixed_intervals expressed in ms.
|
||||||
}
|
if (field instanceof FieldAttribute) {
|
||||||
|
key = new GroupByDateHistogram(aggId, nameOf(field), calendarInterval, h.zoneId());
|
||||||
if (field instanceof FieldAttribute) {
|
} else if (field instanceof Function) {
|
||||||
key = new GroupByDateHistogram(aggId, nameOf(field), intervalAsMillis, h.zoneId());
|
key = new GroupByDateHistogram(aggId, ((Function) field).asScript(), calendarInterval, h.zoneId());
|
||||||
} else if (field instanceof Function) {
|
}
|
||||||
key = new GroupByDateHistogram(aggId, ((Function) field).asScript(), intervalAsMillis, h.zoneId());
|
} else {
|
||||||
|
long intervalAsMillis = Intervals.inMillis(h.interval());
|
||||||
|
|
||||||
|
// When the histogram in SQL is applied on DATE type instead of DATETIME, the interval
|
||||||
|
// specified is truncated to the multiple of a day. If the interval specified is less
|
||||||
|
// than 1 day, then the interval used will be `INTERVAL '1' DAY`.
|
||||||
|
if (h.dataType() == DATE) {
|
||||||
|
intervalAsMillis = DateUtils.minDayInterval(intervalAsMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field instanceof FieldAttribute) {
|
||||||
|
key = new GroupByDateHistogram(aggId, nameOf(field), intervalAsMillis, h.zoneId());
|
||||||
|
} else if (field instanceof Function) {
|
||||||
|
key = new GroupByDateHistogram(aggId, ((Function) field).asScript(), intervalAsMillis, h.zoneId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// numeric histogram
|
// numeric histogram
|
||||||
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.sql.querydsl.agg;
|
|||||||
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
|
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
|
||||||
import org.elasticsearch.search.aggregations.bucket.composite.DateHistogramValuesSourceBuilder;
|
import org.elasticsearch.search.aggregations.bucket.composite.DateHistogramValuesSourceBuilder;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
||||||
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||||
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Direction;
|
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Direction;
|
||||||
|
|
||||||
@ -19,52 +20,65 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public class GroupByDateHistogram extends GroupByKey {
|
public class GroupByDateHistogram extends GroupByKey {
|
||||||
|
|
||||||
private final long interval;
|
private final long fixedInterval;
|
||||||
|
private final String calendarInterval;
|
||||||
private final ZoneId zoneId;
|
private final ZoneId zoneId;
|
||||||
|
|
||||||
public GroupByDateHistogram(String id, String fieldName, long interval, ZoneId zoneId) {
|
public GroupByDateHistogram(String id, String fieldName, long fixedInterval, ZoneId zoneId) {
|
||||||
this(id, fieldName, null, null, interval, zoneId);
|
this(id, fieldName, null, null, fixedInterval, null, zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupByDateHistogram(String id, ScriptTemplate script, long interval, ZoneId zoneId) {
|
public GroupByDateHistogram(String id, ScriptTemplate script, long fixedInterval, ZoneId zoneId) {
|
||||||
this(id, null, script, null, interval, zoneId);
|
this(id, null, script, null, fixedInterval, null, zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupByDateHistogram(String id, String fieldName, String calendarInterval, ZoneId zoneId) {
|
||||||
|
this(id, fieldName, null, null, -1L, calendarInterval, zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupByDateHistogram(String id, ScriptTemplate script, String calendarInterval, ZoneId zoneId) {
|
||||||
|
this(id, null, script, null, -1L, calendarInterval, zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GroupByDateHistogram(String id, String fieldName, ScriptTemplate script, Direction direction, long interval,
|
private GroupByDateHistogram(String id, String fieldName, ScriptTemplate script, Direction direction, long fixedInterval,
|
||||||
ZoneId zoneId) {
|
String calendarInterval, ZoneId zoneId) {
|
||||||
super(id, fieldName, script, direction);
|
super(id, fieldName, script, direction);
|
||||||
this.interval = interval;
|
if (fixedInterval <= 0 && (calendarInterval == null || calendarInterval.trim().isEmpty())) {
|
||||||
|
throw new SqlIllegalArgumentException("Either fixed interval or calendar interval needs to be specified");
|
||||||
|
}
|
||||||
|
this.fixedInterval = fixedInterval;
|
||||||
|
this.calendarInterval = calendarInterval;
|
||||||
this.zoneId = zoneId;
|
this.zoneId = zoneId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing
|
// For testing
|
||||||
public long interval() {
|
public long fixedInterval() {
|
||||||
return interval;
|
return fixedInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CompositeValuesSourceBuilder<?> createSourceBuilder() {
|
protected CompositeValuesSourceBuilder<?> createSourceBuilder() {
|
||||||
return new DateHistogramValuesSourceBuilder(id())
|
DateHistogramValuesSourceBuilder builder = new DateHistogramValuesSourceBuilder(id()).timeZone(zoneId);
|
||||||
.fixedInterval(new DateHistogramInterval(interval + "ms"))
|
return calendarInterval != null ? builder.calendarInterval(new DateHistogramInterval(calendarInterval))
|
||||||
.timeZone(zoneId);
|
: builder.fixedInterval(new DateHistogramInterval(fixedInterval + "ms"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GroupByKey copy(String id, String fieldName, ScriptTemplate script, Direction direction) {
|
protected GroupByKey copy(String id, String fieldName, ScriptTemplate script, Direction direction) {
|
||||||
return new GroupByDateHistogram(id, fieldName, script, direction, interval, zoneId);
|
return new GroupByDateHistogram(id, fieldName, script, direction, fixedInterval, calendarInterval, zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), interval, zoneId);
|
return Objects.hash(super.hashCode(), fixedInterval, calendarInterval, zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (super.equals(obj)) {
|
if (super.equals(obj)) {
|
||||||
GroupByDateHistogram other = (GroupByDateHistogram) obj;
|
GroupByDateHistogram other = (GroupByDateHistogram) obj;
|
||||||
return Objects.equals(interval, other.interval)
|
return Objects.equals(fixedInterval, other.fixedInterval)
|
||||||
|
&& Objects.equals(calendarInterval, other.calendarInterval)
|
||||||
&& Objects.equals(zoneId, other.zoneId);
|
&& Objects.equals(zoneId, other.zoneId);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -915,7 +915,7 @@ public class QueryTranslatorTests extends ESTestCase {
|
|||||||
assertEquals(DataType.INTEGER, eqe.output().get(0).dataType());
|
assertEquals(DataType.INTEGER, eqe.output().get(0).dataType());
|
||||||
assertThat(eqe.queryContainer().aggs().asAggBuilder().toString().replaceAll("\\s+", ""),
|
assertThat(eqe.queryContainer().aggs().asAggBuilder().toString().replaceAll("\\s+", ""),
|
||||||
endsWith("\"date_histogram\":{\"field\":\"date\",\"missing_bucket\":true,\"value_type\":\"date\",\"order\":\"asc\","
|
endsWith("\"date_histogram\":{\"field\":\"date\",\"missing_bucket\":true,\"value_type\":\"date\",\"order\":\"asc\","
|
||||||
+ "\"fixed_interval\":\"31536000000ms\",\"time_zone\":\"Z\"}}}]}}}"));
|
+ "\"calendar_interval\":\"1y\",\"time_zone\":\"Z\"}}}]}}}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGroupByHistogramWithDate() {
|
public void testGroupByHistogramWithDate() {
|
||||||
@ -940,7 +940,7 @@ public class QueryTranslatorTests extends ESTestCase {
|
|||||||
EsQueryExec eqe = (EsQueryExec) p;
|
EsQueryExec eqe = (EsQueryExec) p;
|
||||||
assertEquals(1, eqe.queryContainer().aggs().groups().size());
|
assertEquals(1, eqe.queryContainer().aggs().groups().size());
|
||||||
assertEquals(GroupByDateHistogram.class, eqe.queryContainer().aggs().groups().get(0).getClass());
|
assertEquals(GroupByDateHistogram.class, eqe.queryContainer().aggs().groups().get(0).getClass());
|
||||||
assertEquals(86400000L, ((GroupByDateHistogram) eqe.queryContainer().aggs().groups().get(0)).interval());
|
assertEquals(86400000L, ((GroupByDateHistogram) eqe.queryContainer().aggs().groups().get(0)).fixedInterval());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGroupByHistogramWithDateTruncateIntervalToDayMultiples() {
|
public void testGroupByHistogramWithDateTruncateIntervalToDayMultiples() {
|
||||||
@ -951,7 +951,7 @@ public class QueryTranslatorTests extends ESTestCase {
|
|||||||
EsQueryExec eqe = (EsQueryExec) p;
|
EsQueryExec eqe = (EsQueryExec) p;
|
||||||
assertEquals(1, eqe.queryContainer().aggs().groups().size());
|
assertEquals(1, eqe.queryContainer().aggs().groups().size());
|
||||||
assertEquals(GroupByDateHistogram.class, eqe.queryContainer().aggs().groups().get(0).getClass());
|
assertEquals(GroupByDateHistogram.class, eqe.queryContainer().aggs().groups().get(0).getClass());
|
||||||
assertEquals(172800000L, ((GroupByDateHistogram) eqe.queryContainer().aggs().groups().get(0)).interval());
|
assertEquals(172800000L, ((GroupByDateHistogram) eqe.queryContainer().aggs().groups().get(0)).fixedInterval());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PhysicalPlan p = optimizeAndPlan("SELECT MAX(int) FROM test GROUP BY " +
|
PhysicalPlan p = optimizeAndPlan("SELECT MAX(int) FROM test GROUP BY " +
|
||||||
@ -960,7 +960,7 @@ public class QueryTranslatorTests extends ESTestCase {
|
|||||||
EsQueryExec eqe = (EsQueryExec) p;
|
EsQueryExec eqe = (EsQueryExec) p;
|
||||||
assertEquals(1, eqe.queryContainer().aggs().groups().size());
|
assertEquals(1, eqe.queryContainer().aggs().groups().size());
|
||||||
assertEquals(GroupByDateHistogram.class, eqe.queryContainer().aggs().groups().get(0).getClass());
|
assertEquals(GroupByDateHistogram.class, eqe.queryContainer().aggs().groups().get(0).getClass());
|
||||||
assertEquals(259200000L, ((GroupByDateHistogram) eqe.queryContainer().aggs().groups().get(0)).interval());
|
assertEquals(259200000L, ((GroupByDateHistogram) eqe.queryContainer().aggs().groups().get(0)).fixedInterval());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user