mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 18:35:25 +00:00
Add support for percentile and percentile ranks aggs
Original commit: elastic/x-pack-elasticsearch@dc443ed465
This commit is contained in:
parent
335838db08
commit
2c830bdff2
@ -20,10 +20,8 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import static java.lang.String.format;
|
|
||||||
import static org.elasticsearch.xpack.sql.jdbc.framework.JdbcAssert.assertResultSets;
|
import static org.elasticsearch.xpack.sql.jdbc.framework.JdbcAssert.assertResultSets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,7 +48,9 @@ public class CsvSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
CsvSpecParser parser = new CsvSpecParser();
|
CsvSpecParser parser = new CsvSpecParser();
|
||||||
return CollectionUtils.combine(
|
return CollectionUtils.combine(
|
||||||
readScriptSpec("/command.csv-spec", parser),
|
readScriptSpec("/command.csv-spec", parser),
|
||||||
readScriptSpec("/fulltext.csv-spec", parser));
|
readScriptSpec("/fulltext.csv-spec", parser),
|
||||||
|
readScriptSpec("/agg.csv-spec", parser)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CsvSpecIT(String groupName, String testName, Integer lineNumber, Path source, CsvTestCase testCase) {
|
public CsvSpecIT(String groupName, String testName, Integer lineNumber, Path source, CsvTestCase testCase) {
|
||||||
@ -62,7 +62,7 @@ public class CsvSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
try {
|
try {
|
||||||
assertMatchesCsv(testCase.query, testName, testCase.expectedResults);
|
assertMatchesCsv(testCase.query, testName, testCase.expectedResults);
|
||||||
} catch (AssertionError ae) {
|
} catch (AssertionError ae) {
|
||||||
throw reworkException(new AssertionError(errorMessage(ae), ae.getCause()));
|
throw reworkException(ae);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,22 +86,20 @@ public class CsvSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
.executeQuery("SELECT * FROM " + csvTableName);
|
.executeQuery("SELECT * FROM " + csvTableName);
|
||||||
// trigger data loading for type inference
|
// trigger data loading for type inference
|
||||||
expected.beforeFirst();
|
expected.beforeFirst();
|
||||||
Statement statement = es.createStatement();
|
ResultSet actual = executeJdbcQuery(es, query);
|
||||||
//statement.setFetchSize(randomInt(10));
|
|
||||||
// NOCOMMIT: hook up pagination
|
|
||||||
// NOCOMMIT sometimes accept the default fetch size. I believe it is 0 now which breaks things.
|
|
||||||
statement.setFetchSize(1000);
|
|
||||||
ResultSet actual = statement.executeQuery(query);
|
|
||||||
assertResultSets(expected, actual);
|
assertResultSets(expected, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String errorMessage(Throwable th) {
|
private ResultSet executeJdbcQuery(Connection con, String query) throws SQLException {
|
||||||
return format(Locale.ROOT, "test%s@%s:%d failed\n\"%s\"\n%s", testName, source.getFileName().toString(), lineNumber,
|
Statement statement = con.createStatement();
|
||||||
testCase.query, th.getMessage());
|
//statement.setFetchSize(randomInt(10));
|
||||||
|
// NOCOMMIT: hook up pagination
|
||||||
|
statement.setFetchSize(1000);
|
||||||
|
return statement.executeQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CsvSpecParser implements Parser {
|
protected static class CsvSpecParser implements Parser {
|
||||||
private final StringBuilder data = new StringBuilder();
|
private final StringBuilder data = new StringBuilder();
|
||||||
private CsvTestCase testCase;
|
private CsvTestCase testCase;
|
||||||
|
|
||||||
@ -137,7 +135,7 @@ public class CsvSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CsvTestCase {
|
protected static class CsvTestCase {
|
||||||
String query;
|
String query;
|
||||||
String expectedResults;
|
String expectedResults;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.jdbc;
|
||||||
|
|
||||||
|
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.jdbc.framework.JdbcTestUtils;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class DebugCsvSpec extends CsvSpecIT {
|
||||||
|
|
||||||
|
@ParametersFactory(shuffle = false, argumentFormatting = SqlSpecIT.PARAM_FORMATTING) // NOCOMMIT are we sure?!
|
||||||
|
public static List<Object[]> readScriptSpec() throws Exception {
|
||||||
|
JdbcTestUtils.sqlLogging();
|
||||||
|
|
||||||
|
CsvSpecParser parser = new CsvSpecParser();
|
||||||
|
return readScriptSpec("/debug.csv-spec", parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebugCsvSpec(String groupName, String testName, Integer lineNumber, Path source, CsvTestCase testCase) {
|
||||||
|
super(groupName, testName, lineNumber, source, testCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void assertResults(ResultSet expected, ResultSet actual) throws SQLException {
|
||||||
|
// Logger logger = Loggers.getLogger("org.elasticsearch.xpack.sql.test");
|
||||||
|
// Loggers.setLevel(logger, "INFO");
|
||||||
|
//
|
||||||
|
// JdbcTestUtils.resultSetToLogger(logger, actual);
|
||||||
|
// }
|
||||||
|
}
|
@ -39,7 +39,7 @@ public class SqlSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
// example for enabling logging
|
// example for enabling logging
|
||||||
//JdbcTestUtils.sqlLogging();
|
//JdbcTestUtils.sqlLogging();
|
||||||
|
|
||||||
SqlSpecParser parser = new SqlSpecParser();
|
Parser parser = parser();
|
||||||
return CollectionUtils.combine(
|
return CollectionUtils.combine(
|
||||||
readScriptSpec("/select.sql-spec", parser),
|
readScriptSpec("/select.sql-spec", parser),
|
||||||
readScriptSpec("/filter.sql-spec", parser),
|
readScriptSpec("/filter.sql-spec", parser),
|
||||||
@ -63,6 +63,10 @@ public class SqlSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SqlSpecParser parser() {
|
||||||
|
return new SqlSpecParser();
|
||||||
|
}
|
||||||
|
|
||||||
public SqlSpecIT(String groupName, String testName, Integer lineNumber, Path source, String query) {
|
public SqlSpecIT(String groupName, String testName, Integer lineNumber, Path source, String query) {
|
||||||
super(groupName, testName, lineNumber, source);
|
super(groupName, testName, lineNumber, source);
|
||||||
this.query = query;
|
this.query = query;
|
||||||
@ -74,17 +78,17 @@ public class SqlSpecIT extends SpecBaseIntegrationTestCase {
|
|||||||
Connection es = esJdbc()) {
|
Connection es = esJdbc()) {
|
||||||
ResultSet expected, actual;
|
ResultSet expected, actual;
|
||||||
try {
|
try {
|
||||||
expected = executeQuery(h2);
|
expected = executeJdbcQuery(h2);
|
||||||
actual = executeQuery(es);
|
actual = executeJdbcQuery(es);
|
||||||
|
|
||||||
assertResultSets(expected, actual);
|
assertResultSets(expected, actual);
|
||||||
} catch (AssertionError ae) {
|
} catch (AssertionError ae) {
|
||||||
throw reworkException(new AssertionError(errorMessage(ae), ae.getCause()));
|
throw reworkException(ae);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultSet executeQuery(Connection con) throws SQLException {
|
private ResultSet executeJdbcQuery(Connection con) throws SQLException {
|
||||||
Statement statement = con.createStatement();
|
Statement statement = con.createStatement();
|
||||||
//statement.setFetchSize(randomInt(10));
|
//statement.setFetchSize(randomInt(10));
|
||||||
// NOCOMMIT: hook up pagination
|
// NOCOMMIT: hook up pagination
|
||||||
|
@ -10,10 +10,13 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@ -29,7 +32,22 @@ public class JdbcAssert {
|
|||||||
ResultSetMetaData expectedMeta = expected.getMetaData();
|
ResultSetMetaData expectedMeta = expected.getMetaData();
|
||||||
ResultSetMetaData actualMeta = actual.getMetaData();
|
ResultSetMetaData actualMeta = actual.getMetaData();
|
||||||
|
|
||||||
assertEquals("Different number of columns returned", expectedMeta.getColumnCount(), actualMeta.getColumnCount());
|
if (expectedMeta.getColumnCount() != actualMeta.getColumnCount()) {
|
||||||
|
List<String> expectedCols = new ArrayList<>();
|
||||||
|
for (int i = 1; i <= expectedMeta.getColumnCount(); i++) {
|
||||||
|
expectedCols.add(expectedMeta.getColumnName(i));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> actualCols = new ArrayList<>();
|
||||||
|
for (int i = 1; i <= actualMeta.getColumnCount(); i++) {
|
||||||
|
actualCols.add(actualMeta.getColumnName(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(format(Locale.ROOT, "Different number of columns returned (expected %d but was %d);",
|
||||||
|
expectedMeta.getColumnCount(), actualMeta.getColumnCount()),
|
||||||
|
expectedCols.toString(), actualCols.toString());
|
||||||
|
}
|
||||||
|
|
||||||
for (int column = 1; column <= expectedMeta.getColumnCount(); column++) {
|
for (int column = 1; column <= expectedMeta.getColumnCount(); column++) {
|
||||||
String expectedName = expectedMeta.getColumnName(column);
|
String expectedName = expectedMeta.getColumnName(column);
|
||||||
|
@ -5,9 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.jdbc.framework;
|
package org.elasticsearch.xpack.sql.jdbc.framework;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.elasticsearch.common.logging.Loggers;
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.xpack.sql.util.CollectionUtils;
|
import org.elasticsearch.xpack.sql.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
@ -28,4 +32,84 @@ public abstract class JdbcTestUtils {
|
|||||||
Loggers.setLevel(Loggers.getLogger(entry.getKey()), entry.getValue());
|
Loggers.setLevel(Loggers.getLogger(entry.getKey()), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static void printResultSet(ResultSet set) throws Exception {
|
||||||
|
Logger logger = Loggers.getLogger("org.elasticsearch.xpack.sql.test");
|
||||||
|
Loggers.setLevel(logger, "INFO");
|
||||||
|
|
||||||
|
ResultSetMetaData metaData = set.getMetaData();
|
||||||
|
// header
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
int colSize = 15;
|
||||||
|
for (int column = 1; column <= metaData.getColumnCount(); column++) {
|
||||||
|
String colName = metaData.getColumnName(column);
|
||||||
|
|
||||||
|
int size = colName.length();
|
||||||
|
if (column > 1) {
|
||||||
|
sb.append("|");
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
sb.append(colName);
|
||||||
|
for (int i = size; i < colSize; i++) {
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int MAX_WIDTH = 20;
|
||||||
|
|
||||||
|
public static void resultSetToLogger(Logger log, ResultSet rs) throws SQLException {
|
||||||
|
ResultSetMetaData metaData = rs.getMetaData();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
StringBuilder column = new StringBuilder();
|
||||||
|
|
||||||
|
int columns = metaData.getColumnCount();
|
||||||
|
for (int i = 1; i <= columns; i++) {
|
||||||
|
if (i > 1) {
|
||||||
|
sb.append(" | ");
|
||||||
|
}
|
||||||
|
column.setLength(0);
|
||||||
|
column.append(metaData.getColumnName(i));
|
||||||
|
column.append("(");
|
||||||
|
column.append(metaData.getColumnTypeName(i));
|
||||||
|
column.append(")");
|
||||||
|
|
||||||
|
sb.append(trimOrPad(column));
|
||||||
|
}
|
||||||
|
|
||||||
|
int l = sb.length();
|
||||||
|
sb.append("\n");
|
||||||
|
for (int i = 0; i < l; i++) {
|
||||||
|
sb.append("=");
|
||||||
|
}
|
||||||
|
log.info(sb);
|
||||||
|
|
||||||
|
while (rs.next()) {
|
||||||
|
sb.setLength(0);
|
||||||
|
for (int i = 1; i <= columns; i++) {
|
||||||
|
column.setLength(0);
|
||||||
|
if (i > 1) {
|
||||||
|
sb.append(" | ");
|
||||||
|
}
|
||||||
|
sb.append(trimOrPad(column.append(rs.getString(i))));
|
||||||
|
}
|
||||||
|
log.info(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StringBuilder trimOrPad(StringBuilder buffer) {
|
||||||
|
if (buffer.length() > MAX_WIDTH) {
|
||||||
|
buffer.setLength(MAX_WIDTH - 1);
|
||||||
|
buffer.append("~");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = buffer.length(); i < MAX_WIDTH; i++) {
|
||||||
|
buffer.append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
67
sql/jdbc/src/test/resources/agg.csv-spec
Normal file
67
sql/jdbc/src/test/resources/agg.csv-spec
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// Aggs not supported by H2 / traditional SQL stores
|
||||||
|
//
|
||||||
|
|
||||||
|
singlePercentileWithoutComma
|
||||||
|
SELECT gender, PERCENTILE(emp_no, 97) p1 FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | p1
|
||||||
|
M | 10095.6112
|
||||||
|
F | 10099.1936
|
||||||
|
;
|
||||||
|
|
||||||
|
singlePercentileWithComma
|
||||||
|
SELECT gender, PERCENTILE(emp_no, 97.76) p1 FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | p1
|
||||||
|
M | 10095.6112
|
||||||
|
F | 10099.1936
|
||||||
|
;
|
||||||
|
|
||||||
|
multiplePercentilesOneWithCommaOneWithout
|
||||||
|
SELECT gender, PERCENTILE(emp_no, 92.45) p1, PERCENTILE(emp_no, 91) p2 FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | p1 | p2
|
||||||
|
M | 10090.319 | 10087.68
|
||||||
|
F | 10095.128 | 10093.52
|
||||||
|
;
|
||||||
|
|
||||||
|
multiplePercentilesWithoutComma
|
||||||
|
SELECT gender, PERCENTILE(emp_no, 91) p1, PERCENTILE(emp_no, 89) p2 FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | p1 | p2
|
||||||
|
M | 10087.68 | 10085.18
|
||||||
|
F | 10093.52 | 10092.08
|
||||||
|
;
|
||||||
|
|
||||||
|
multiplePercentilesWithComma
|
||||||
|
SELECT gender, PERCENTILE(emp_no, 85.7) p1, PERCENTILE(emp_no, 94.3) p2 FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | p1 | p2
|
||||||
|
M | 10083.134 | 10091.932
|
||||||
|
F | 10088.852 | 10097.792
|
||||||
|
;
|
||||||
|
|
||||||
|
percentileRank
|
||||||
|
SELECT gender, PERCENTILE_RANK(emp_no, 10025) rank FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | rank
|
||||||
|
M | 23.41269841269841
|
||||||
|
F | 26.351351351351347
|
||||||
|
;
|
||||||
|
|
||||||
|
multiplePercentileRanks
|
||||||
|
SELECT gender, PERCENTILE_RANK(emp_no, 10030.0) rank1, PERCENTILE_RANK(emp_no, 10025) rank2 FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | rank1 | rank2
|
||||||
|
M | 29.365079365079367 | 23.41269841269841
|
||||||
|
F | 29.93762993762994 | 26.351351351351347
|
||||||
|
;
|
||||||
|
|
||||||
|
multiplePercentilesAndPercentileRank
|
||||||
|
SELECT gender, PERCENTILE(emp_no, 97.76) p1, PERCENTILE(emp_no, 93.3) p2, PERCENTILE_RANK(emp_no, 10025) rank FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
|
gender | p1 | p2 | rank
|
||||||
|
M | 10095.6112 | 10090.846 | 23.41269841269841
|
||||||
|
F | 10099.1936 | 10096.351999999999 | 26.351351351351347
|
||||||
|
;
|
@ -3,51 +3,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
debug
|
debug
|
||||||
SHOW FUNCTIONS;
|
SELECT gender, PERCENTILE(emp_no, 97.76) p1, PERCENTILE(emp_no, 93.3) p2, PERCENTILE_RANK(emp_no, 10025) rank FROM test_emp GROUP BY gender;
|
||||||
|
|
||||||
name | type
|
gender | p1 | p2 | rank
|
||||||
AVG |AGGREGATE
|
M | 10095.6112 | 10090.846 | 23.41269841269841
|
||||||
COUNT |AGGREGATE
|
F | 10099.1936 | 10096.351999999999 | 26.351351351351347
|
||||||
MAX |AGGREGATE
|
|
||||||
MIN |AGGREGATE
|
|
||||||
SUM |AGGREGATE
|
|
||||||
DAY_OF_MONTH |SCALAR
|
|
||||||
DAY |SCALAR
|
|
||||||
DOM |SCALAR
|
|
||||||
DAY_OF_WEEK |SCALAR
|
|
||||||
DOW |SCALAR
|
|
||||||
DAY_OF_YEAR |SCALAR
|
|
||||||
DOY |SCALAR
|
|
||||||
HOUR_OF_DAY |SCALAR
|
|
||||||
HOUR |SCALAR
|
|
||||||
MINUTE_OF_DAY |SCALAR
|
|
||||||
MINUTE_OF_HOUR |SCALAR
|
|
||||||
MINUTE |SCALAR
|
|
||||||
SECOND_OF_MINUTE|SCALAR
|
|
||||||
SECOND |SCALAR
|
|
||||||
MONTH_OF_YEAR |SCALAR
|
|
||||||
MONTH |SCALAR
|
|
||||||
YEAR |SCALAR
|
|
||||||
ABS |SCALAR
|
|
||||||
ACOS |SCALAR
|
|
||||||
ASIN |SCALAR
|
|
||||||
ATAN |SCALAR
|
|
||||||
CBRT |SCALAR
|
|
||||||
CEIL |SCALAR
|
|
||||||
COS |SCALAR
|
|
||||||
COSH |SCALAR
|
|
||||||
DEGREES |SCALAR
|
|
||||||
E |SCALAR
|
|
||||||
EXP |SCALAR
|
|
||||||
EXPM1 |SCALAR
|
|
||||||
FLOOR |SCALAR
|
|
||||||
LOG |SCALAR
|
|
||||||
LOG10 |SCALAR
|
|
||||||
PI |SCALAR
|
|
||||||
RADIANS |SCALAR
|
|
||||||
ROUND |SCALAR
|
|
||||||
SIN |SCALAR
|
|
||||||
SINH |SCALAR
|
|
||||||
SQRT |SCALAR
|
|
||||||
TAN |SCALAR
|
|
||||||
;
|
;
|
@ -1,203 +1,203 @@
|
|||||||
T__0=1
|
T__0=1
|
||||||
T__1=2
|
T__1=2
|
||||||
T__2=3
|
T__2=3
|
||||||
T__3=4
|
T__3=4
|
||||||
SELECT=5
|
SELECT=5
|
||||||
FROM=6
|
FROM=6
|
||||||
AS=7
|
AS=7
|
||||||
ALL=8
|
ALL=8
|
||||||
WHEN=9
|
WHEN=9
|
||||||
THEN=10
|
THEN=10
|
||||||
ANY=11
|
ANY=11
|
||||||
DISTINCT=12
|
DISTINCT=12
|
||||||
WHERE=13
|
WHERE=13
|
||||||
GROUP=14
|
GROUP=14
|
||||||
BY=15
|
BY=15
|
||||||
GROUPING=16
|
GROUPING=16
|
||||||
SETS=17
|
SETS=17
|
||||||
ORDER=18
|
ORDER=18
|
||||||
HAVING=19
|
HAVING=19
|
||||||
LIMIT=20
|
LIMIT=20
|
||||||
OR=21
|
OR=21
|
||||||
AND=22
|
AND=22
|
||||||
IN=23
|
IN=23
|
||||||
NOT=24
|
NOT=24
|
||||||
NO=25
|
NO=25
|
||||||
EXISTS=26
|
EXISTS=26
|
||||||
BETWEEN=27
|
BETWEEN=27
|
||||||
LIKE=28
|
LIKE=28
|
||||||
RLIKE=29
|
RLIKE=29
|
||||||
IS=30
|
IS=30
|
||||||
NULL=31
|
NULL=31
|
||||||
TRUE=32
|
TRUE=32
|
||||||
FALSE=33
|
FALSE=33
|
||||||
LAST=34
|
LAST=34
|
||||||
ASC=35
|
ASC=35
|
||||||
DESC=36
|
DESC=36
|
||||||
FOR=37
|
FOR=37
|
||||||
INTEGER=38
|
INTEGER=38
|
||||||
JOIN=39
|
JOIN=39
|
||||||
CROSS=40
|
CROSS=40
|
||||||
OUTER=41
|
OUTER=41
|
||||||
INNER=42
|
INNER=42
|
||||||
LEFT=43
|
LEFT=43
|
||||||
RIGHT=44
|
RIGHT=44
|
||||||
FULL=45
|
FULL=45
|
||||||
NATURAL=46
|
NATURAL=46
|
||||||
USING=47
|
USING=47
|
||||||
ON=48
|
ON=48
|
||||||
WITH=49
|
WITH=49
|
||||||
TABLE=50
|
TABLE=50
|
||||||
INTO=51
|
INTO=51
|
||||||
DESCRIBE=52
|
DESCRIBE=52
|
||||||
OPTION=53
|
OPTION=53
|
||||||
EXPLAIN=54
|
EXPLAIN=54
|
||||||
ANALYZE=55
|
ANALYZE=55
|
||||||
FORMAT=56
|
FORMAT=56
|
||||||
TYPE=57
|
TYPE=57
|
||||||
TEXT=58
|
TEXT=58
|
||||||
VERIFY=59
|
VERIFY=59
|
||||||
GRAPHVIZ=60
|
GRAPHVIZ=60
|
||||||
LOGICAL=61
|
LOGICAL=61
|
||||||
PHYSICAL=62
|
PHYSICAL=62
|
||||||
SHOW=63
|
SHOW=63
|
||||||
TABLES=64
|
TABLES=64
|
||||||
COLUMNS=65
|
COLUMNS=65
|
||||||
COLUMN=66
|
COLUMN=66
|
||||||
FUNCTIONS=67
|
FUNCTIONS=67
|
||||||
TO=68
|
TO=68
|
||||||
DEBUG=69
|
DEBUG=69
|
||||||
PLAN=70
|
PLAN=70
|
||||||
PARSED=71
|
PARSED=71
|
||||||
ANALYZED=72
|
ANALYZED=72
|
||||||
OPTIMIZED=73
|
OPTIMIZED=73
|
||||||
MAPPED=74
|
MAPPED=74
|
||||||
EXECUTABLE=75
|
EXECUTABLE=75
|
||||||
USE=76
|
USE=76
|
||||||
SET=77
|
SET=77
|
||||||
RESET=78
|
RESET=78
|
||||||
SESSION=79
|
SESSION=79
|
||||||
SCHEMAS=80
|
SCHEMAS=80
|
||||||
EXTRACT=81
|
EXTRACT=81
|
||||||
QUERY=82
|
QUERY=82
|
||||||
MATCH=83
|
MATCH=83
|
||||||
CAST=84
|
CAST=84
|
||||||
EQ=85
|
EQ=85
|
||||||
NEQ=86
|
NEQ=86
|
||||||
LT=87
|
LT=87
|
||||||
LTE=88
|
LTE=88
|
||||||
GT=89
|
GT=89
|
||||||
GTE=90
|
GTE=90
|
||||||
PLUS=91
|
PLUS=91
|
||||||
MINUS=92
|
MINUS=92
|
||||||
ASTERISK=93
|
ASTERISK=93
|
||||||
SLASH=94
|
SLASH=94
|
||||||
PERCENT=95
|
PERCENT=95
|
||||||
CONCAT=96
|
CONCAT=96
|
||||||
STRING=97
|
STRING=97
|
||||||
INTEGER_VALUE=98
|
INTEGER_VALUE=98
|
||||||
DECIMAL_VALUE=99
|
DECIMAL_VALUE=99
|
||||||
IDENTIFIER=100
|
IDENTIFIER=100
|
||||||
DIGIT_IDENTIFIER=101
|
DIGIT_IDENTIFIER=101
|
||||||
QUOTED_IDENTIFIER=102
|
QUOTED_IDENTIFIER=102
|
||||||
BACKQUOTED_IDENTIFIER=103
|
BACKQUOTED_IDENTIFIER=103
|
||||||
SIMPLE_COMMENT=104
|
SIMPLE_COMMENT=104
|
||||||
BRACKETED_COMMENT=105
|
BRACKETED_COMMENT=105
|
||||||
WS=106
|
WS=106
|
||||||
UNRECOGNIZED=107
|
UNRECOGNIZED=107
|
||||||
DELIMITER=108
|
DELIMITER=108
|
||||||
'('=1
|
'('=1
|
||||||
')'=2
|
')'=2
|
||||||
','=3
|
','=3
|
||||||
'.'=4
|
'.'=4
|
||||||
'SELECT'=5
|
'SELECT'=5
|
||||||
'FROM'=6
|
'FROM'=6
|
||||||
'AS'=7
|
'AS'=7
|
||||||
'ALL'=8
|
'ALL'=8
|
||||||
'WHEN'=9
|
'WHEN'=9
|
||||||
'THEN'=10
|
'THEN'=10
|
||||||
'ANY'=11
|
'ANY'=11
|
||||||
'DISTINCT'=12
|
'DISTINCT'=12
|
||||||
'WHERE'=13
|
'WHERE'=13
|
||||||
'GROUP'=14
|
'GROUP'=14
|
||||||
'BY'=15
|
'BY'=15
|
||||||
'GROUPING'=16
|
'GROUPING'=16
|
||||||
'SETS'=17
|
'SETS'=17
|
||||||
'ORDER'=18
|
'ORDER'=18
|
||||||
'HAVING'=19
|
'HAVING'=19
|
||||||
'LIMIT'=20
|
'LIMIT'=20
|
||||||
'OR'=21
|
'OR'=21
|
||||||
'AND'=22
|
'AND'=22
|
||||||
'IN'=23
|
'IN'=23
|
||||||
'NOT'=24
|
'NOT'=24
|
||||||
'NO'=25
|
'NO'=25
|
||||||
'EXISTS'=26
|
'EXISTS'=26
|
||||||
'BETWEEN'=27
|
'BETWEEN'=27
|
||||||
'LIKE'=28
|
'LIKE'=28
|
||||||
'RLIKE'=29
|
'RLIKE'=29
|
||||||
'IS'=30
|
'IS'=30
|
||||||
'NULL'=31
|
'NULL'=31
|
||||||
'TRUE'=32
|
'TRUE'=32
|
||||||
'FALSE'=33
|
'FALSE'=33
|
||||||
'LAST'=34
|
'LAST'=34
|
||||||
'ASC'=35
|
'ASC'=35
|
||||||
'DESC'=36
|
'DESC'=36
|
||||||
'FOR'=37
|
'FOR'=37
|
||||||
'INTEGER'=38
|
'INTEGER'=38
|
||||||
'JOIN'=39
|
'JOIN'=39
|
||||||
'CROSS'=40
|
'CROSS'=40
|
||||||
'OUTER'=41
|
'OUTER'=41
|
||||||
'INNER'=42
|
'INNER'=42
|
||||||
'LEFT'=43
|
'LEFT'=43
|
||||||
'RIGHT'=44
|
'RIGHT'=44
|
||||||
'FULL'=45
|
'FULL'=45
|
||||||
'NATURAL'=46
|
'NATURAL'=46
|
||||||
'USING'=47
|
'USING'=47
|
||||||
'ON'=48
|
'ON'=48
|
||||||
'WITH'=49
|
'WITH'=49
|
||||||
'TABLE'=50
|
'TABLE'=50
|
||||||
'INTO'=51
|
'INTO'=51
|
||||||
'DESCRIBE'=52
|
'DESCRIBE'=52
|
||||||
'OPTION'=53
|
'OPTION'=53
|
||||||
'EXPLAIN'=54
|
'EXPLAIN'=54
|
||||||
'ANALYZE'=55
|
'ANALYZE'=55
|
||||||
'FORMAT'=56
|
'FORMAT'=56
|
||||||
'TYPE'=57
|
'TYPE'=57
|
||||||
'TEXT'=58
|
'TEXT'=58
|
||||||
'VERIFY'=59
|
'VERIFY'=59
|
||||||
'GRAPHVIZ'=60
|
'GRAPHVIZ'=60
|
||||||
'LOGICAL'=61
|
'LOGICAL'=61
|
||||||
'PHYSICAL'=62
|
'PHYSICAL'=62
|
||||||
'SHOW'=63
|
'SHOW'=63
|
||||||
'TABLES'=64
|
'TABLES'=64
|
||||||
'COLUMNS'=65
|
'COLUMNS'=65
|
||||||
'COLUMN'=66
|
'COLUMN'=66
|
||||||
'FUNCTIONS'=67
|
'FUNCTIONS'=67
|
||||||
'TO'=68
|
'TO'=68
|
||||||
'DEBUG'=69
|
'DEBUG'=69
|
||||||
'PLAN'=70
|
'PLAN'=70
|
||||||
'PARSED'=71
|
'PARSED'=71
|
||||||
'ANALYZED'=72
|
'ANALYZED'=72
|
||||||
'OPTIMIZED'=73
|
'OPTIMIZED'=73
|
||||||
'MAPPED'=74
|
'MAPPED'=74
|
||||||
'EXECUTABLE'=75
|
'EXECUTABLE'=75
|
||||||
'USE'=76
|
'USE'=76
|
||||||
'SET'=77
|
'SET'=77
|
||||||
'RESET'=78
|
'RESET'=78
|
||||||
'SESSION'=79
|
'SESSION'=79
|
||||||
'SCHEMAS'=80
|
'SCHEMAS'=80
|
||||||
'EXTRACT'=81
|
'EXTRACT'=81
|
||||||
'QUERY'=82
|
'QUERY'=82
|
||||||
'MATCH'=83
|
'MATCH'=83
|
||||||
'CAST'=84
|
'CAST'=84
|
||||||
'='=85
|
'='=85
|
||||||
'<'=87
|
'<'=87
|
||||||
'<='=88
|
'<='=88
|
||||||
'>'=89
|
'>'=89
|
||||||
'>='=90
|
'>='=90
|
||||||
'+'=91
|
'+'=91
|
||||||
'-'=92
|
'-'=92
|
||||||
'*'=93
|
'*'=93
|
||||||
'/'=94
|
'/'=94
|
||||||
'%'=95
|
'%'=95
|
||||||
'||'=96
|
'||'=96
|
||||||
|
@ -1,202 +1,202 @@
|
|||||||
T__0=1
|
T__0=1
|
||||||
T__1=2
|
T__1=2
|
||||||
T__2=3
|
T__2=3
|
||||||
T__3=4
|
T__3=4
|
||||||
SELECT=5
|
SELECT=5
|
||||||
FROM=6
|
FROM=6
|
||||||
AS=7
|
AS=7
|
||||||
ALL=8
|
ALL=8
|
||||||
WHEN=9
|
WHEN=9
|
||||||
THEN=10
|
THEN=10
|
||||||
ANY=11
|
ANY=11
|
||||||
DISTINCT=12
|
DISTINCT=12
|
||||||
WHERE=13
|
WHERE=13
|
||||||
GROUP=14
|
GROUP=14
|
||||||
BY=15
|
BY=15
|
||||||
GROUPING=16
|
GROUPING=16
|
||||||
SETS=17
|
SETS=17
|
||||||
ORDER=18
|
ORDER=18
|
||||||
HAVING=19
|
HAVING=19
|
||||||
LIMIT=20
|
LIMIT=20
|
||||||
OR=21
|
OR=21
|
||||||
AND=22
|
AND=22
|
||||||
IN=23
|
IN=23
|
||||||
NOT=24
|
NOT=24
|
||||||
NO=25
|
NO=25
|
||||||
EXISTS=26
|
EXISTS=26
|
||||||
BETWEEN=27
|
BETWEEN=27
|
||||||
LIKE=28
|
LIKE=28
|
||||||
RLIKE=29
|
RLIKE=29
|
||||||
IS=30
|
IS=30
|
||||||
NULL=31
|
NULL=31
|
||||||
TRUE=32
|
TRUE=32
|
||||||
FALSE=33
|
FALSE=33
|
||||||
LAST=34
|
LAST=34
|
||||||
ASC=35
|
ASC=35
|
||||||
DESC=36
|
DESC=36
|
||||||
FOR=37
|
FOR=37
|
||||||
INTEGER=38
|
INTEGER=38
|
||||||
JOIN=39
|
JOIN=39
|
||||||
CROSS=40
|
CROSS=40
|
||||||
OUTER=41
|
OUTER=41
|
||||||
INNER=42
|
INNER=42
|
||||||
LEFT=43
|
LEFT=43
|
||||||
RIGHT=44
|
RIGHT=44
|
||||||
FULL=45
|
FULL=45
|
||||||
NATURAL=46
|
NATURAL=46
|
||||||
USING=47
|
USING=47
|
||||||
ON=48
|
ON=48
|
||||||
WITH=49
|
WITH=49
|
||||||
TABLE=50
|
TABLE=50
|
||||||
INTO=51
|
INTO=51
|
||||||
DESCRIBE=52
|
DESCRIBE=52
|
||||||
OPTION=53
|
OPTION=53
|
||||||
EXPLAIN=54
|
EXPLAIN=54
|
||||||
ANALYZE=55
|
ANALYZE=55
|
||||||
FORMAT=56
|
FORMAT=56
|
||||||
TYPE=57
|
TYPE=57
|
||||||
TEXT=58
|
TEXT=58
|
||||||
VERIFY=59
|
VERIFY=59
|
||||||
GRAPHVIZ=60
|
GRAPHVIZ=60
|
||||||
LOGICAL=61
|
LOGICAL=61
|
||||||
PHYSICAL=62
|
PHYSICAL=62
|
||||||
SHOW=63
|
SHOW=63
|
||||||
TABLES=64
|
TABLES=64
|
||||||
COLUMNS=65
|
COLUMNS=65
|
||||||
COLUMN=66
|
COLUMN=66
|
||||||
FUNCTIONS=67
|
FUNCTIONS=67
|
||||||
TO=68
|
TO=68
|
||||||
DEBUG=69
|
DEBUG=69
|
||||||
PLAN=70
|
PLAN=70
|
||||||
PARSED=71
|
PARSED=71
|
||||||
ANALYZED=72
|
ANALYZED=72
|
||||||
OPTIMIZED=73
|
OPTIMIZED=73
|
||||||
MAPPED=74
|
MAPPED=74
|
||||||
EXECUTABLE=75
|
EXECUTABLE=75
|
||||||
USE=76
|
USE=76
|
||||||
SET=77
|
SET=77
|
||||||
RESET=78
|
RESET=78
|
||||||
SESSION=79
|
SESSION=79
|
||||||
SCHEMAS=80
|
SCHEMAS=80
|
||||||
EXTRACT=81
|
EXTRACT=81
|
||||||
QUERY=82
|
QUERY=82
|
||||||
MATCH=83
|
MATCH=83
|
||||||
CAST=84
|
CAST=84
|
||||||
EQ=85
|
EQ=85
|
||||||
NEQ=86
|
NEQ=86
|
||||||
LT=87
|
LT=87
|
||||||
LTE=88
|
LTE=88
|
||||||
GT=89
|
GT=89
|
||||||
GTE=90
|
GTE=90
|
||||||
PLUS=91
|
PLUS=91
|
||||||
MINUS=92
|
MINUS=92
|
||||||
ASTERISK=93
|
ASTERISK=93
|
||||||
SLASH=94
|
SLASH=94
|
||||||
PERCENT=95
|
PERCENT=95
|
||||||
CONCAT=96
|
CONCAT=96
|
||||||
STRING=97
|
STRING=97
|
||||||
INTEGER_VALUE=98
|
INTEGER_VALUE=98
|
||||||
DECIMAL_VALUE=99
|
DECIMAL_VALUE=99
|
||||||
IDENTIFIER=100
|
IDENTIFIER=100
|
||||||
DIGIT_IDENTIFIER=101
|
DIGIT_IDENTIFIER=101
|
||||||
QUOTED_IDENTIFIER=102
|
QUOTED_IDENTIFIER=102
|
||||||
BACKQUOTED_IDENTIFIER=103
|
BACKQUOTED_IDENTIFIER=103
|
||||||
SIMPLE_COMMENT=104
|
SIMPLE_COMMENT=104
|
||||||
BRACKETED_COMMENT=105
|
BRACKETED_COMMENT=105
|
||||||
WS=106
|
WS=106
|
||||||
UNRECOGNIZED=107
|
UNRECOGNIZED=107
|
||||||
'('=1
|
'('=1
|
||||||
')'=2
|
')'=2
|
||||||
','=3
|
','=3
|
||||||
'.'=4
|
'.'=4
|
||||||
'SELECT'=5
|
'SELECT'=5
|
||||||
'FROM'=6
|
'FROM'=6
|
||||||
'AS'=7
|
'AS'=7
|
||||||
'ALL'=8
|
'ALL'=8
|
||||||
'WHEN'=9
|
'WHEN'=9
|
||||||
'THEN'=10
|
'THEN'=10
|
||||||
'ANY'=11
|
'ANY'=11
|
||||||
'DISTINCT'=12
|
'DISTINCT'=12
|
||||||
'WHERE'=13
|
'WHERE'=13
|
||||||
'GROUP'=14
|
'GROUP'=14
|
||||||
'BY'=15
|
'BY'=15
|
||||||
'GROUPING'=16
|
'GROUPING'=16
|
||||||
'SETS'=17
|
'SETS'=17
|
||||||
'ORDER'=18
|
'ORDER'=18
|
||||||
'HAVING'=19
|
'HAVING'=19
|
||||||
'LIMIT'=20
|
'LIMIT'=20
|
||||||
'OR'=21
|
'OR'=21
|
||||||
'AND'=22
|
'AND'=22
|
||||||
'IN'=23
|
'IN'=23
|
||||||
'NOT'=24
|
'NOT'=24
|
||||||
'NO'=25
|
'NO'=25
|
||||||
'EXISTS'=26
|
'EXISTS'=26
|
||||||
'BETWEEN'=27
|
'BETWEEN'=27
|
||||||
'LIKE'=28
|
'LIKE'=28
|
||||||
'RLIKE'=29
|
'RLIKE'=29
|
||||||
'IS'=30
|
'IS'=30
|
||||||
'NULL'=31
|
'NULL'=31
|
||||||
'TRUE'=32
|
'TRUE'=32
|
||||||
'FALSE'=33
|
'FALSE'=33
|
||||||
'LAST'=34
|
'LAST'=34
|
||||||
'ASC'=35
|
'ASC'=35
|
||||||
'DESC'=36
|
'DESC'=36
|
||||||
'FOR'=37
|
'FOR'=37
|
||||||
'INTEGER'=38
|
'INTEGER'=38
|
||||||
'JOIN'=39
|
'JOIN'=39
|
||||||
'CROSS'=40
|
'CROSS'=40
|
||||||
'OUTER'=41
|
'OUTER'=41
|
||||||
'INNER'=42
|
'INNER'=42
|
||||||
'LEFT'=43
|
'LEFT'=43
|
||||||
'RIGHT'=44
|
'RIGHT'=44
|
||||||
'FULL'=45
|
'FULL'=45
|
||||||
'NATURAL'=46
|
'NATURAL'=46
|
||||||
'USING'=47
|
'USING'=47
|
||||||
'ON'=48
|
'ON'=48
|
||||||
'WITH'=49
|
'WITH'=49
|
||||||
'TABLE'=50
|
'TABLE'=50
|
||||||
'INTO'=51
|
'INTO'=51
|
||||||
'DESCRIBE'=52
|
'DESCRIBE'=52
|
||||||
'OPTION'=53
|
'OPTION'=53
|
||||||
'EXPLAIN'=54
|
'EXPLAIN'=54
|
||||||
'ANALYZE'=55
|
'ANALYZE'=55
|
||||||
'FORMAT'=56
|
'FORMAT'=56
|
||||||
'TYPE'=57
|
'TYPE'=57
|
||||||
'TEXT'=58
|
'TEXT'=58
|
||||||
'VERIFY'=59
|
'VERIFY'=59
|
||||||
'GRAPHVIZ'=60
|
'GRAPHVIZ'=60
|
||||||
'LOGICAL'=61
|
'LOGICAL'=61
|
||||||
'PHYSICAL'=62
|
'PHYSICAL'=62
|
||||||
'SHOW'=63
|
'SHOW'=63
|
||||||
'TABLES'=64
|
'TABLES'=64
|
||||||
'COLUMNS'=65
|
'COLUMNS'=65
|
||||||
'COLUMN'=66
|
'COLUMN'=66
|
||||||
'FUNCTIONS'=67
|
'FUNCTIONS'=67
|
||||||
'TO'=68
|
'TO'=68
|
||||||
'DEBUG'=69
|
'DEBUG'=69
|
||||||
'PLAN'=70
|
'PLAN'=70
|
||||||
'PARSED'=71
|
'PARSED'=71
|
||||||
'ANALYZED'=72
|
'ANALYZED'=72
|
||||||
'OPTIMIZED'=73
|
'OPTIMIZED'=73
|
||||||
'MAPPED'=74
|
'MAPPED'=74
|
||||||
'EXECUTABLE'=75
|
'EXECUTABLE'=75
|
||||||
'USE'=76
|
'USE'=76
|
||||||
'SET'=77
|
'SET'=77
|
||||||
'RESET'=78
|
'RESET'=78
|
||||||
'SESSION'=79
|
'SESSION'=79
|
||||||
'SCHEMAS'=80
|
'SCHEMAS'=80
|
||||||
'EXTRACT'=81
|
'EXTRACT'=81
|
||||||
'QUERY'=82
|
'QUERY'=82
|
||||||
'MATCH'=83
|
'MATCH'=83
|
||||||
'CAST'=84
|
'CAST'=84
|
||||||
'='=85
|
'='=85
|
||||||
'<'=87
|
'<'=87
|
||||||
'<='=88
|
'<='=88
|
||||||
'>'=89
|
'>'=89
|
||||||
'>='=90
|
'>='=90
|
||||||
'+'=91
|
'+'=91
|
||||||
'-'=92
|
'-'=92
|
||||||
'*'=93
|
'*'=93
|
||||||
'/'=94
|
'/'=94
|
||||||
'%'=95
|
'%'=95
|
||||||
'||'=96
|
'||'=96
|
||||||
|
@ -823,7 +823,7 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
|||||||
if (f instanceof Count) {
|
if (f instanceof Count) {
|
||||||
Count c = (Count) f;
|
Count c = (Count) f;
|
||||||
if (!c.distinct()) {
|
if (!c.distinct()) {
|
||||||
if (c.argument() instanceof Literal && c.argument().dataType().isInteger()) {
|
if (c.field() instanceof Literal && c.field().dataType().isInteger()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.expression;
|
package org.elasticsearch.xpack.sql.expression;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.elasticsearch.xpack.sql.capabilities.Resolvable;
|
import org.elasticsearch.xpack.sql.capabilities.Resolvable;
|
||||||
import org.elasticsearch.xpack.sql.capabilities.Resolvables;
|
import org.elasticsearch.xpack.sql.capabilities.Resolvables;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
@ -16,6 +13,9 @@ import org.elasticsearch.xpack.sql.tree.NodeUtils;
|
|||||||
import org.elasticsearch.xpack.sql.type.DataType;
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
|
|
||||||
public abstract class Expression extends Node<Expression> implements Resolvable {
|
public abstract class Expression extends Node<Expression> implements Resolvable {
|
||||||
@ -78,7 +78,7 @@ public abstract class Expression extends Node<Expression> implements Resolvable
|
|||||||
return lazyChildrenResolved;
|
return lazyChildrenResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeResolution typeResolved() {
|
public final TypeResolution typeResolved() {
|
||||||
if (lazyTypeResolution == null) {
|
if (lazyTypeResolution == null) {
|
||||||
lazyTypeResolution = resolveType();
|
lazyTypeResolution = resolveType();
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,15 @@ public abstract class Expressions {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean nullable(List<? extends Expression> exps) {
|
||||||
|
for (Expression exp : exps) {
|
||||||
|
if (!exp.nullable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static AttributeSet references(List<? extends Expression> exps) {
|
public static AttributeSet references(List<? extends Expression> exps) {
|
||||||
if (exps.isEmpty()) {
|
if (exps.isEmpty()) {
|
||||||
return AttributeSet.EMPTY;
|
return AttributeSet.EMPTY;
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.expression;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataTypeConvertion;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class Foldables {
|
||||||
|
|
||||||
|
public static <T> T valueOf(Expression e, DataType to) {
|
||||||
|
if (e.foldable()) {
|
||||||
|
return DataTypeConvertion.convert(e.fold(), e.dataType(), to);
|
||||||
|
}
|
||||||
|
throw new SqlIllegalArgumentException("Cannot determine value for %s", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object valueOf(Expression e) {
|
||||||
|
if (e.foldable()) {
|
||||||
|
return e.fold();
|
||||||
|
}
|
||||||
|
throw new SqlIllegalArgumentException("Cannot determine value for %s", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String stringValueOf(Expression e) {
|
||||||
|
return valueOf(e, DataTypes.KEYWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer intValueOf(Expression e) {
|
||||||
|
return valueOf(e, DataTypes.INTEGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long longValueOf(Expression e) {
|
||||||
|
return valueOf(e, DataTypes.LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double doubleValueOf(Expression e) {
|
||||||
|
return valueOf(e, DataTypes.DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> valuesOf(List<Expression> list, DataType to) {
|
||||||
|
List<T> l = new ArrayList<>();
|
||||||
|
for (Expression e : list) {
|
||||||
|
if (e.foldable()) {
|
||||||
|
l.add(DataTypeConvertion.convert(e.fold(), e.dataType(), to));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new SqlIllegalArgumentException("Cannot determine value for %s", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Double> doubleValuesOf(List<Expression> list) {
|
||||||
|
return valuesOf(list, DataTypes.DOUBLE);
|
||||||
|
}
|
||||||
|
}
|
@ -18,9 +18,4 @@ public abstract class LeafExpression extends Expression {
|
|||||||
public AttributeSet references() {
|
public AttributeSet references() {
|
||||||
return AttributeSet.EMPTY;
|
return AttributeSet.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.expression;
|
package org.elasticsearch.xpack.sql.expression;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
import org.elasticsearch.xpack.sql.type.DataType;
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
import org.elasticsearch.xpack.sql.type.DataTypes;
|
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||||
|
|
||||||
public class Literal extends Expression {
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Literal extends LeafExpression {
|
||||||
|
|
||||||
private final Object value;
|
private final Object value;
|
||||||
private final DataType dataType;
|
private final DataType dataType;
|
||||||
@ -21,7 +20,7 @@ public class Literal extends Expression {
|
|||||||
public static final Literal FALSE = Literal.of(Location.EMPTY, Boolean.FALSE);
|
public static final Literal FALSE = Literal.of(Location.EMPTY, Boolean.FALSE);
|
||||||
|
|
||||||
public Literal(Location location, Object value, DataType dataType) {
|
public Literal(Location location, Object value, DataType dataType) {
|
||||||
super(location, Collections.emptyList());
|
super(location);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.dataType = dataType;
|
this.dataType = dataType;
|
||||||
}
|
}
|
||||||
|
@ -7,22 +7,18 @@ package org.elasticsearch.xpack.sql.expression.function;
|
|||||||
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aware.DistinctAware;
|
import org.elasticsearch.xpack.sql.expression.function.aware.DistinctAware;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aware.TimeZoneAware;
|
import org.elasticsearch.xpack.sql.expression.function.aware.TimeZoneAware;
|
||||||
import org.elasticsearch.xpack.sql.parser.ParsingException;
|
import org.elasticsearch.xpack.sql.parser.ParsingException;
|
||||||
import org.elasticsearch.xpack.sql.session.SqlSettings;
|
import org.elasticsearch.xpack.sql.session.SqlSettings;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
|
||||||
import org.elasticsearch.xpack.sql.tree.Node;
|
import org.elasticsearch.xpack.sql.tree.Node;
|
||||||
import org.elasticsearch.xpack.sql.tree.NodeUtils;
|
import org.elasticsearch.xpack.sql.tree.NodeUtils;
|
||||||
import org.elasticsearch.xpack.sql.tree.NodeUtils.NodeInfo;
|
import org.elasticsearch.xpack.sql.tree.NodeUtils.NodeInfo;
|
||||||
import org.elasticsearch.xpack.sql.util.Assert;
|
import org.elasticsearch.xpack.sql.util.Assert;
|
||||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -98,46 +94,61 @@ abstract class AbstractFunctionRegistry implements FunctionRegistry {
|
|||||||
return StringUtils.camelCaseToUnderscore(name);
|
return StringUtils.camelCaseToUnderscore(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Instantiates a function through reflection.
|
||||||
|
// Picks up the constructor by expecting to be of type (Location,Expression) or (Location,List<Expression>) depending on the size of given children, parameters.
|
||||||
|
// If the function has certain 'aware'-ness (based on the interface implemented), the appropriate types are added to the signature
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static Function createInstance(Class<? extends Function> clazz, UnresolvedFunction ur, SqlSettings settings) {
|
private static Function createInstance(Class<? extends Function> clazz, UnresolvedFunction ur, SqlSettings settings) {
|
||||||
NodeInfo info = NodeUtils.info((Class<? extends Node>) clazz);
|
NodeInfo info = NodeUtils.info((Class<? extends Node>) clazz);
|
||||||
Class<?> exp = ur.children().size() == 1 ? Expression.class : List.class;
|
Class<?>[] pTypes = info.ctr.getParameterTypes();
|
||||||
Object expVal = exp == Expression.class ? ur.children().get(0) : ur.children();
|
|
||||||
|
|
||||||
boolean noExpression = false;
|
|
||||||
boolean distinctAware = DistinctAware.class.isAssignableFrom(clazz);
|
boolean distinctAware = DistinctAware.class.isAssignableFrom(clazz);
|
||||||
boolean timezoneAware = TimeZoneAware.class.isAssignableFrom(clazz);
|
boolean timezoneAware = TimeZoneAware.class.isAssignableFrom(clazz);
|
||||||
|
|
||||||
|
// constructor types - location - distinct? - timezone?
|
||||||
|
int expectedParamCount = pTypes.length - (1 + (distinctAware ? 1 : 0) + (timezoneAware ? 1 : 0));
|
||||||
|
|
||||||
// check constructor signature
|
// check constructor signature
|
||||||
|
if (ur.children().size() != expectedParamCount) {
|
||||||
|
List<String> expected = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 1; i < expectedParamCount; i++) {
|
||||||
|
expected.add(pTypes[i].getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ParsingException(ur.location(), "Invalid number of arguments given to function [%s], expected %d argument(s):%s but received %d:%s",
|
||||||
|
ur.name(), expected.size(), expected.toString(), ur.children().size(), ur.children());
|
||||||
|
}
|
||||||
|
|
||||||
// validate distinct ctor
|
// validate distinct ctor
|
||||||
if (!distinctAware && ur.distinct()) {
|
if (!distinctAware && ur.distinct()) {
|
||||||
throw new ParsingException(ur.location(), "Function [%s] does not support DISTINCT yet it was specified", ur.name());
|
throw new ParsingException(ur.location(), "Function [%s] does not support DISTINCT yet it was specified", ur.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Class> ctorSignature = new ArrayList<>();
|
|
||||||
ctorSignature.add(Location.class);
|
|
||||||
|
|
||||||
// might be a constant function
|
|
||||||
if (expVal instanceof List && ((List) expVal).isEmpty()) {
|
|
||||||
noExpression = Arrays.equals(new Class[] { Location.class }, info.ctr.getParameterTypes());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctorSignature.add(exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// aware stuff
|
// List<Class> ctorSignature = new ArrayList<>();
|
||||||
if (distinctAware) {
|
// ctorSignature.add(Location.class);
|
||||||
ctorSignature.add(boolean.class);
|
//
|
||||||
}
|
// // might be a constant function
|
||||||
if (timezoneAware) {
|
// if (expVal instanceof List && ((List) expVal).isEmpty()) {
|
||||||
ctorSignature.add(DateTimeZone.class);
|
// noExpression = Arrays.equals(new Class[] { Location.class }, info.ctr.getParameterTypes());
|
||||||
}
|
// }
|
||||||
|
// else {
|
||||||
// validate
|
// ctorSignature.add(exp);
|
||||||
Assert.isTrue(Arrays.equals(ctorSignature.toArray(new Class[ctorSignature.size()]), info.ctr.getParameterTypes()),
|
// }
|
||||||
"No constructor with signature %s found for [%s]", ctorSignature, clazz.getTypeName());
|
//
|
||||||
|
// // aware stuff
|
||||||
|
// if (distinctAware) {
|
||||||
|
// ctorSignature.add(boolean.class);
|
||||||
|
// }
|
||||||
|
// if (timezoneAware) {
|
||||||
|
// ctorSignature.add(DateTimeZone.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // validate
|
||||||
|
// Assert.isTrue(Arrays.equals(ctorSignature.toArray(new Class[ctorSignature.size()]), info.ctr.getParameterTypes()),
|
||||||
|
// "No constructor with signature %s found for [%s], found %s instead", ctorSignature, clazz.getTypeName(), info.ctr);
|
||||||
|
|
||||||
// now add the actual values
|
// now add the actual values
|
||||||
try {
|
try {
|
||||||
@ -147,15 +158,15 @@ abstract class AbstractFunctionRegistry implements FunctionRegistry {
|
|||||||
args.add(ur.location());
|
args.add(ur.location());
|
||||||
|
|
||||||
// has multiple arguments
|
// has multiple arguments
|
||||||
if (!noExpression) {
|
args.addAll(ur.children());
|
||||||
args.add(expVal);
|
|
||||||
if (distinctAware) {
|
if (distinctAware) {
|
||||||
args.add(ur.distinct());
|
args.add(ur.distinct());
|
||||||
}
|
}
|
||||||
if (timezoneAware) {
|
if (timezoneAware) {
|
||||||
args.add(settings.timeZone());
|
args.add(settings.timeZone());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return (Function) info.ctr.newInstance(args.toArray());
|
return (Function) info.ctr.newInstance(args.toArray());
|
||||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||||
throw new SqlIllegalArgumentException(ex, "Cannot create instance of function %s", ur.name());
|
throw new SqlIllegalArgumentException(ex, "Cannot create instance of function %s", ur.name());
|
||||||
|
@ -13,6 +13,8 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.Kurtosis;
|
|||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Max;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Max;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Mean;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Mean;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Min;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Min;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Percentile;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.PercentileRank;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Skewness;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Skewness;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.StddevPop;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.StddevPop;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum;
|
||||||
@ -92,8 +94,11 @@ public class DefaultFunctionRegistry extends AbstractFunctionRegistry {
|
|||||||
VarPop.class,
|
VarPop.class,
|
||||||
SumOfSquares.class,
|
SumOfSquares.class,
|
||||||
Skewness.class,
|
Skewness.class,
|
||||||
Kurtosis.class
|
Kurtosis.class,
|
||||||
// TODO: add multi arg functions like Covariance, Correlate, Percentiles and percentiles rank
|
Percentile.class,
|
||||||
|
PercentileRank.class
|
||||||
|
// TODO: add multi arg functions like Covariance, Correlate
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,20 +8,34 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.Function;
|
import org.elasticsearch.xpack.sql.expression.function.Function;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
import org.elasticsearch.xpack.sql.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
public abstract class AggregateFunction extends Function {
|
public abstract class AggregateFunction extends Function {
|
||||||
|
|
||||||
private final Expression argument;
|
private final Expression field;
|
||||||
|
private final List<Expression> arguments;
|
||||||
|
|
||||||
AggregateFunction(Location location, Expression child) {
|
AggregateFunction(Location location, Expression field) {
|
||||||
super(location, singletonList(child));
|
this(location, field, emptyList());
|
||||||
this.argument = child;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Expression argument() {
|
AggregateFunction(Location location, Expression field, List<Expression> arguments) {
|
||||||
return argument;
|
super(location, CollectionUtils.combine(singletonList(field), arguments));
|
||||||
|
this.field = field;
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression field() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Expression> arguments() {
|
||||||
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String functionId() {
|
public String functionId() {
|
||||||
|
@ -8,11 +8,17 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
// marker type for compound aggregates, that is aggregate that provide multiple values (like Stats or Matrix)
|
// marker type for compound aggregates, that is aggregate that provide multiple values (like Stats or Matrix)
|
||||||
// and thus cannot be used directly in SQL and are mainly for internal use
|
// and thus cannot be used directly in SQL and are mainly for internal use
|
||||||
public abstract class CompoundAggregate extends NumericAggregate {
|
public abstract class CompoundNumericAggregate extends NumericAggregate {
|
||||||
|
|
||||||
public CompoundAggregate(Location location, Expression argument) {
|
CompoundNumericAggregate(Location location, Expression field, List<Expression> arguments) {
|
||||||
super(location, argument);
|
super(location, field, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundNumericAggregate(Location location, Expression field) {
|
||||||
|
super(location, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,12 +12,12 @@ import org.elasticsearch.xpack.sql.tree.Location;
|
|||||||
import org.elasticsearch.xpack.sql.type.DataType;
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
import org.elasticsearch.xpack.sql.type.DataTypes;
|
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||||
|
|
||||||
public class Count extends AggregateFunction implements DistinctAware {
|
public class Count extends NumericAggregate implements DistinctAware {
|
||||||
|
|
||||||
private final boolean distinct;
|
private final boolean distinct;
|
||||||
|
|
||||||
public Count(Location location, Expression argument, boolean distinct) {
|
public Count(Location location, Expression field, boolean distinct) {
|
||||||
super(location, argument);
|
super(location, field);
|
||||||
this.distinct = distinct;
|
this.distinct = distinct;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,13 +30,12 @@ public class Count extends AggregateFunction implements DistinctAware {
|
|||||||
return DataTypes.LONG;
|
return DataTypes.LONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String functionId() {
|
public String functionId() {
|
||||||
String functionId = id().toString();
|
String functionId = id().toString();
|
||||||
// if count works against a given expression, use its id (to identify the group)
|
// if count works against a given expression, use its id (to identify the group)
|
||||||
if (argument() instanceof NamedExpression) {
|
if (field() instanceof NamedExpression) {
|
||||||
functionId = ((NamedExpression) argument()).id().toString();
|
functionId = ((NamedExpression) field()).id().toString();
|
||||||
}
|
}
|
||||||
return functionId;
|
return functionId;
|
||||||
}
|
}
|
||||||
@ -45,4 +44,4 @@ public class Count extends AggregateFunction implements DistinctAware {
|
|||||||
public AggregateFunctionAttribute toAttribute() {
|
public AggregateFunctionAttribute toAttribute() {
|
||||||
return new AggregateFunctionAttribute(location(), name(), dataType(), id(), functionId(), "_count");
|
return new AggregateFunctionAttribute(location(), name(), dataType(), id(), functionId(), "_count");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
||||||
|
|
||||||
|
// Agg 'enclosed' by another agg. Used for agg that return multiple embedded aggs (like MatrixStats)
|
||||||
public interface EnclosedAgg {
|
public interface EnclosedAgg {
|
||||||
|
|
||||||
String innerName();
|
String innerName();
|
||||||
|
@ -8,9 +8,9 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
public class ExtendedStats extends CompoundAggregate {
|
public class ExtendedStats extends CompoundNumericAggregate {
|
||||||
|
|
||||||
public ExtendedStats(Location location, Expression argument) {
|
public ExtendedStats(Location location, Expression field) {
|
||||||
super(location, argument);
|
super(location, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,17 @@ import org.elasticsearch.xpack.sql.type.DataType;
|
|||||||
public class InnerAggregate extends AggregateFunction {
|
public class InnerAggregate extends AggregateFunction {
|
||||||
|
|
||||||
private final AggregateFunction inner;
|
private final AggregateFunction inner;
|
||||||
private final CompoundAggregate outer;
|
private final CompoundNumericAggregate outer;
|
||||||
private final String innerId;
|
private final String innerId;
|
||||||
// used when the result needs to be extracted from a map (like in MatrixAggs)
|
// used when the result needs to be extracted from a map (like in MatrixAggs or Percentiles)
|
||||||
private final Expression innerKey;
|
private final Expression innerKey;
|
||||||
|
|
||||||
public InnerAggregate(AggregateFunction inner, CompoundAggregate outer) {
|
public InnerAggregate(AggregateFunction inner, CompoundNumericAggregate outer) {
|
||||||
this(inner, outer, null);
|
this(inner, outer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InnerAggregate(AggregateFunction inner, CompoundAggregate outer, Expression innerKey) {
|
public InnerAggregate(AggregateFunction inner, CompoundNumericAggregate outer, Expression innerKey) {
|
||||||
super(inner.location(), outer.argument());
|
super(inner.location(), outer.field(), outer.arguments());
|
||||||
this.inner = inner;
|
this.inner = inner;
|
||||||
this.outer = outer;
|
this.outer = outer;
|
||||||
this.innerId = ((EnclosedAgg) inner).innerName();
|
this.innerId = ((EnclosedAgg) inner).innerName();
|
||||||
@ -34,7 +34,7 @@ public class InnerAggregate extends AggregateFunction {
|
|||||||
return inner;
|
return inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundAggregate outer() {
|
public CompoundNumericAggregate outer() {
|
||||||
return outer;
|
return outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
public class MatrixStats extends CompoundAggregate {
|
public class MatrixStats extends CompoundNumericAggregate {
|
||||||
|
|
||||||
public MatrixStats(Location location, Expression argument) {
|
public MatrixStats(Location location, Expression field) {
|
||||||
super(location, argument);
|
super(location, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ public class Max extends NumericAggregate implements EnclosedAgg {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType dataType() {
|
public DataType dataType() {
|
||||||
return argument().dataType();
|
return field().dataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -17,7 +17,7 @@ public class Min extends NumericAggregate implements EnclosedAgg {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType dataType() {
|
public DataType dataType() {
|
||||||
return argument().dataType();
|
return field().dataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -11,17 +11,24 @@ import org.elasticsearch.xpack.sql.tree.Location;
|
|||||||
import org.elasticsearch.xpack.sql.type.DataType;
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
import org.elasticsearch.xpack.sql.type.DataTypes;
|
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||||
|
|
||||||
abstract class NumericAggregate extends AggregateFunction {
|
import java.util.List;
|
||||||
|
|
||||||
NumericAggregate(Location location, Expression argument) {
|
class NumericAggregate extends AggregateFunction {
|
||||||
super(location, argument);
|
|
||||||
|
NumericAggregate(Location location, Expression field, List<Expression> arguments) {
|
||||||
|
super(location, field, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumericAggregate(Location location, Expression field) {
|
||||||
|
super(location, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TypeResolution resolveType() {
|
protected TypeResolution resolveType() {
|
||||||
return argument().dataType().isNumeric() ?
|
return field().dataType().isNumeric() ? TypeResolution.TYPE_RESOLVED : new TypeResolution(
|
||||||
TypeResolution.TYPE_RESOLVED :
|
"Function '%s' cannot be applied on a non-numeric expression ('%s' of type '%s')", functionName(),
|
||||||
new TypeResolution("Function '%s' cannot be applied on a non-numeric expression ('%s' of type '%s')", functionName(), Expressions.name(argument()), argument().dataType().esName());
|
Expressions.name(field()), field().dataType().esName());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|
||||||
|
|
||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
|
||||||
import org.elasticsearch.xpack.sql.expression.Expressions;
|
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
|
||||||
import org.elasticsearch.xpack.sql.type.DataType;
|
|
||||||
|
|
||||||
abstract class NumericAggregateFunction extends AggregateFunction {
|
|
||||||
|
|
||||||
NumericAggregateFunction(Location location, Expression argument) {
|
|
||||||
super(location, argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TypeResolution resolveType() {
|
|
||||||
return argument().dataType().isNumeric() ?
|
|
||||||
TypeResolution.TYPE_RESOLVED :
|
|
||||||
new TypeResolution("Function '%s' cannot be applied on a non-numeric expression ('%s' of type '%s')", functionName(), Expressions.name(argument()), argument().dataType().esName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataType dataType() {
|
|
||||||
return argument().dataType();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
|
public class Percentile extends AggregateFunction implements EnclosedAgg {
|
||||||
|
|
||||||
|
private final Expression percent;
|
||||||
|
|
||||||
|
public Percentile(Location location, Expression field, Expression percent) {
|
||||||
|
super(location, field, singletonList(percent));
|
||||||
|
this.percent = percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TypeResolution resolveType() {
|
||||||
|
TypeResolution resolution = field().dataType().isNumeric() ? TypeResolution.TYPE_RESOLVED :
|
||||||
|
new TypeResolution("Function '%s' cannot be applied on a non-numeric expression ('%s' of type '%s')",
|
||||||
|
functionName(), Expressions.name(field()), field().dataType().esName());
|
||||||
|
|
||||||
|
if (TypeResolution.TYPE_RESOLVED.equals(resolution)) {
|
||||||
|
resolution = percent().dataType().isNumeric() ? TypeResolution.TYPE_RESOLVED :
|
||||||
|
new TypeResolution("Percentile#percent argument cannot be non-numeric (type is'%s')", percent().dataType().esName());
|
||||||
|
}
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression percent() {
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType dataType() {
|
||||||
|
return DataTypes.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String innerName() {
|
||||||
|
return "[" + Double.toString(Foldables.doubleValueOf(percent)) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Percentile other = (Percentile) obj;
|
||||||
|
return Objects.equals(field(), other.field())
|
||||||
|
&& Objects.equals(percent, other.percent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
|
public class PercentileRank extends AggregateFunction implements EnclosedAgg {
|
||||||
|
|
||||||
|
private final Expression value;
|
||||||
|
|
||||||
|
public PercentileRank(Location location, Expression field, Expression value) {
|
||||||
|
super(location, field, singletonList(value));
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TypeResolution resolveType() {
|
||||||
|
TypeResolution resolution = field().dataType().isNumeric() ? TypeResolution.TYPE_RESOLVED :
|
||||||
|
new TypeResolution("Function '%s' cannot be applied on a non-numeric expression ('%s' of type '%s')",
|
||||||
|
functionName(), Expressions.name(field()), field().dataType().esName());
|
||||||
|
|
||||||
|
if (TypeResolution.TYPE_RESOLVED.equals(resolution)) {
|
||||||
|
resolution = value.dataType().isNumeric() ? TypeResolution.TYPE_RESOLVED :
|
||||||
|
new TypeResolution("PercentileRank#value argument cannot be non-numeric (type is'%s')", value.dataType().esName());
|
||||||
|
}
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType dataType() {
|
||||||
|
return DataTypes.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String innerName() {
|
||||||
|
return "[" + Double.toString(Foldables.doubleValueOf(value)) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PercentileRank other = (PercentileRank) obj;
|
||||||
|
return Objects.equals(field(), other.field())
|
||||||
|
&& Objects.equals(value, other.value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class PercentileRanks extends CompoundNumericAggregate {
|
||||||
|
|
||||||
|
private final List<Expression> values;
|
||||||
|
|
||||||
|
public PercentileRanks(Location location, Expression field, List<Expression> values) {
|
||||||
|
super(location, field, values);
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Expression> values() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PercentileRanks other = (PercentileRanks) obj;
|
||||||
|
return Objects.equals(field(), other.field())
|
||||||
|
&& Objects.equals(values, other.values);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Percentiles extends CompoundNumericAggregate {
|
||||||
|
|
||||||
|
private final List<Expression> percents;
|
||||||
|
|
||||||
|
public Percentiles(Location location, Expression field, List<Expression> percents) {
|
||||||
|
super(location, field, percents);
|
||||||
|
this.percents = percents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Expression> percents() {
|
||||||
|
return percents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Percentiles other = (Percentiles) obj;
|
||||||
|
return Objects.equals(field(), other.field())
|
||||||
|
&& Objects.equals(percents, other.percents);
|
||||||
|
}
|
||||||
|
}
|
@ -8,10 +8,10 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
public class Stats extends CompoundAggregate {
|
public class Stats extends CompoundNumericAggregate {
|
||||||
|
|
||||||
public Stats(Location location, Expression argument) {
|
public Stats(Location location, Expression field) {
|
||||||
super(location, argument);
|
super(location, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isTypeCompatible(Expression e) {
|
public static boolean isTypeCompatible(Expression e) {
|
||||||
|
@ -17,7 +17,7 @@ public class Sum extends NumericAggregate implements EnclosedAgg {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType dataType() {
|
public DataType dataType() {
|
||||||
return argument().dataType();
|
return field().dataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,6 +27,10 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.ExtendedStatsEn
|
|||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.InnerAggregate;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.InnerAggregate;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.MatrixStats;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.MatrixStats;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.MatrixStatsEnclosed;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.MatrixStatsEnclosed;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Percentile;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.PercentileRank;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.PercentileRanks;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Percentiles;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Stats;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Stats;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.And;
|
import org.elasticsearch.xpack.sql.expression.predicate.And;
|
||||||
@ -50,7 +54,6 @@ import org.elasticsearch.xpack.sql.plan.logical.SubQueryAlias;
|
|||||||
import org.elasticsearch.xpack.sql.rule.Rule;
|
import org.elasticsearch.xpack.sql.rule.Rule;
|
||||||
import org.elasticsearch.xpack.sql.rule.RuleExecutor;
|
import org.elasticsearch.xpack.sql.rule.RuleExecutor;
|
||||||
import org.elasticsearch.xpack.sql.session.EmptyExecutable;
|
import org.elasticsearch.xpack.sql.session.EmptyExecutable;
|
||||||
import org.elasticsearch.xpack.sql.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -71,6 +74,8 @@ import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.inComm
|
|||||||
import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.splitAnd;
|
import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.splitAnd;
|
||||||
import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.splitOr;
|
import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.splitOr;
|
||||||
import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.subtract;
|
import static org.elasticsearch.xpack.sql.expression.predicate.Predicates.subtract;
|
||||||
|
import static org.elasticsearch.xpack.sql.util.CollectionUtils.combine;
|
||||||
|
|
||||||
|
|
||||||
public class Optimizer extends RuleExecutor<LogicalPlan> {
|
public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||||
|
|
||||||
@ -101,7 +106,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
new CombineAggsToMatrixStats(),
|
new CombineAggsToMatrixStats(),
|
||||||
new CombineAggsToExtendedStats(),
|
new CombineAggsToExtendedStats(),
|
||||||
new CombineAggsToStats(),
|
new CombineAggsToStats(),
|
||||||
new PromoteStatsToExtendedStats()
|
new PromoteStatsToExtendedStats(), new CombineAggsToPercentiles(), new CombineAggsToPercentileRanks()
|
||||||
);
|
);
|
||||||
|
|
||||||
Batch cleanup = new Batch("Operator Optimization",
|
Batch cleanup = new Batch("Operator Optimization",
|
||||||
@ -254,7 +259,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
if (e instanceof MatrixStatsEnclosed) {
|
if (e instanceof MatrixStatsEnclosed) {
|
||||||
AggregateFunction f = (AggregateFunction) e;
|
AggregateFunction f = (AggregateFunction) e;
|
||||||
|
|
||||||
Expression argument = f.argument();
|
Expression argument = f.field();
|
||||||
MatrixStats matrixStats = seen.get(argument);
|
MatrixStats matrixStats = seen.get(argument);
|
||||||
|
|
||||||
if (matrixStats == null) {
|
if (matrixStats == null) {
|
||||||
@ -262,7 +267,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
seen.put(argument, matrixStats);
|
seen.put(argument, matrixStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerAggregate ia = new InnerAggregate(f, matrixStats, f.argument());
|
InnerAggregate ia = new InnerAggregate(f, matrixStats, f.field());
|
||||||
promotedIds.putIfAbsent(f.functionId(), ia.toAttribute());
|
promotedIds.putIfAbsent(f.functionId(), ia.toAttribute());
|
||||||
return ia;
|
return ia;
|
||||||
}
|
}
|
||||||
@ -276,7 +281,6 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
@Override
|
@Override
|
||||||
public LogicalPlan apply(LogicalPlan p) {
|
public LogicalPlan apply(LogicalPlan p) {
|
||||||
Map<String, AggregateFunctionAttribute> promotedFunctionIds = new LinkedHashMap<>();
|
Map<String, AggregateFunctionAttribute> promotedFunctionIds = new LinkedHashMap<>();
|
||||||
|
|
||||||
Map<Expression, ExtendedStats> seen = new LinkedHashMap<>();
|
Map<Expression, ExtendedStats> seen = new LinkedHashMap<>();
|
||||||
p = p.transformExpressionsUp(e -> rule(e, seen, promotedFunctionIds));
|
p = p.transformExpressionsUp(e -> rule(e, seen, promotedFunctionIds));
|
||||||
// update old agg attributes
|
// update old agg attributes
|
||||||
@ -292,7 +296,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
if (e instanceof ExtendedStatsEnclosed) {
|
if (e instanceof ExtendedStatsEnclosed) {
|
||||||
AggregateFunction f = (AggregateFunction) e;
|
AggregateFunction f = (AggregateFunction) e;
|
||||||
|
|
||||||
Expression argument = f.argument();
|
Expression argument = f.field();
|
||||||
ExtendedStats extendedStats = seen.get(argument);
|
ExtendedStats extendedStats = seen.get(argument);
|
||||||
|
|
||||||
if (extendedStats == null) {
|
if (extendedStats == null) {
|
||||||
@ -343,7 +347,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
if (Stats.isTypeCompatible(e)) {
|
if (Stats.isTypeCompatible(e)) {
|
||||||
AggregateFunction f = (AggregateFunction) e;
|
AggregateFunction f = (AggregateFunction) e;
|
||||||
|
|
||||||
Expression argument = f.argument();
|
Expression argument = f.field();
|
||||||
Counter counter = seen.get(argument);
|
Counter counter = seen.get(argument);
|
||||||
|
|
||||||
if (counter == null) {
|
if (counter == null) {
|
||||||
@ -365,7 +369,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
if (Stats.isTypeCompatible(e)) {
|
if (Stats.isTypeCompatible(e)) {
|
||||||
AggregateFunction f = (AggregateFunction) e;
|
AggregateFunction f = (AggregateFunction) e;
|
||||||
|
|
||||||
Expression argument = f.argument();
|
Expression argument = f.field();
|
||||||
Counter counter = seen.get(argument);
|
Counter counter = seen.get(argument);
|
||||||
|
|
||||||
// if the stat has at least two different functions for it, promote it as stat
|
// if the stat has at least two different functions for it, promote it as stat
|
||||||
@ -412,7 +416,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
InnerAggregate ia = (InnerAggregate) e;
|
InnerAggregate ia = (InnerAggregate) e;
|
||||||
if (ia.outer() instanceof ExtendedStats) {
|
if (ia.outer() instanceof ExtendedStats) {
|
||||||
ExtendedStats extStats = (ExtendedStats) ia.outer();
|
ExtendedStats extStats = (ExtendedStats) ia.outer();
|
||||||
seen.putIfAbsent(extStats.argument(), extStats);
|
seen.putIfAbsent(extStats.field(), extStats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,8 +426,8 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
InnerAggregate ia = (InnerAggregate) e;
|
InnerAggregate ia = (InnerAggregate) e;
|
||||||
if (ia.outer() instanceof Stats) {
|
if (ia.outer() instanceof Stats) {
|
||||||
Stats stats = (Stats) ia.outer();
|
Stats stats = (Stats) ia.outer();
|
||||||
ExtendedStats ext = seen.get(stats.argument());
|
ExtendedStats ext = seen.get(stats.field());
|
||||||
if (ext != null && stats.argument().equals(ext.argument())) {
|
if (ext != null && stats.field().equals(ext.field())) {
|
||||||
return new InnerAggregate(ia.inner(), ext);
|
return new InnerAggregate(ia.inner(), ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,6 +437,119 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class CombineAggsToPercentiles extends Rule<LogicalPlan, LogicalPlan> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogicalPlan apply(LogicalPlan p) {
|
||||||
|
// percentile per field/expression
|
||||||
|
Map<Expression, Set<Expression>> percentsPerField = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// count gather the percents for each field
|
||||||
|
p.forEachExpressionsUp(e -> count(e, percentsPerField));
|
||||||
|
|
||||||
|
Map<Expression, Percentiles> percentilesPerField = new LinkedHashMap<>();
|
||||||
|
// create a Percentile agg for each field (and its associated percents)
|
||||||
|
percentsPerField.forEach((k, v) -> {
|
||||||
|
percentilesPerField.put(k, new Percentiles(v.iterator().next().location(), k, new ArrayList<>(v)));
|
||||||
|
});
|
||||||
|
|
||||||
|
// now replace the agg with pointer to the main ones
|
||||||
|
Map<String, AggregateFunctionAttribute> promotedFunctionIds = new LinkedHashMap<>();
|
||||||
|
p = p.transformExpressionsUp(e -> rule(e, percentilesPerField, promotedFunctionIds));
|
||||||
|
// finally update all the function references as well
|
||||||
|
return p.transformExpressionsDown(e -> CombineAggsToStats.updateFunctionAttrs(e, promotedFunctionIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void count(Expression e, Map<Expression, Set<Expression>> percentsPerField) {
|
||||||
|
if (e instanceof Percentile) {
|
||||||
|
Percentile p = (Percentile) e;
|
||||||
|
Expression field = p.field();
|
||||||
|
Set<Expression> percentiles = percentsPerField.get(field);
|
||||||
|
|
||||||
|
if (percentiles == null) {
|
||||||
|
percentiles = new LinkedHashSet<>();
|
||||||
|
percentsPerField.put(field, percentiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
percentiles.add(p.percent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Expression rule(Expression e, Map<Expression, Percentiles> percentilesPerField, Map<String, AggregateFunctionAttribute> promotedIds) {
|
||||||
|
if (e instanceof Percentile) {
|
||||||
|
Percentile p = (Percentile) e;
|
||||||
|
Percentiles percentiles = percentilesPerField.get(p.field());
|
||||||
|
|
||||||
|
InnerAggregate ia = new InnerAggregate(p, percentiles);
|
||||||
|
promotedIds.putIfAbsent(p.functionId(), ia.toAttribute());
|
||||||
|
return ia;
|
||||||
|
}
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LogicalPlan rule(LogicalPlan e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CombineAggsToPercentileRanks extends Rule<LogicalPlan, LogicalPlan> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogicalPlan apply(LogicalPlan p) {
|
||||||
|
// percentile per field/expression
|
||||||
|
Map<Expression, Set<Expression>> valuesPerField = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// count gather the percents for each field
|
||||||
|
p.forEachExpressionsUp(e -> count(e, valuesPerField));
|
||||||
|
|
||||||
|
Map<Expression, PercentileRanks> ranksPerField = new LinkedHashMap<>();
|
||||||
|
// create a PercentileRanks agg for each field (and its associated values)
|
||||||
|
valuesPerField.forEach((k, v) -> {
|
||||||
|
ranksPerField.put(k, new PercentileRanks(v.iterator().next().location(), k, new ArrayList<>(v)));
|
||||||
|
});
|
||||||
|
|
||||||
|
// now replace the agg with pointer to the main ones
|
||||||
|
Map<String, AggregateFunctionAttribute> promotedFunctionIds = new LinkedHashMap<>();
|
||||||
|
p = p.transformExpressionsUp(e -> rule(e, ranksPerField, promotedFunctionIds));
|
||||||
|
// finally update all the function references as well
|
||||||
|
return p.transformExpressionsDown(e -> CombineAggsToStats.updateFunctionAttrs(e, promotedFunctionIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void count(Expression e, Map<Expression, Set<Expression>> ranksPerField) {
|
||||||
|
if (e instanceof PercentileRank) {
|
||||||
|
PercentileRank p = (PercentileRank) e;
|
||||||
|
Expression field = p.field();
|
||||||
|
Set<Expression> percentiles = ranksPerField.get(field);
|
||||||
|
|
||||||
|
if (percentiles == null) {
|
||||||
|
percentiles = new LinkedHashSet<>();
|
||||||
|
ranksPerField.put(field, percentiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
percentiles.add(p.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Expression rule(Expression e, Map<Expression, PercentileRanks> ranksPerField, Map<String, AggregateFunctionAttribute> promotedIds) {
|
||||||
|
if (e instanceof PercentileRank) {
|
||||||
|
PercentileRank p = (PercentileRank) e;
|
||||||
|
PercentileRanks ranks = ranksPerField.get(p.field());
|
||||||
|
|
||||||
|
InnerAggregate ia = new InnerAggregate(p, ranks);
|
||||||
|
promotedIds.putIfAbsent(p.functionId(), ia.toAttribute());
|
||||||
|
return ia;
|
||||||
|
}
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LogicalPlan rule(LogicalPlan e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class PruneFilters extends OptimizerRule<Filter> {
|
static class PruneFilters extends OptimizerRule<Filter> {
|
||||||
|
|
||||||
@ -783,7 +900,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
// (a || b || c || ... ) && (a || b || d || ... ) => ((c || ...) && (d || ...)) || a || b
|
// (a || b || c || ... ) && (a || b || d || ... ) => ((c || ...) && (d || ...)) || a || b
|
||||||
Expression combineLeft = combineOr(lDiff);
|
Expression combineLeft = combineOr(lDiff);
|
||||||
Expression combineRight = combineOr(rDiff);
|
Expression combineRight = combineOr(rDiff);
|
||||||
return combineOr(CollectionUtils.combine(common, new And(combineLeft.location(), combineLeft, combineRight)));
|
return combineOr(combine(common, new And(combineLeft.location(), combineLeft, combineRight)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bc instanceof Or) {
|
if (bc instanceof Or) {
|
||||||
@ -821,7 +938,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||||||
// (a || b || c || ... ) && (a || b || d || ... ) => ((c || ...) && (d || ...)) || a || b
|
// (a || b || c || ... ) && (a || b || d || ... ) => ((c || ...) && (d || ...)) || a || b
|
||||||
Expression combineLeft = combineAnd(lDiff);
|
Expression combineLeft = combineAnd(lDiff);
|
||||||
Expression combineRight = combineAnd(rDiff);
|
Expression combineRight = combineAnd(rDiff);
|
||||||
return combineAnd(CollectionUtils.combine(common, new Or(combineLeft.location(), combineLeft, combineRight)));
|
return combineAnd(combine(common, new Or(combineLeft.location(), combineLeft, combineRight)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: eliminate conjunction/disjunction
|
// TODO: eliminate conjunction/disjunction
|
||||||
|
@ -90,14 +90,6 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
|||||||
return expression(ctx.expression());
|
return expression(ctx.expression());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
// Star will be resolved by the analyzer - currently just put a placeholder
|
|
||||||
public Expression visitStar(StarContext ctx) {
|
|
||||||
return new UnresolvedStar(source(ctx), ctx.qualifier != null ? visitColumnExpression(ctx.qualifier) : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Expression visitSelectExpression(SelectExpressionContext ctx) {
|
public Expression visitSelectExpression(SelectExpressionContext ctx) {
|
||||||
Expression exp = expression(ctx.expression());
|
Expression exp = expression(ctx.expression());
|
||||||
@ -108,6 +100,11 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
|||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Expression visitStar(StarContext ctx) {
|
||||||
|
return new UnresolvedStar(source(ctx), ctx.qualifier != null ? visitColumnExpression(ctx.qualifier) : null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDereference(DereferenceContext ctx) {
|
public Object visitDereference(DereferenceContext ctx) {
|
||||||
String fieldName = visitIdentifier(ctx.fieldName);
|
String fieldName = visitIdentifier(ctx.fieldName);
|
||||||
@ -286,6 +283,7 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
|||||||
if (ctx.setQuantifier() != null) {
|
if (ctx.setQuantifier() != null) {
|
||||||
isDistinct = (ctx.setQuantifier().DISTINCT() != null);
|
isDistinct = (ctx.setQuantifier().DISTINCT() != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UnresolvedFunction(source(ctx), name, isDistinct, expressions(ctx.expression()));
|
return new UnresolvedFunction(source(ctx), name, isDistinct, expressions(ctx.expression()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import org.elasticsearch.xpack.sql.expression.Alias;
|
|||||||
import org.elasticsearch.xpack.sql.expression.Attribute;
|
import org.elasticsearch.xpack.sql.expression.Attribute;
|
||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.expression.ExpressionId;
|
import org.elasticsearch.xpack.sql.expression.ExpressionId;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||||
import org.elasticsearch.xpack.sql.expression.NamedExpression;
|
import org.elasticsearch.xpack.sql.expression.NamedExpression;
|
||||||
import org.elasticsearch.xpack.sql.expression.NestedFieldAttribute;
|
import org.elasticsearch.xpack.sql.expression.NestedFieldAttribute;
|
||||||
import org.elasticsearch.xpack.sql.expression.Order;
|
import org.elasticsearch.xpack.sql.expression.Order;
|
||||||
@ -17,7 +18,7 @@ import org.elasticsearch.xpack.sql.expression.RootFieldAttribute;
|
|||||||
import org.elasticsearch.xpack.sql.expression.function.Function;
|
import org.elasticsearch.xpack.sql.expression.function.Function;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.Functions;
|
import org.elasticsearch.xpack.sql.expression.function.Functions;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunction;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunction;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.CompoundAggregate;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.CompoundNumericAggregate;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Count;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Count;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.InnerAggregate;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.InnerAggregate;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ColumnProcessor;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.ColumnProcessor;
|
||||||
@ -234,7 +235,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
|||||||
|
|
||||||
Map<Attribute, Attribute> aliases = new LinkedHashMap<>();
|
Map<Attribute, Attribute> aliases = new LinkedHashMap<>();
|
||||||
// tracker for compound aggs seen in a group
|
// tracker for compound aggs seen in a group
|
||||||
Map<CompoundAggregate, String> compoundAggMap = new LinkedHashMap<>();
|
Map<CompoundNumericAggregate, String> compoundAggMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
// followed by actual aggregates
|
// followed by actual aggregates
|
||||||
for (NamedExpression ne : a.aggregates()) {
|
for (NamedExpression ne : a.aggregates()) {
|
||||||
@ -338,7 +339,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
|||||||
return queryC.addAggRef(aggInfo.propertyPath(), proc);
|
return queryC.addAggRef(aggInfo.propertyPath(), proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryContainer addFunction(GroupingAgg parentAgg, AggregateFunction f, ColumnProcessor proc, Map<CompoundAggregate, String> compoundAggMap, QueryContainer queryC) {
|
private QueryContainer addFunction(GroupingAgg parentAgg, AggregateFunction f, ColumnProcessor proc, Map<CompoundNumericAggregate, String> compoundAggMap, QueryContainer queryC) {
|
||||||
String functionId = f.functionId();
|
String functionId = f.functionId();
|
||||||
// handle count as a special case agg
|
// handle count as a special case agg
|
||||||
if (f instanceof Count) {
|
if (f instanceof Count) {
|
||||||
@ -354,7 +355,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
|||||||
|
|
||||||
if (f instanceof InnerAggregate) {
|
if (f instanceof InnerAggregate) {
|
||||||
InnerAggregate ia = (InnerAggregate) f;
|
InnerAggregate ia = (InnerAggregate) f;
|
||||||
CompoundAggregate outer = ia.outer();
|
CompoundNumericAggregate outer = ia.outer();
|
||||||
String cAggPath = compoundAggMap.get(outer);
|
String cAggPath = compoundAggMap.get(outer);
|
||||||
|
|
||||||
// the compound agg hasn't been seen before so initialize it
|
// the compound agg hasn't been seen before so initialize it
|
||||||
@ -449,7 +450,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
|||||||
protected PhysicalPlan rule(LimitExec plan) {
|
protected PhysicalPlan rule(LimitExec plan) {
|
||||||
if (plan.child() instanceof EsQueryExec) {
|
if (plan.child() instanceof EsQueryExec) {
|
||||||
EsQueryExec exec = (EsQueryExec) plan.child();
|
EsQueryExec exec = (EsQueryExec) plan.child();
|
||||||
int limit = Integer.valueOf(QueryTranslator.valueOf(plan.limit()));
|
int limit = Foldables.intValueOf(plan.limit());
|
||||||
int currentSize = exec.queryContainer().limit();
|
int currentSize = exec.queryContainer().limit();
|
||||||
int newSize = currentSize < 0 ? limit : Math.min(currentSize, limit);
|
int newSize = currentSize < 0 ? limit : Math.min(currentSize, limit);
|
||||||
return exec.with(exec.queryContainer().withLimit(newSize));
|
return exec.with(exec.queryContainer().withLimit(newSize));
|
||||||
|
@ -20,12 +20,14 @@ import org.elasticsearch.xpack.sql.expression.function.Functions;
|
|||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunction;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunction;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Avg;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Avg;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.CompoundAggregate;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.CompoundNumericAggregate;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Count;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Count;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.ExtendedStats;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.ExtendedStats;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.MatrixStats;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.MatrixStats;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Max;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Max;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Min;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Min;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.PercentileRanks;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Percentiles;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Stats;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Stats;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum;
|
import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ColumnProcessor;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.ColumnProcessor;
|
||||||
@ -62,6 +64,8 @@ import org.elasticsearch.xpack.sql.querydsl.agg.MatrixStatsAgg;
|
|||||||
import org.elasticsearch.xpack.sql.querydsl.agg.MaxAgg;
|
import org.elasticsearch.xpack.sql.querydsl.agg.MaxAgg;
|
||||||
import org.elasticsearch.xpack.sql.querydsl.agg.MinAgg;
|
import org.elasticsearch.xpack.sql.querydsl.agg.MinAgg;
|
||||||
import org.elasticsearch.xpack.sql.querydsl.agg.OrAggFilter;
|
import org.elasticsearch.xpack.sql.querydsl.agg.OrAggFilter;
|
||||||
|
import org.elasticsearch.xpack.sql.querydsl.agg.PercentileRanksAgg;
|
||||||
|
import org.elasticsearch.xpack.sql.querydsl.agg.PercentilesAgg;
|
||||||
import org.elasticsearch.xpack.sql.querydsl.agg.StatsAgg;
|
import org.elasticsearch.xpack.sql.querydsl.agg.StatsAgg;
|
||||||
import org.elasticsearch.xpack.sql.querydsl.agg.SumAgg;
|
import org.elasticsearch.xpack.sql.querydsl.agg.SumAgg;
|
||||||
import org.elasticsearch.xpack.sql.querydsl.query.AndQuery;
|
import org.elasticsearch.xpack.sql.querydsl.query.AndQuery;
|
||||||
@ -93,6 +97,9 @@ import java.util.Map.Entry;
|
|||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
|
import static org.elasticsearch.xpack.sql.expression.Foldables.doubleValuesOf;
|
||||||
|
import static org.elasticsearch.xpack.sql.expression.Foldables.stringValueOf;
|
||||||
|
import static org.elasticsearch.xpack.sql.expression.Foldables.valueOf;
|
||||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
|
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
|
||||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate;
|
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate;
|
||||||
|
|
||||||
@ -117,6 +124,8 @@ abstract class QueryTranslator {
|
|||||||
new StatsAggs(),
|
new StatsAggs(),
|
||||||
new ExtendedStatsAggs(),
|
new ExtendedStatsAggs(),
|
||||||
new MatrixStatsAggs(),
|
new MatrixStatsAggs(),
|
||||||
|
new PercentilesAggs(),
|
||||||
|
new PercentileRanksAggs(),
|
||||||
new DistinctCounts(),
|
new DistinctCounts(),
|
||||||
new DateTimes()
|
new DateTimes()
|
||||||
);
|
);
|
||||||
@ -203,8 +212,8 @@ abstract class QueryTranslator {
|
|||||||
if (groupPath != null) {
|
if (groupPath != null) {
|
||||||
GroupingAgg matchingGroup = null;
|
GroupingAgg matchingGroup = null;
|
||||||
// group found - finding the dedicated agg
|
// group found - finding the dedicated agg
|
||||||
if (f.argument() instanceof NamedExpression) {
|
if (f.field() instanceof NamedExpression) {
|
||||||
matchingGroup = groupMap.get(((NamedExpression) f.argument()).id());
|
matchingGroup = groupMap.get(((NamedExpression) f.field()).id());
|
||||||
}
|
}
|
||||||
// return matching group or the tail (last group)
|
// return matching group or the tail (last group)
|
||||||
return matchingGroup != null ? matchingGroup : tail;
|
return matchingGroup != null ? matchingGroup : tail;
|
||||||
@ -358,11 +367,6 @@ abstract class QueryTranslator {
|
|||||||
return new NotQuery(query.location(), query);
|
return new NotQuery(query.location(), query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static <T> T valueOf(Expression e) {
|
|
||||||
return (T) ((Literal) e).value();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String nameOf(Expression e) {
|
static String nameOf(Expression e) {
|
||||||
if (e instanceof DateTimeFunction) {
|
if (e instanceof DateTimeFunction) {
|
||||||
return nameOf(((DateTimeFunction) e).argument());
|
return nameOf(((DateTimeFunction) e).argument());
|
||||||
@ -370,6 +374,9 @@ abstract class QueryTranslator {
|
|||||||
if (e instanceof NamedExpression) {
|
if (e instanceof NamedExpression) {
|
||||||
return ((NamedExpression) e).name();
|
return ((NamedExpression) e).name();
|
||||||
}
|
}
|
||||||
|
if (e instanceof Literal) {
|
||||||
|
return String.valueOf(e.fold());
|
||||||
|
}
|
||||||
throw new SqlIllegalArgumentException("Cannot determine name for %s", e);
|
throw new SqlIllegalArgumentException("Cannot determine name for %s", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +401,7 @@ abstract class QueryTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String field(AggregateFunction af) {
|
static String field(AggregateFunction af) {
|
||||||
Expression arg = af.argument();
|
Expression arg = af.field();
|
||||||
if (arg instanceof RootFieldAttribute) {
|
if (arg instanceof RootFieldAttribute) {
|
||||||
return ((RootFieldAttribute) arg).name();
|
return ((RootFieldAttribute) arg).name();
|
||||||
}
|
}
|
||||||
@ -420,7 +427,7 @@ abstract class QueryTranslator {
|
|||||||
target = nameOf(analyzed ? fa : fa.notAnalyzedAttribute());
|
target = nameOf(analyzed ? fa : fa.notAnalyzedAttribute());
|
||||||
}
|
}
|
||||||
|
|
||||||
String pattern = sqlToEsPatternMatching(valueOf(e.right()));
|
String pattern = sqlToEsPatternMatching(stringValueOf(e.right()));
|
||||||
if (e instanceof Like) {
|
if (e instanceof Like) {
|
||||||
if (analyzed) {
|
if (analyzed) {
|
||||||
q = new QueryStringQuery(e.location(), pattern, target);
|
q = new QueryStringQuery(e.location(), pattern, target);
|
||||||
@ -435,7 +442,7 @@ abstract class QueryTranslator {
|
|||||||
q = new QueryStringQuery(e.location(), "/" + pattern + "/", target);
|
q = new QueryStringQuery(e.location(), "/" + pattern + "/", target);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
q = new RegexQuery(e.location(), nameOf(e.left()), sqlToEsPatternMatching(valueOf(e.right())));
|
q = new RegexQuery(e.location(), nameOf(e.left()), sqlToEsPatternMatching(stringValueOf(e.right())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,6 +772,22 @@ abstract class QueryTranslator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class PercentilesAggs extends CompoundAggTranslator<Percentiles> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LeafAgg toAgg(String id, String path, Percentiles p) {
|
||||||
|
return new PercentilesAgg(id, path, field(p), doubleValuesOf(p.percents()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PercentileRanksAggs extends CompoundAggTranslator<PercentileRanks> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LeafAgg toAgg(String id, String path, PercentileRanks p) {
|
||||||
|
return new PercentileRanksAgg(id, path, field(p), doubleValuesOf(p.values()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class DateTimes extends SingleValueAggTranslator<Min> {
|
static class DateTimes extends SingleValueAggTranslator<Min> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -796,7 +819,7 @@ abstract class QueryTranslator {
|
|||||||
protected abstract LeafAgg toAgg(String id, String path, F f);
|
protected abstract LeafAgg toAgg(String id, String path, F f);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract static class CompoundAggTranslator<C extends CompoundAggregate> extends AggTranslator<C> {
|
abstract static class CompoundAggTranslator<C extends CompoundNumericAggregate> extends AggTranslator<C> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final LeafAgg asAgg(String id, String parent, C function) {
|
protected final LeafAgg asAgg(String id, String parent, C function) {
|
||||||
|
@ -41,7 +41,8 @@ public abstract class AggPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String metricValue(String aggPath, String valueName) {
|
public static String metricValue(String aggPath, String valueName) {
|
||||||
return aggPath + VALUE_DELIMITER + valueName;
|
// handle aggPath inconsistency (for percentiles and percentileRanks) percentile[99.9] (valid) vs percentile.99.9 (invalid)
|
||||||
|
return valueName.startsWith("[") ? aggPath + valueName : aggPath + VALUE_DELIMITER + valueName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String path(String parent, String child) {
|
public static String path(String parent, String child) {
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.querydsl.agg;
|
||||||
|
|
||||||
|
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.elasticsearch.search.aggregations.AggregationBuilders.percentileRanks;
|
||||||
|
|
||||||
|
public class PercentileRanksAgg extends LeafAgg {
|
||||||
|
|
||||||
|
private final List<Double> values;
|
||||||
|
|
||||||
|
public PercentileRanksAgg(String id, String propertyPath, String fieldName, List<Double> values) {
|
||||||
|
super(id, propertyPath, fieldName);
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Double> percents() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AggregationBuilder toBuilder() {
|
||||||
|
// TODO: look at keyed
|
||||||
|
return percentileRanks(id())
|
||||||
|
.field(fieldName())
|
||||||
|
.values(values.stream().mapToDouble(Double::doubleValue).toArray());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.sql.querydsl.agg;
|
||||||
|
|
||||||
|
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.elasticsearch.search.aggregations.AggregationBuilders.percentiles;
|
||||||
|
|
||||||
|
public class PercentilesAgg extends LeafAgg {
|
||||||
|
|
||||||
|
private final List<Double> percents;
|
||||||
|
|
||||||
|
public PercentilesAgg(String id, String propertyPath, String fieldName, List<Double> percents) {
|
||||||
|
super(id, propertyPath, fieldName);
|
||||||
|
this.percents = percents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Double> percents() {
|
||||||
|
return percents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AggregationBuilder toBuilder() {
|
||||||
|
// TODO: look at keyed
|
||||||
|
return percentiles(id())
|
||||||
|
.field(fieldName())
|
||||||
|
.percentiles(percents.stream().mapToDouble(Double::doubleValue).toArray());
|
||||||
|
}
|
||||||
|
}
|
@ -64,4 +64,4 @@ public interface DataType {
|
|||||||
default boolean same(DataType other) {
|
default boolean same(DataType other) {
|
||||||
return getClass() == other.getClass();
|
return getClass() == other.getClass();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,12 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.type;
|
package org.elasticsearch.xpack.sql.type;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
|
|
||||||
import java.sql.JDBCType;
|
import java.sql.JDBCType;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
|
||||||
|
|
||||||
public abstract class DataTypes {
|
public abstract class DataTypes {
|
||||||
|
|
||||||
public static final DataType NULL = new NullType();
|
public static final DataType NULL = new NullType();
|
||||||
@ -104,6 +104,9 @@ public abstract class DataTypes {
|
|||||||
if (value instanceof Short) {
|
if (value instanceof Short) {
|
||||||
return SHORT;
|
return SHORT;
|
||||||
}
|
}
|
||||||
|
if (value instanceof String) {
|
||||||
|
return KEYWORD;
|
||||||
|
}
|
||||||
throw new SqlIllegalArgumentException("No idea what's the DataType for %s", value.getClass());
|
throw new SqlIllegalArgumentException("No idea what's the DataType for %s", value.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,15 @@ public abstract class CollectionUtils {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> List<T> combine(Collection<? extends T> left, Collection<? extends T> right) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> List<T> combine(List<? extends T> left, List<? extends T> right) {
|
||||||
|
if (right.isEmpty()) {
|
||||||
|
return (List<T>) left;
|
||||||
|
}
|
||||||
|
if (left.isEmpty()) {
|
||||||
|
return (List<T>) right;
|
||||||
|
}
|
||||||
|
|
||||||
List<T> list = new ArrayList<>(left.size() + right.size());
|
List<T> list = new ArrayList<>(left.size() + right.size());
|
||||||
if (!left.isEmpty()) {
|
if (!left.isEmpty()) {
|
||||||
list.addAll(left);
|
list.addAll(left);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user