This is an automated email from the ASF dual-hosted git repository. jackie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push: new 82252ed843 [Clean up] Do not count DISTINCT as aggregation (#10985) 82252ed843 is described below commit 82252ed84340627223258ba1aaeb1b372a86c2f9 Author: Xiaotian (Jackie) Jiang <17555551+jackie-ji...@users.noreply.github.com> AuthorDate: Wed Jun 28 13:07:25 2023 -0700 [Clean up] Do not count DISTINCT as aggregation (#10985) --- .../pinot/sql/parsers/CalciteSqlCompilerTest.java | 12 +- .../blocks/results/DistinctResultsBlock.java | 5 +- .../operator/blocks/results/ResultsBlockUtils.java | 29 ++-- .../query/DictionaryBasedDistinctOperator.java | 122 ++++++---------- .../core/operator/query/DistinctOperator.java | 29 ++-- .../apache/pinot/core/plan/DistinctPlanNode.java | 31 ++-- .../function/AggregationFunctionFactory.java | 26 ++-- .../function/DistinctAggregationFunction.java | 161 --------------------- .../query/distinct/DistinctExecutorFactory.java | 17 ++- .../core/query/reduce/BaseGapfillProcessor.java | 6 +- .../query/reduce/DistinctDataTableReducer.java | 23 +-- .../pinot/core/query/reduce/GapfillProcessor.java | 2 +- .../core/query/reduce/ResultReducerFactory.java | 24 +-- .../core/query/request/context/QueryContext.java | 40 +++-- .../context/utils/QueryContextConverterUtils.java | 46 +++--- .../request/context/utils/QueryContextUtils.java | 16 +- .../function/AggregationFunctionFactoryTest.java | 157 +++++++++----------- .../BrokerRequestToQueryContextConverterTest.java | 44 +++--- .../query/parser/CalciteRexExpressionParser.java | 3 +- .../LeafStageTransferableBlockOperatorTest.java | 11 +- .../pinot/segment/spi/AggregationFunctionType.java | 1 - 21 files changed, 281 insertions(+), 524 deletions(-) diff --git a/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java b/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java index fd6c3b6ac3..891151f17c 100644 --- a/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java +++ b/pinot-common/src/test/java/org/apache/pinot/sql/parsers/CalciteSqlCompilerTest.java @@ -1062,7 +1062,7 @@ public class CalciteSqlCompilerTest { Assert.assertEquals(selectListExpressions.get(0).getType(), ExpressionType.FUNCTION); Function distinctFunction = selectListExpressions.get(0).getFunctionCall(); - Assert.assertEquals(distinctFunction.getOperator(), AggregationFunctionType.DISTINCT.getName()); + Assert.assertEquals(distinctFunction.getOperator(), "distinct"); Assert.assertEquals(distinctFunction.getOperands().size(), 1); Identifier c1 = distinctFunction.getOperands().get(0).getIdentifier(); @@ -1076,7 +1076,7 @@ public class CalciteSqlCompilerTest { Assert.assertEquals(selectListExpressions.get(0).getType(), ExpressionType.FUNCTION); distinctFunction = selectListExpressions.get(0).getFunctionCall(); - Assert.assertEquals(distinctFunction.getOperator(), AggregationFunctionType.DISTINCT.getName()); + Assert.assertEquals(distinctFunction.getOperator(), "distinct"); Assert.assertEquals(distinctFunction.getOperands().size(), 2); c1 = distinctFunction.getOperands().get(0).getIdentifier(); @@ -1093,7 +1093,7 @@ public class CalciteSqlCompilerTest { Assert.assertEquals(selectListExpressions.get(0).getType(), ExpressionType.FUNCTION); distinctFunction = selectListExpressions.get(0).getFunctionCall(); - Assert.assertEquals(distinctFunction.getOperator(), AggregationFunctionType.DISTINCT.getName()); + Assert.assertEquals(distinctFunction.getOperator(), "distinct"); Assert.assertEquals(distinctFunction.getOperands().size(), 3); final Expression filter = pinotQuery.getFilterExpression(); @@ -1210,7 +1210,7 @@ public class CalciteSqlCompilerTest { Assert.assertEquals(selectListExpressions.get(0).getType(), ExpressionType.FUNCTION); distinctFunction = selectListExpressions.get(0).getFunctionCall(); - Assert.assertEquals(distinctFunction.getOperator(), AggregationFunctionType.DISTINCT.getName()); + Assert.assertEquals(distinctFunction.getOperator(), "distinct"); Assert.assertEquals(distinctFunction.getOperands().size(), 1); Function add = distinctFunction.getOperands().get(0).getFunctionCall(); @@ -1229,7 +1229,7 @@ public class CalciteSqlCompilerTest { Assert.assertEquals(selectListExpressions.get(0).getType(), ExpressionType.FUNCTION); distinctFunction = selectListExpressions.get(0).getFunctionCall(); - Assert.assertEquals(distinctFunction.getOperator(), AggregationFunctionType.DISTINCT.getName()); + Assert.assertEquals(distinctFunction.getOperator(), "distinct"); Assert.assertEquals(distinctFunction.getOperands().size(), 2); // check for DISTINCT's first operand ADD(....) @@ -1272,7 +1272,7 @@ public class CalciteSqlCompilerTest { Assert.assertEquals(selectListExpressions.get(0).getType(), ExpressionType.FUNCTION); distinctFunction = selectListExpressions.get(0).getFunctionCall(); - Assert.assertEquals(distinctFunction.getOperator(), AggregationFunctionType.DISTINCT.getName()); + Assert.assertEquals(distinctFunction.getOperator(), "distinct"); Assert.assertEquals(distinctFunction.getOperands().size(), 4); // check for DISTINCT's first operand ADD(....) diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/DistinctResultsBlock.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/DistinctResultsBlock.java index 0cbeebd176..b1d4fc3ade 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/DistinctResultsBlock.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/DistinctResultsBlock.java @@ -25,7 +25,6 @@ import java.util.List; import org.apache.pinot.common.datatable.DataTable; import org.apache.pinot.common.utils.DataSchema; import org.apache.pinot.core.data.table.Record; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.DistinctTable; import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.core.query.selection.SelectionOperatorUtils; @@ -35,11 +34,9 @@ import org.apache.pinot.core.query.selection.SelectionOperatorUtils; * Results block for distinct queries. */ public class DistinctResultsBlock extends BaseResultsBlock { - private final DistinctAggregationFunction _distinctFunction; private DistinctTable _distinctTable; - public DistinctResultsBlock(DistinctAggregationFunction distinctFunction, DistinctTable distinctTable) { - _distinctFunction = distinctFunction; + public DistinctResultsBlock(DistinctTable distinctTable) { _distinctTable = distinctTable; } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/ResultsBlockUtils.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/ResultsBlockUtils.java index f760920923..ed59ffbcc6 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/ResultsBlockUtils.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/ResultsBlockUtils.java @@ -29,7 +29,6 @@ import org.apache.pinot.common.utils.DataSchema; import org.apache.pinot.common.utils.DataSchema.ColumnDataType; import org.apache.pinot.core.query.aggregation.function.AggregationFunction; import org.apache.pinot.core.query.aggregation.function.AggregationFunctionUtils; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.DistinctTable; import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.core.query.request.context.utils.QueryContextUtils; @@ -43,16 +42,16 @@ public class ResultsBlockUtils { public static BaseResultsBlock buildEmptyQueryResults(QueryContext queryContext) { if (QueryContextUtils.isSelectionQuery(queryContext)) { return buildEmptySelectionQueryResults(queryContext); - } else if (QueryContextUtils.isAggregationQuery(queryContext)) { + } + if (QueryContextUtils.isAggregationQuery(queryContext)) { if (queryContext.getGroupByExpressions() == null) { return buildEmptyAggregationQueryResults(queryContext); } else { return buildEmptyGroupByQueryResults(queryContext); } - } else { - assert QueryContextUtils.isDistinctQuery(queryContext); - return buildEmptyDistinctQueryResults(queryContext); } + assert QueryContextUtils.isDistinctQuery(queryContext); + return buildEmptyDistinctQueryResults(queryContext); } private static SelectionResultsBlock buildEmptySelectionQueryResults(QueryContext queryContext) { @@ -105,17 +104,17 @@ public class ResultsBlockUtils { } private static DistinctResultsBlock buildEmptyDistinctQueryResults(QueryContext queryContext) { - AggregationFunction[] aggregationFunctions = queryContext.getAggregationFunctions(); - assert aggregationFunctions != null && aggregationFunctions.length == 1 - && aggregationFunctions[0] instanceof DistinctAggregationFunction; - DistinctAggregationFunction distinctAggregationFunction = (DistinctAggregationFunction) aggregationFunctions[0]; - String[] columnNames = distinctAggregationFunction.getColumns(); - ColumnDataType[] columnDataTypes = new ColumnDataType[columnNames.length]; + List<ExpressionContext> expressions = queryContext.getSelectExpressions(); + int numExpressions = expressions.size(); + String[] columns = new String[numExpressions]; + for (int i = 0; i < numExpressions; i++) { + columns[i] = expressions.get(i).toString(); + } + ColumnDataType[] columnDataTypes = new ColumnDataType[numExpressions]; // NOTE: Use STRING column data type as default for distinct query Arrays.fill(columnDataTypes, ColumnDataType.STRING); - DistinctTable distinctTable = - new DistinctTable(new DataSchema(columnNames, columnDataTypes), Collections.emptySet(), - queryContext.isNullHandlingEnabled()); - return new DistinctResultsBlock(distinctAggregationFunction, distinctTable); + DistinctTable distinctTable = new DistinctTable(new DataSchema(columns, columnDataTypes), Collections.emptySet(), + queryContext.isNullHandlingEnabled()); + return new DistinctResultsBlock(distinctTable); } } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DictionaryBasedDistinctOperator.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DictionaryBasedDistinctOperator.java index edb5f8a109..2ab339cb21 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DictionaryBasedDistinctOperator.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DictionaryBasedDistinctOperator.java @@ -21,7 +21,6 @@ package org.apache.pinot.core.operator.query; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.request.context.OrderByExpressionContext; import org.apache.pinot.common.utils.DataSchema; import org.apache.pinot.core.common.Operator; @@ -29,11 +28,11 @@ import org.apache.pinot.core.data.table.Record; import org.apache.pinot.core.operator.BaseOperator; import org.apache.pinot.core.operator.ExecutionStatistics; import org.apache.pinot.core.operator.blocks.results.DistinctResultsBlock; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.DistinctTable; -import org.apache.pinot.segment.spi.AggregationFunctionType; +import org.apache.pinot.core.query.request.context.QueryContext; +import org.apache.pinot.segment.spi.datasource.DataSource; +import org.apache.pinot.segment.spi.datasource.DataSourceMetadata; import org.apache.pinot.segment.spi.index.reader.Dictionary; -import org.apache.pinot.spi.data.FieldSpec; import org.apache.pinot.spi.trace.Tracing; @@ -43,103 +42,77 @@ import org.apache.pinot.spi.trace.Tracing; public class DictionaryBasedDistinctOperator extends BaseOperator<DistinctResultsBlock> { private static final String EXPLAIN_NAME = "DISTINCT_DICTIONARY"; - private final DistinctAggregationFunction _distinctAggregationFunction; - private final Dictionary _dictionary; - private final int _numTotalDocs; - private final boolean _nullHandlingEnabled; - private final FieldSpec.DataType _dataType; + private final DataSource _dataSource; + private final QueryContext _queryContext; - private boolean _hasOrderBy; - private boolean _isAscending; private int _numDocsScanned; - public DictionaryBasedDistinctOperator(FieldSpec.DataType dataType, - DistinctAggregationFunction distinctAggregationFunction, Dictionary dictionary, int numTotalDocs, - boolean nullHandlingEnabled) { - _dataType = dataType; - _distinctAggregationFunction = distinctAggregationFunction; - _dictionary = dictionary; - _numTotalDocs = numTotalDocs; - _nullHandlingEnabled = nullHandlingEnabled; - - List<OrderByExpressionContext> orderByExpressionContexts = _distinctAggregationFunction.getOrderByExpressions(); - if (orderByExpressionContexts != null) { - OrderByExpressionContext orderByExpressionContext = orderByExpressionContexts.get(0); - _isAscending = orderByExpressionContext.isAsc(); - _hasOrderBy = true; - } + public DictionaryBasedDistinctOperator(DataSource dataSource, QueryContext queryContext) { + _dataSource = dataSource; + _queryContext = queryContext; } @Override protected DistinctResultsBlock getNextBlock() { - return new DistinctResultsBlock(_distinctAggregationFunction, buildResult()); - } - - /** - * Build the final result for this operation - */ - private DistinctTable buildResult() { - - assert _distinctAggregationFunction.getType() == AggregationFunctionType.DISTINCT; - - List<ExpressionContext> expressions = _distinctAggregationFunction.getInputExpressions(); - ExpressionContext expression = expressions.get(0); - DataSchema dataSchema = new DataSchema(new String[]{expression.toString()}, - new DataSchema.ColumnDataType[]{DataSchema.ColumnDataType.fromDataTypeSV(_dataType)}); - int dictLength = _dictionary.length(); - List<Record> records; - - int limit = _distinctAggregationFunction.getLimit(); - int actualLimit = Math.min(limit, dictLength); + String column = _queryContext.getSelectExpressions().get(0).getIdentifier(); + Dictionary dictionary = _dataSource.getDictionary(); + assert dictionary != null; + DataSourceMetadata dataSourceMetadata = _dataSource.getDataSourceMetadata(); + DataSchema dataSchema = new DataSchema(new String[]{column}, + new DataSchema.ColumnDataType[]{DataSchema.ColumnDataType.fromDataTypeSV(dataSourceMetadata.getDataType())}); + int limit = _queryContext.getLimit(); + int dictLength = dictionary.length(); + int numValuesToKeep = Math.min(limit, dictLength); + boolean nullHandlingEnabled = _queryContext.isNullHandlingEnabled(); // If ORDER BY is not present, we read the first limit values from the dictionary and return. // If ORDER BY is present and the dictionary is sorted, then we read the first/last limit values // from the dictionary. If not sorted, then we read the entire dictionary and return it. - if (!_hasOrderBy) { - records = new ArrayList<>(actualLimit); - - _numDocsScanned = actualLimit; - iterateOnDictionary(dictLength, actualLimit, records); + DistinctTable distinctTable; + List<OrderByExpressionContext> orderByExpressions = _queryContext.getOrderByExpressions(); + if (orderByExpressions == null) { + distinctTable = + new DistinctTable(dataSchema, iterateOnDictionary(dictionary, numValuesToKeep), nullHandlingEnabled); + _numDocsScanned = numValuesToKeep; } else { - if (_dictionary.isSorted()) { - records = new ArrayList<>(actualLimit); - if (_isAscending) { - _numDocsScanned = actualLimit; - iterateOnDictionary(dictLength, actualLimit, records); + if (dictionary.isSorted()) { + if (orderByExpressions.get(0).isAsc()) { + distinctTable = + new DistinctTable(dataSchema, iterateOnDictionary(dictionary, numValuesToKeep), nullHandlingEnabled); } else { - _numDocsScanned = actualLimit; - iterateOnDictionaryDesc(dictLength, actualLimit, records); + distinctTable = + new DistinctTable(dataSchema, iterateOnDictionaryDesc(dictionary, numValuesToKeep), nullHandlingEnabled); } + _numDocsScanned = numValuesToKeep; } else { - // DictionaryBasedDistinctOperator cannot handle nulls. - DistinctTable distinctTable = - new DistinctTable(dataSchema, _distinctAggregationFunction.getOrderByExpressions(), limit, - _nullHandlingEnabled); - - _numDocsScanned = dictLength; + distinctTable = new DistinctTable(dataSchema, orderByExpressions, limit, nullHandlingEnabled); for (int i = 0; i < dictLength; i++) { - distinctTable.addWithOrderBy(new Record(new Object[]{_dictionary.getInternal(i)})); + distinctTable.addWithOrderBy(new Record(new Object[]{dictionary.getInternal(i)})); } - - return distinctTable; + _numDocsScanned = dictLength; } } - return new DistinctTable(dataSchema, records, _nullHandlingEnabled); + return new DistinctResultsBlock(distinctTable); } - private void iterateOnDictionary(int dictLength, int actualLimit, List<Record> records) { - for (int i = 0; i < actualLimit; i++) { + private static List<Record> iterateOnDictionary(Dictionary dictionary, int length) { + List<Record> records = new ArrayList<>(length); + for (int i = 0; i < length; i++) { Tracing.ThreadAccountantOps.sampleAndCheckInterruptionPeriodically(i); - records.add(new Record(new Object[]{_dictionary.getInternal(i)})); + records.add(new Record(new Object[]{dictionary.getInternal(i)})); } + return records; } - private void iterateOnDictionaryDesc(int dictLength, int actualLimit, List<Record> records) { - for (int i = dictLength - 1, j = 0; i >= (dictLength - actualLimit); i--, j++) { + private static List<Record> iterateOnDictionaryDesc(Dictionary dictionary, int length) { + List<Record> records = new ArrayList<>(length); + int dictLength = dictionary.length(); + for (int i = dictLength - 1, j = 0; i >= (dictLength - length); i--, j++) { Tracing.ThreadAccountantOps.sampleAndCheckInterruptionPeriodically(j); - records.add(new Record(new Object[]{_dictionary.getInternal(i)})); + records.add(new Record(new Object[]{dictionary.getInternal(i)})); } + return records; } @Override @@ -155,6 +128,7 @@ public class DictionaryBasedDistinctOperator extends BaseOperator<DistinctResult @Override public ExecutionStatistics getExecutionStatistics() { // NOTE: Set numDocsScanned to numTotalDocs for backward compatibility. - return new ExecutionStatistics(_numDocsScanned, 0, _numDocsScanned, _numTotalDocs); + return new ExecutionStatistics(_numDocsScanned, 0, _numDocsScanned, + _dataSource.getDataSourceMetadata().getNumDocs()); } } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DistinctOperator.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DistinctOperator.java index 30e135223f..3d95a0c547 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DistinctOperator.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/query/DistinctOperator.java @@ -20,12 +20,12 @@ package org.apache.pinot.core.operator.query; import java.util.Collections; import java.util.List; +import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.core.operator.BaseOperator; import org.apache.pinot.core.operator.BaseProjectOperator; import org.apache.pinot.core.operator.ExecutionStatistics; import org.apache.pinot.core.operator.blocks.ValueBlock; import org.apache.pinot.core.operator.blocks.results.DistinctResultsBlock; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.DistinctExecutor; import org.apache.pinot.core.query.distinct.DistinctExecutorFactory; import org.apache.pinot.core.query.request.context.QueryContext; @@ -39,31 +39,29 @@ public class DistinctOperator extends BaseOperator<DistinctResultsBlock> { private static final String EXPLAIN_NAME = "DISTINCT"; private final IndexSegment _indexSegment; - private final DistinctAggregationFunction _distinctAggregationFunction; private final BaseProjectOperator<?> _projectOperator; - private final DistinctExecutor _distinctExecutor; + private final QueryContext _queryContext; private int _numDocsScanned = 0; - public DistinctOperator(IndexSegment indexSegment, DistinctAggregationFunction distinctAggregationFunction, - BaseProjectOperator<?> projectOperator, QueryContext queryContext) { + public DistinctOperator(IndexSegment indexSegment, BaseProjectOperator<?> projectOperator, + QueryContext queryContext) { _indexSegment = indexSegment; - _distinctAggregationFunction = distinctAggregationFunction; _projectOperator = projectOperator; - _distinctExecutor = DistinctExecutorFactory.getDistinctExecutor(distinctAggregationFunction, projectOperator, - queryContext.isNullHandlingEnabled()); + _queryContext = queryContext; } @Override protected DistinctResultsBlock getNextBlock() { + DistinctExecutor executor = DistinctExecutorFactory.getDistinctExecutor(_projectOperator, _queryContext); ValueBlock valueBlock; while ((valueBlock = _projectOperator.nextBlock()) != null) { _numDocsScanned += valueBlock.getNumDocs(); - if (_distinctExecutor.process(valueBlock)) { + if (executor.process(valueBlock)) { break; } } - return new DistinctResultsBlock(_distinctAggregationFunction, _distinctExecutor.getResult()); + return new DistinctResultsBlock(executor.getResult()); } @Override @@ -87,13 +85,12 @@ public class DistinctOperator extends BaseOperator<DistinctResultsBlock> { @Override public String toExplainString() { - String[] keys = _distinctAggregationFunction.getColumns(); + List<ExpressionContext> expressions = _queryContext.getSelectExpressions(); + int numExpressions = expressions.size(); StringBuilder stringBuilder = new StringBuilder(EXPLAIN_NAME).append("(keyColumns:"); - if (keys.length > 0) { - stringBuilder.append(keys[0]); - for (int i = 1; i < keys.length; i++) { - stringBuilder.append(", ").append(keys[i]); - } + stringBuilder.append(expressions.get(0).toString()); + for (int i = 1; i < numExpressions; i++) { + stringBuilder.append(", ").append(expressions.get(i).toString()); } return stringBuilder.append(')').toString(); } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/plan/DistinctPlanNode.java b/pinot-core/src/main/java/org/apache/pinot/core/plan/DistinctPlanNode.java index 81182535cc..be8b92e833 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/plan/DistinctPlanNode.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/plan/DistinctPlanNode.java @@ -25,20 +25,15 @@ import org.apache.pinot.core.operator.BaseProjectOperator; import org.apache.pinot.core.operator.blocks.results.DistinctResultsBlock; import org.apache.pinot.core.operator.query.DictionaryBasedDistinctOperator; import org.apache.pinot.core.operator.query.DistinctOperator; -import org.apache.pinot.core.query.aggregation.function.AggregationFunction; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.segment.spi.IndexSegment; import org.apache.pinot.segment.spi.datasource.DataSource; -import org.apache.pinot.segment.spi.datasource.DataSourceMetadata; -import org.apache.pinot.segment.spi.index.reader.Dictionary; import org.apache.pinot.segment.spi.index.reader.NullValueVectorReader; /** * Execution plan for distinct queries on a single segment. */ -@SuppressWarnings("rawtypes") public class DistinctPlanNode implements PlanNode { private final IndexSegment _indexSegment; private final QueryContext _queryContext; @@ -50,20 +45,17 @@ public class DistinctPlanNode implements PlanNode { @Override public Operator<DistinctResultsBlock> run() { - AggregationFunction[] aggregationFunctions = _queryContext.getAggregationFunctions(); - assert aggregationFunctions != null && aggregationFunctions.length == 1 - && aggregationFunctions[0] instanceof DistinctAggregationFunction; - DistinctAggregationFunction distinctAggregationFunction = (DistinctAggregationFunction) aggregationFunctions[0]; - List<ExpressionContext> expressions = distinctAggregationFunction.getInputExpressions(); + List<ExpressionContext> expressions = _queryContext.getSelectExpressions(); // Use dictionary to solve the query if possible - if (_queryContext.getFilter() == null && !_queryContext.isNullHandlingEnabled() && expressions.size() == 1) { - ExpressionContext expression = expressions.get(0); - if (expression.getType() == ExpressionContext.Type.IDENTIFIER) { - DataSource dataSource = _indexSegment.getDataSource(expression.getIdentifier()); - Dictionary dictionary = dataSource.getDictionary(); - if (dictionary != null) { - DataSourceMetadata dataSourceMetadata = dataSource.getDataSourceMetadata(); + if (_queryContext.getFilter() == null && expressions.size() == 1) { + String column = expressions.get(0).getIdentifier(); + if (column != null) { + DataSource dataSource = _indexSegment.getDataSource(column); + if (dataSource.getDictionary() != null) { + if (!_queryContext.isNullHandlingEnabled()) { + return new DictionaryBasedDistinctOperator(dataSource, _queryContext); + } // If nullHandlingEnabled is set to true, and the column contains null values, call DistinctOperator instead // of DictionaryBasedDistinctOperator since nullValueVectorReader is a form of a filter. // TODO: reserve special value in dictionary (e.g. -1) for null in the future so @@ -71,8 +63,7 @@ public class DistinctPlanNode implements PlanNode { // dictionary-encoded columns. NullValueVectorReader nullValueReader = dataSource.getNullValueVector(); if (nullValueReader == null || nullValueReader.getNullBitmap().isEmpty()) { - return new DictionaryBasedDistinctOperator(dataSourceMetadata.getDataType(), distinctAggregationFunction, - dictionary, dataSourceMetadata.getNumDocs(), _queryContext.isNullHandlingEnabled()); + return new DictionaryBasedDistinctOperator(dataSource, _queryContext); } } } @@ -80,6 +71,6 @@ public class DistinctPlanNode implements PlanNode { BaseProjectOperator<?> projectOperator = new ProjectPlanNode(_indexSegment, _queryContext, expressions, DocIdSetPlanNode.MAX_DOC_PER_CALL).run(); - return new DistinctOperator(_indexSegment, distinctAggregationFunction, projectOperator, _queryContext); + return new DistinctOperator(_indexSegment, projectOperator, _queryContext); } } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactory.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactory.java index 7f96072c9e..4a01580e61 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactory.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactory.java @@ -24,7 +24,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.datasketches.tuple.aninteger.IntegerSummary; import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.request.context.FunctionContext; -import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.segment.spi.AggregationFunctionType; import org.apache.pinot.spi.data.FieldSpec.DataType; import org.apache.pinot.spi.exception.BadQueryRequestException; @@ -41,12 +40,8 @@ public class AggregationFunctionFactory { /** * Given the function information, returns a new instance of the corresponding aggregation function. * <p>NOTE: Underscores in the function name are ignored. - * <p>NOTE: We pass the query context to this method because DISTINCT is currently modeled as an aggregation function - * and requires the order-by and limit information from the query. - * <p>TODO: Consider modeling DISTINCT as unique selection instead of aggregation so that early-termination, limit and - * offset can be applied easier */ - public static AggregationFunction getAggregationFunction(FunctionContext function, QueryContext queryContext) { + public static AggregationFunction getAggregationFunction(FunctionContext function, boolean nullHandlingEnabled) { try { String upperCaseFunctionName = StringUtils.remove(function.getFunctionName(), '_').toUpperCase(); List<ExpressionContext> arguments = function.getArguments(); @@ -187,17 +182,17 @@ public class AggregationFunctionFactory { } else { switch (AggregationFunctionType.valueOf(upperCaseFunctionName)) { case COUNT: - return new CountAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new CountAggregationFunction(firstArgument, nullHandlingEnabled); case MIN: - return new MinAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new MinAggregationFunction(firstArgument, nullHandlingEnabled); case MAX: - return new MaxAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new MaxAggregationFunction(firstArgument, nullHandlingEnabled); case SUM: - return new SumAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new SumAggregationFunction(firstArgument, nullHandlingEnabled); case SUMPRECISION: - return new SumPrecisionAggregationFunction(arguments, queryContext.isNullHandlingEnabled()); + return new SumPrecisionAggregationFunction(arguments, nullHandlingEnabled); case AVG: - return new AvgAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new AvgAggregationFunction(firstArgument, nullHandlingEnabled); case MODE: return new ModeAggregationFunction(arguments); case FIRSTWITHTIME: @@ -308,9 +303,6 @@ public class AggregationFunctionFactory { return new DistinctSumMVAggregationFunction(firstArgument); case DISTINCTAVGMV: return new DistinctAvgMVAggregationFunction(firstArgument); - case DISTINCT: - return new DistinctAggregationFunction(arguments, queryContext.getOrderByExpressions(), - queryContext.getLimit()); case STUNION: return new StUnionAggregationFunction(firstArgument); case HISTOGRAM: @@ -320,9 +312,9 @@ public class AggregationFunctionFactory { case COVARSAMP: return new CovarianceAggregationFunction(arguments, true); case BOOLAND: - return new BooleanAndAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new BooleanAndAggregationFunction(firstArgument, nullHandlingEnabled); case BOOLOR: - return new BooleanOrAggregationFunction(firstArgument, queryContext.isNullHandlingEnabled()); + return new BooleanOrAggregationFunction(firstArgument, nullHandlingEnabled); case VARPOP: return new VarianceAggregationFunction(firstArgument, false, false); case VARSAMP: diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctAggregationFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctAggregationFunction.java deleted file mode 100644 index 6035ca5a03..0000000000 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctAggregationFunction.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.pinot.core.query.aggregation.function; - -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; -import org.apache.pinot.common.request.context.ExpressionContext; -import org.apache.pinot.common.request.context.OrderByExpressionContext; -import org.apache.pinot.common.utils.DataSchema.ColumnDataType; -import org.apache.pinot.core.common.BlockValSet; -import org.apache.pinot.core.query.aggregation.AggregationResultHolder; -import org.apache.pinot.core.query.aggregation.groupby.GroupByResultHolder; -import org.apache.pinot.segment.spi.AggregationFunctionType; - - -/** - * The DISTINCT clause in SQL is represented as the DISTINCT aggregation function. Currently it is only used to wrap the - * information for the distinct queries. - * TODO: Use a separate way to represent DISTINCT instead of aggregation. - */ -@SuppressWarnings("rawtypes") -public class DistinctAggregationFunction implements AggregationFunction<Object, Comparable> { - private final List<ExpressionContext> _expressions; - private final String[] _columns; - private final List<OrderByExpressionContext> _orderByExpressions; - private final int _limit; - - /** - * Constructor for the class. - * - * @param expressions Distinct columns to return - * @param orderByExpressions Order By clause - * @param limit Limit clause - */ - public DistinctAggregationFunction(List<ExpressionContext> expressions, - @Nullable List<OrderByExpressionContext> orderByExpressions, int limit) { - _expressions = expressions; - int numExpressions = expressions.size(); - _columns = new String[numExpressions]; - for (int i = 0; i < numExpressions; i++) { - _columns[i] = expressions.get(i).toString(); - } - _orderByExpressions = orderByExpressions; - _limit = limit; - } - - public String[] getColumns() { - return _columns; - } - - public List<OrderByExpressionContext> getOrderByExpressions() { - return _orderByExpressions; - } - - public int getLimit() { - return _limit; - } - - @Override - public AggregationFunctionType getType() { - return AggregationFunctionType.DISTINCT; - } - - @Override - public List<ExpressionContext> getInputExpressions() { - return _expressions; - } - - @Override - public String getResultColumnName() { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public ColumnDataType getIntermediateResultColumnType() { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public AggregationResultHolder createAggregationResultHolder() { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public GroupByResultHolder createGroupByResultHolder(int initialCapacity, int maxCapacity) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public void aggregate(int length, AggregationResultHolder aggregationResultHolder, - Map<ExpressionContext, BlockValSet> blockValSetMap) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public void aggregateGroupBySV(int length, int[] groupKeyArray, GroupByResultHolder groupByResultHolder, - Map<ExpressionContext, BlockValSet> blockValSetMap) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public void aggregateGroupByMV(int length, int[][] groupKeysArray, GroupByResultHolder groupByResultHolder, - Map<ExpressionContext, BlockValSet> blockValSetMap) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public Object extractAggregationResult(AggregationResultHolder aggregationResultHolder) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public Object extractGroupByResult(GroupByResultHolder groupByResultHolder, int groupKey) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public Object merge(Object intermediateResult1, Object intermediateResult2) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public ColumnDataType getFinalResultColumnType() { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public Comparable extractFinalResult(Object intermediateResult) { - throw new UnsupportedOperationException("Operation not supported for DISTINCT aggregation function"); - } - - @Override - public String toExplainString() { - StringBuilder stringBuilder = new StringBuilder(getType().getName()).append('('); - int numArguments = getInputExpressions().size(); - if (numArguments > 0) { - stringBuilder.append(getInputExpressions().get(0).toString()); - for (int i = 1; i < numArguments; i++) { - stringBuilder.append(", ").append(getInputExpressions().get(i).toString()); - } - } - return stringBuilder.append(')').toString(); - } -} diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctExecutorFactory.java b/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctExecutorFactory.java index 4a89147c05..5a3e052c15 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctExecutorFactory.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctExecutorFactory.java @@ -24,7 +24,6 @@ import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.request.context.OrderByExpressionContext; import org.apache.pinot.core.operator.BaseProjectOperator; import org.apache.pinot.core.operator.ColumnContext; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.dictionary.DictionaryBasedMultiColumnDistinctOnlyExecutor; import org.apache.pinot.core.query.distinct.dictionary.DictionaryBasedMultiColumnDistinctOrderByExecutor; import org.apache.pinot.core.query.distinct.dictionary.DictionaryBasedSingleColumnDistinctOnlyExecutor; @@ -44,6 +43,7 @@ import org.apache.pinot.core.query.distinct.raw.RawLongSingleColumnDistinctOrder import org.apache.pinot.core.query.distinct.raw.RawMultiColumnDistinctExecutor; import org.apache.pinot.core.query.distinct.raw.RawStringSingleColumnDistinctOnlyExecutor; import org.apache.pinot.core.query.distinct.raw.RawStringSingleColumnDistinctOrderByExecutor; +import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.segment.spi.index.reader.Dictionary; import org.apache.pinot.spi.data.FieldSpec.DataType; @@ -58,15 +58,16 @@ public class DistinctExecutorFactory { /** * Returns the {@link DistinctExecutor} for the given distinct query. */ - public static DistinctExecutor getDistinctExecutor(DistinctAggregationFunction distinctAggregationFunction, - BaseProjectOperator<?> projectOperator, boolean nullHandlingEnabled) { - List<ExpressionContext> expressions = distinctAggregationFunction.getInputExpressions(); - List<OrderByExpressionContext> orderByExpressions = distinctAggregationFunction.getOrderByExpressions(); - int limit = distinctAggregationFunction.getLimit(); + public static DistinctExecutor getDistinctExecutor(BaseProjectOperator<?> projectOperator, + QueryContext queryContext) { + List<ExpressionContext> expressions = queryContext.getSelectExpressions(); + List<OrderByExpressionContext> orderByExpressions = queryContext.getOrderByExpressions(); + int limit = queryContext.getLimit(); if (orderByExpressions == null) { - return getDistinctOnlyExecutor(expressions, limit, projectOperator, nullHandlingEnabled); + return getDistinctOnlyExecutor(expressions, limit, projectOperator, queryContext.isNullHandlingEnabled()); } else { - return getDistinctOrderByExecutor(expressions, orderByExpressions, limit, projectOperator, nullHandlingEnabled); + return getDistinctOrderByExecutor(expressions, orderByExpressions, limit, projectOperator, + queryContext.isNullHandlingEnabled()); } } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/BaseGapfillProcessor.java b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/BaseGapfillProcessor.java index b7da1d674f..25106858ea 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/BaseGapfillProcessor.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/BaseGapfillProcessor.java @@ -201,7 +201,7 @@ abstract class BaseGapfillProcessor { } else { FunctionContext functionContext = expressionContext.getFunction(); AggregationFunction aggregationFunction = - AggregationFunctionFactory.getAggregationFunction(functionContext, _queryContext); + AggregationFunctionFactory.getAggregationFunction(functionContext, _queryContext.isNullHandlingEnabled()); columnDataTypes[i] = aggregationFunction.getFinalResultColumnType(); columnNames[i] = functionContext.toString(); } @@ -222,8 +222,8 @@ abstract class BaseGapfillProcessor { return epoch / sz * sz; } - protected List<Object[]> gapFillAndAggregate( - List<Object[]> rows, DataSchema dataSchema, DataSchema resultTableSchema) { + protected List<Object[]> gapFillAndAggregate(List<Object[]> rows, DataSchema dataSchema, + DataSchema resultTableSchema) { throw new UnsupportedOperationException("Not supported"); } } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/DistinctDataTableReducer.java b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/DistinctDataTableReducer.java index d7bc3574df..5adc021bba 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/DistinctDataTableReducer.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/DistinctDataTableReducer.java @@ -27,13 +27,13 @@ import java.util.Map; import org.apache.pinot.common.CustomObject; import org.apache.pinot.common.datatable.DataTable; import org.apache.pinot.common.metrics.BrokerMetrics; +import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.response.broker.BrokerResponseNative; import org.apache.pinot.common.response.broker.ResultTable; import org.apache.pinot.common.utils.DataSchema; import org.apache.pinot.common.utils.DataSchema.ColumnDataType; import org.apache.pinot.core.common.ObjectSerDeUtils; import org.apache.pinot.core.data.table.Record; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.DistinctTable; import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.core.query.selection.SelectionOperatorUtils; @@ -46,11 +46,9 @@ import org.roaringbitmap.RoaringBitmap; * Helper class to reduce data tables and set results of distinct query into the BrokerResponseNative */ public class DistinctDataTableReducer implements DataTableReducer { - private final DistinctAggregationFunction _distinctAggregationFunction; private final QueryContext _queryContext; - DistinctDataTableReducer(DistinctAggregationFunction distinctAggregationFunction, QueryContext queryContext) { - _distinctAggregationFunction = distinctAggregationFunction; + DistinctDataTableReducer(QueryContext queryContext) { _queryContext = queryContext; } @@ -115,18 +113,21 @@ public class DistinctDataTableReducer implements DataTableReducer { // All the DistinctTables are empty, construct an empty response // TODO: This returns schema with all STRING data types. // There's no way currently to get the data types of the distinct columns for empty results - String[] columns = _distinctAggregationFunction.getColumns(); - - int numColumns = columns.length; - ColumnDataType[] columnDataTypes = new ColumnDataType[numColumns]; + List<ExpressionContext> expressions = _queryContext.getSelectExpressions(); + int numExpressions = expressions.size(); + String[] columns = new String[numExpressions]; + for (int i = 0; i < numExpressions; i++) { + columns[i] = expressions.get(i).toString(); + } + ColumnDataType[] columnDataTypes = new ColumnDataType[numExpressions]; Arrays.fill(columnDataTypes, ColumnDataType.STRING); brokerResponseNative.setResultTable( new ResultTable(new DataSchema(columns, columnDataTypes), Collections.emptyList())); } else { // Construct a main DistinctTable and merge all non-empty DistinctTables into it - DistinctTable mainDistinctTable = new DistinctTable(nonEmptyDistinctTables.get(0).getDataSchema(), - _distinctAggregationFunction.getOrderByExpressions(), _distinctAggregationFunction.getLimit(), - _queryContext.isNullHandlingEnabled()); + DistinctTable mainDistinctTable = + new DistinctTable(nonEmptyDistinctTables.get(0).getDataSchema(), _queryContext.getOrderByExpressions(), + _queryContext.getLimit(), _queryContext.isNullHandlingEnabled()); for (DistinctTable distinctTable : nonEmptyDistinctTables) { mainDistinctTable.mergeTable(distinctTable); } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/GapfillProcessor.java b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/GapfillProcessor.java index 9523ea4e65..9b14c51700 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/GapfillProcessor.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/GapfillProcessor.java @@ -280,7 +280,7 @@ public class GapfillProcessor extends BaseGapfillProcessor { if (expressionContext.getType() == ExpressionContext.Type.FUNCTION) { FunctionContext functionContext = expressionContext.getFunction(); AggregationFunction aggregationFunction = - AggregationFunctionFactory.getAggregationFunction(functionContext, _queryContext); + AggregationFunctionFactory.getAggregationFunction(functionContext, _queryContext.isNullHandlingEnabled()); GroupByResultHolder groupByResultHolder = aggregationFunction.createGroupByResultHolder(groupKeyIndexes.size(), groupKeyIndexes.size()); if (aggregationFunction instanceof CountAggregationFunction) { diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/ResultReducerFactory.java b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/ResultReducerFactory.java index 529cad24db..24d991d4b4 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/ResultReducerFactory.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/reduce/ResultReducerFactory.java @@ -18,17 +18,13 @@ */ package org.apache.pinot.core.query.reduce; -import org.apache.pinot.core.query.aggregation.function.AggregationFunction; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.request.context.QueryContext; import org.apache.pinot.core.query.request.context.utils.QueryContextUtils; -import org.apache.pinot.segment.spi.AggregationFunctionType; /** * Factory class to construct the right result reducer based on the query context. */ -@SuppressWarnings("rawtypes") public final class ResultReducerFactory { private ResultReducerFactory() { } @@ -40,26 +36,18 @@ public final class ResultReducerFactory { if (queryContext.isExplain()) { return new ExplainPlanDataTableReducer(queryContext); } - - AggregationFunction[] aggregationFunctions = queryContext.getAggregationFunctions(); - if (aggregationFunctions == null) { - // Selection query + if (QueryContextUtils.isSelectionQuery(queryContext)) { return new SelectionDataTableReducer(queryContext); - } else { - // Aggregation query + } + if (QueryContextUtils.isAggregationQuery(queryContext)) { if (queryContext.getGroupByExpressions() == null) { - // Aggregation only query - if (aggregationFunctions.length == 1 && aggregationFunctions[0].getType() == AggregationFunctionType.DISTINCT) { - // Distinct query - return new DistinctDataTableReducer((DistinctAggregationFunction) aggregationFunctions[0], queryContext); - } else { - return new AggregationDataTableReducer(queryContext); - } + return new AggregationDataTableReducer(queryContext); } else { - // Aggregation group-by query return new GroupByDataTableReducer(queryContext); } } + assert QueryContextUtils.isDistinctQuery(queryContext); + return new DistinctDataTableReducer(queryContext); } public static StreamingReducer getStreamingReducer(QueryContext queryContext) { diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/QueryContext.java b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/QueryContext.java index fcc97dd6fd..5d5e9a3718 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/QueryContext.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/QueryContext.java @@ -73,6 +73,7 @@ public class QueryContext { private final String _tableName; private final QueryContext _subquery; private final List<ExpressionContext> _selectExpressions; + private final boolean _distinct; private final List<String> _aliasList; private final FilterContext _filter; private final List<ExpressionContext> _groupByExpressions; @@ -124,14 +125,15 @@ public class QueryContext { private boolean _serverReturnFinalResult; private QueryContext(@Nullable String tableName, @Nullable QueryContext subquery, - List<ExpressionContext> selectExpressions, List<String> aliasList, @Nullable FilterContext filter, - @Nullable List<ExpressionContext> groupByExpressions, @Nullable FilterContext havingFilter, - @Nullable List<OrderByExpressionContext> orderByExpressions, int limit, int offset, - Map<String, String> queryOptions, @Nullable Map<ExpressionContext, ExpressionContext> expressionOverrideHints, - boolean explain) { + List<ExpressionContext> selectExpressions, boolean distinct, List<String> aliasList, + @Nullable FilterContext filter, @Nullable List<ExpressionContext> groupByExpressions, + @Nullable FilterContext havingFilter, @Nullable List<OrderByExpressionContext> orderByExpressions, int limit, + int offset, Map<String, String> queryOptions, + @Nullable Map<ExpressionContext, ExpressionContext> expressionOverrideHints, boolean explain) { _tableName = tableName; _subquery = subquery; _selectExpressions = selectExpressions; + _distinct = distinct; _aliasList = Collections.unmodifiableList(aliasList); _filter = filter; _groupByExpressions = groupByExpressions; @@ -167,6 +169,13 @@ public class QueryContext { return _selectExpressions; } + /** + * Returns whether the query is a DISTINCT query. + */ + public boolean isDistinct() { + return _distinct; + } + /** * Returns an unmodifiable list from the expression to its alias. */ @@ -413,9 +422,9 @@ public class QueryContext { @Override public String toString() { return "QueryContext{" + "_tableName='" + _tableName + '\'' + ", _subquery=" + _subquery + ", _selectExpressions=" - + _selectExpressions + ", _aliasList=" + _aliasList + ", _filter=" + _filter + ", _groupByExpressions=" - + _groupByExpressions + ", _havingFilter=" + _havingFilter + ", _orderByExpressions=" + _orderByExpressions - + ", _limit=" + _limit + ", _offset=" + _offset + ", _queryOptions=" + _queryOptions + + _selectExpressions + ", _distinct=" + _distinct + ", _aliasList=" + _aliasList + ", _filter=" + _filter + + ", _groupByExpressions=" + _groupByExpressions + ", _havingFilter=" + _havingFilter + ", _orderByExpressions=" + + _orderByExpressions + ", _limit=" + _limit + ", _offset=" + _offset + ", _queryOptions=" + _queryOptions + ", _expressionOverrideHints=" + _expressionOverrideHints + ", _explain=" + _explain + '}'; } @@ -423,6 +432,7 @@ public class QueryContext { private String _tableName; private QueryContext _subquery; private List<ExpressionContext> _selectExpressions; + private boolean _distinct; private List<String> _aliasList; private FilterContext _filter; private List<ExpressionContext> _groupByExpressions; @@ -450,6 +460,11 @@ public class QueryContext { return this; } + public Builder setDistinct(boolean distinct) { + _distinct = distinct; + return this; + } + public Builder setAliasList(List<String> aliasList) { _aliasList = aliasList; return this; @@ -507,8 +522,9 @@ public class QueryContext { _queryOptions = Collections.emptyMap(); } QueryContext queryContext = - new QueryContext(_tableName, _subquery, _selectExpressions, _aliasList, _filter, _groupByExpressions, - _havingFilter, _orderByExpressions, _limit, _offset, _queryOptions, _expressionOverrideHints, _explain); + new QueryContext(_tableName, _subquery, _selectExpressions, _distinct, _aliasList, _filter, + _groupByExpressions, _havingFilter, _orderByExpressions, _limit, _offset, _queryOptions, + _expressionOverrideHints, _explain); queryContext.setNullHandlingEnabled(QueryOptionsUtils.isNullHandlingEnabled(_queryOptions)); queryContext.setServerReturnFinalResult(QueryOptionsUtils.isServerReturnFinalResult(_queryOptions)); @@ -540,7 +556,7 @@ public class QueryContext { } int functionIndex = filteredAggregationFunctions.size(); AggregationFunction aggregationFunction = - AggregationFunctionFactory.getAggregationFunction(aggregation, queryContext); + AggregationFunctionFactory.getAggregationFunction(aggregation, queryContext._nullHandlingEnabled); filteredAggregationFunctions.add(Pair.of(aggregationFunction, filter)); filteredAggregationsIndexMap.put(Pair.of(aggregation, filter), functionIndex); } @@ -561,7 +577,7 @@ public class QueryContext { FilterContext filter = pair.getRight(); int functionIndex = filteredAggregationFunctions.size(); AggregationFunction aggregationFunction = - AggregationFunctionFactory.getAggregationFunction(aggregation, queryContext); + AggregationFunctionFactory.getAggregationFunction(aggregation, queryContext._nullHandlingEnabled); filteredAggregationFunctions.add(Pair.of(aggregationFunction, filter)); filteredAggregationsIndexMap.put(Pair.of(aggregation, filter), functionIndex); } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java index f2b08eafaa..7d16ed1cc4 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java @@ -28,7 +28,6 @@ import javax.annotation.Nullable; import org.apache.commons.collections.CollectionUtils; import org.apache.pinot.common.request.DataSource; import org.apache.pinot.common.request.Expression; -import org.apache.pinot.common.request.ExpressionType; import org.apache.pinot.common.request.Function; import org.apache.pinot.common.request.PinotQuery; import org.apache.pinot.common.request.context.ExpressionContext; @@ -65,40 +64,29 @@ public class QueryContextConverterUtils { // SELECT List<ExpressionContext> selectExpressions; + boolean distinct = false; List<Expression> selectList = pinotQuery.getSelectList(); + // Handle DISTINCT + if (selectList.size() == 1) { + Function function = selectList.get(0).getFunctionCall(); + if (function != null && function.getOperator().equals("distinct")) { + distinct = true; + selectList = function.getOperands(); + } + } List<String> aliasList = new ArrayList<>(selectList.size()); selectExpressions = new ArrayList<>(selectList.size()); for (Expression thriftExpression : selectList) { // Handle alias - Expression expressionWithoutAlias = thriftExpression; - if (thriftExpression.getType() == ExpressionType.FUNCTION) { - Function function = thriftExpression.getFunctionCall(); + Function function = thriftExpression.getFunctionCall(); + Expression expressionWithoutAlias; + if (function != null && function.getOperator().equals("as")) { List<Expression> operands = function.getOperands(); - switch (function.getOperator().toUpperCase()) { - case "AS": - expressionWithoutAlias = operands.get(0); - aliasList.add(operands.get(1).getIdentifier().getName()); - break; - case "DISTINCT": - int numOperands = operands.size(); - for (int i = 0; i < numOperands; i++) { - Expression operand = operands.get(i); - Function operandFunction = operand.getFunctionCall(); - if (operandFunction != null && operandFunction.getOperator().equalsIgnoreCase("AS")) { - operands.set(i, operandFunction.getOperands().get(0)); - aliasList.add(operandFunction.getOperands().get(1).getIdentifier().getName()); - } else { - aliasList.add(null); - } - } - break; - default: - // Add null as a placeholder for alias. - aliasList.add(null); - break; - } + expressionWithoutAlias = operands.get(0); + aliasList.add(operands.get(1).getIdentifier().getName()); } else { - // Add null as a placeholder for alias. + expressionWithoutAlias = thriftExpression; + // Add null as a placeholder for alias aliasList.add(null); } selectExpressions.add(RequestContextUtils.getExpression(expressionWithoutAlias)); @@ -161,7 +149,7 @@ public class QueryContextConverterUtils { } return new QueryContext.Builder().setTableName(tableName).setSubquery(subquery) - .setSelectExpressions(selectExpressions).setAliasList(aliasList).setFilter(filter) + .setSelectExpressions(selectExpressions).setDistinct(distinct).setAliasList(aliasList).setFilter(filter) .setGroupByExpressions(groupByExpressions).setOrderByExpressions(orderByExpressions) .setHavingFilter(havingFilter).setLimit(pinotQuery.getLimit()).setOffset(pinotQuery.getOffset()) .setQueryOptions(pinotQuery.getQueryOptions()).setExpressionOverrideHints(expressionContextOverrideHints) diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextUtils.java b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextUtils.java index 7a468c438b..b5beee1a40 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextUtils.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextUtils.java @@ -24,12 +24,9 @@ import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.request.context.FilterContext; import org.apache.pinot.common.request.context.FunctionContext; import org.apache.pinot.common.request.context.OrderByExpressionContext; -import org.apache.pinot.core.query.aggregation.function.AggregationFunction; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.request.context.QueryContext; -@SuppressWarnings("rawtypes") public class QueryContextUtils { private QueryContextUtils() { } @@ -38,7 +35,7 @@ public class QueryContextUtils { * Returns {@code true} if the given query is a selection query, {@code false} otherwise. */ public static boolean isSelectionQuery(QueryContext query) { - return query.getAggregationFunctions() == null; + return !query.isDistinct() && query.getAggregationFunctions() == null; } /** @@ -47,25 +44,21 @@ public class QueryContextUtils { * Selection-only query at this moment means selection query without order-by. */ public static boolean isSelectionOnlyQuery(QueryContext query) { - return query.getAggregationFunctions() == null && query.getOrderByExpressions() == null; + return isSelectionQuery(query) && query.getOrderByExpressions() == null; } /** * Returns {@code true} if the given query is an aggregation query, {@code false} otherwise. */ public static boolean isAggregationQuery(QueryContext query) { - AggregationFunction[] aggregationFunctions = query.getAggregationFunctions(); - return aggregationFunctions != null && (aggregationFunctions.length != 1 - || !(aggregationFunctions[0] instanceof DistinctAggregationFunction)); + return query.getAggregationFunctions() != null; } /** * Returns {@code true} if the given query is a distinct query, {@code false} otherwise. */ public static boolean isDistinctQuery(QueryContext query) { - AggregationFunction[] aggregationFunctions = query.getAggregationFunctions(); - return aggregationFunctions != null && aggregationFunctions.length == 1 - && aggregationFunctions[0] instanceof DistinctAggregationFunction; + return query.isDistinct(); } /** Collect aggregation functions (except for the ones in filter). */ @@ -96,7 +89,6 @@ public class QueryContextUtils { } } - /** Collect aggregation functions from an ExpressionContext. */ public static void collectPostAggregations(ExpressionContext expression, Set<String> postAggregations) { FunctionContext function = expression.getFunction(); diff --git a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactoryTest.java b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactoryTest.java index a4eaa1f991..de8abca960 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactoryTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/query/aggregation/function/AggregationFunctionFactoryTest.java @@ -18,12 +18,8 @@ */ package org.apache.pinot.core.query.aggregation.function; -import java.util.Arrays; -import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.request.context.FunctionContext; import org.apache.pinot.common.request.context.RequestContextUtils; -import org.apache.pinot.core.query.request.context.QueryContext; -import org.apache.pinot.core.query.request.context.utils.QueryContextConverterUtils; import org.apache.pinot.segment.spi.AggregationFunctionType; import org.testng.annotations.Test; @@ -35,416 +31,413 @@ import static org.testng.Assert.assertTrue; public class AggregationFunctionFactoryTest { private static final String ARGUMENT_COLUMN = "(column)"; private static final String ARGUMENT_STAR = "(*)"; - private static final QueryContext DUMMY_QUERY_CONTEXT = - QueryContextConverterUtils.getQueryContext("SELECT * FROM testTable"); @Test public void testGetAggregationFunction() { FunctionContext function = getFunction("CoUnT", ARGUMENT_STAR); - AggregationFunction aggregationFunction = - AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + AggregationFunction aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof CountAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.COUNT); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MiN"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof MinAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MIN); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MaX"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof MaxAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MAX); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("SuM"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof SumAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.SUM); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("SuMPreCIsiON"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof SumPrecisionAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.SUMPRECISION); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("AvG"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof AvgAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.AVG); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MoDe"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof ModeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MODE); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'BOOLEAN')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FirstIntValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'INT')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FirstIntValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'LONG')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FirstLongValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'FLOAT')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FirstFloatValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'DOUBLE')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FirstDoubleValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FiRsTwItHtImE", "(column,timeColumn,'STRING')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FirstStringValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FIRSTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("LaStWiThTiMe", "(column,timeColumn,'BOOLEAN')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof LastIntValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("LaStWiThTiMe", "(column,timeColumn,'INT')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof LastIntValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("LaStWiThTiMe", "(column,timeColumn,'LONG')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof LastLongValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("LaStWiThTiMe", "(column,timeColumn,'FLOAT')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof LastFloatValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("LaStWiThTiMe", "(column,timeColumn,'DOUBLE')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof LastDoubleValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("LaStWiThTiMe", "(column,timeColumn,'STRING')"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof LastStringValueWithTimeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.LASTWITHTIME); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MiNmAxRaNgE"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof MinMaxRangeAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MINMAXRANGE); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCtCoUnT"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNT); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCtCoUnThLl"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountHLLAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLL); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCtCoUnTrAwHlL"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountRawHLLAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTRAWHLL); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("FaStHlL"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FastHLLAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.FASTHLL); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLe5"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILE); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeEsT50"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileEstAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEEST); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeRaWEsT50"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawEstAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWEST); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeTdIgEsT99"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeRaWTdIgEsT99"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLe", "(column, 5)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILE); assertEquals(aggregationFunction.getResultColumnName(), "percentile(column, 5.0)"); function = getFunction("PeRcEnTiLe", "(column, 5.5)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILE); assertEquals(aggregationFunction.getResultColumnName(), "percentile(column, 5.5)"); function = getFunction("PeRcEnTiLeEsT", "(column, 50)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileEstAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEEST); assertEquals(aggregationFunction.getResultColumnName(), "percentileest(column, 50.0)"); function = getFunction("PeRcEnTiLeRaWeSt", "(column, 50)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawEstAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWEST); assertEquals(aggregationFunction.getResultColumnName(), "percentilerawest(column, 50.0)"); function = getFunction("PeRcEnTiLeEsT", "(column, 55.555)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileEstAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEEST); assertEquals(aggregationFunction.getResultColumnName(), "percentileest(column, 55.555)"); function = getFunction("PeRcEnTiLeRaWeSt", "(column, 55.555)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawEstAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWEST); assertEquals(aggregationFunction.getResultColumnName(), "percentilerawest(column, 55.555)"); function = getFunction("PeRcEnTiLeTdIgEsT", "(column, 99)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigest(column, 99.0)"); function = getFunction("PeRcEnTiLeTdIgEsT", "(column, 99.9999)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigest(column, 99.9999)"); function = getFunction("PeRcEnTiLeTdIgEsT", "(column, 99.9999, 1000)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigest(column, 99.9999, 1000)"); function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.0)"); function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99.9999)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.9999)"); function = getFunction("PeRcEntiLEkll", "(column, 99.9999)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileKLLAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEKLL); assertEquals(aggregationFunction.getResultColumnName(), "percentilekll(column, 99.9999)"); function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99.9999, 500)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.9999, 500)"); function = getFunction("PeRcEnTiLeRaWtDiGeSt", "(column, 99.9999, 100)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileRawTDigestAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILERAWTDIGEST); assertEquals(aggregationFunction.getResultColumnName(), "percentilerawtdigest(column, 99.9999)"); function = getFunction("CoUnTmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof CountMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.COUNTMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MiNmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof MinMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MINMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MaXmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof MaxMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MAXMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("SuMmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof SumMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.SUMMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("AvGmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof AvgMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.AVGMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("AvG_mV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof AvgMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.AVGMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("MiNmAxRaNgEmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof MinMaxRangeMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.MINMAXRANGEMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCtCoUnTmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCtCoUnThLlMv"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountHLLMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLLMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCt_CoUnT_hLl_Mv"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountHLLMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTHLLMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("DiStInCtCoUnTrAwHlLmV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof DistinctCountRawHLLMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCTCOUNTRAWHLLMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLe10Mv"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeEsT90mV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileEstMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEESTMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeTdIgEsT95mV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLe_TdIgEsT_95_mV"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("PeRcEnTiLeMv", "(column, 10)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEMV); assertEquals(aggregationFunction.getResultColumnName(), "percentilemv(column, 10.0)"); function = getFunction("PeRcEnTiLeEsTmV", "(column, 90)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileEstMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILEESTMV); assertEquals(aggregationFunction.getResultColumnName(), "percentileestmv(column, 90.0)"); function = getFunction("PeRcEnTiLeTdIgEsTmV", "(column, 95)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0)"); function = getFunction("PeRcEnTiLeTdIgEsTmV", "(column, 95, 1000)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0, 1000)"); function = getFunction("PeRcEnTiLe_TdIgEsT_mV", "(column, 95)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0)"); function = getFunction("PeRcEnTiLe_TdIgEsT_mV", "(column, 95, 200)"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof PercentileTDigestMVAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.PERCENTILETDIGESTMV); assertEquals(aggregationFunction.getResultColumnName(), "percentiletdigestmv(column, 95.0, 200)"); function = getFunction("bool_and"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof BooleanAndAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.BOOLAND); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("bool_or"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof BooleanOrAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.BOOLOR); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("skewness"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FourthMomentAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.SKEWNESS); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); function = getFunction("kurtosis"); - aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, DUMMY_QUERY_CONTEXT); + aggregationFunction = AggregationFunctionFactory.getAggregationFunction(function, false); assertTrue(aggregationFunction instanceof FourthMomentAggregationFunction); assertEquals(aggregationFunction.getType(), AggregationFunctionType.KURTOSIS); assertEquals(aggregationFunction.getResultColumnName(), function.toString()); @@ -457,18 +450,4 @@ public class AggregationFunctionFactoryTest { private FunctionContext getFunction(String functionName, String args) { return RequestContextUtils.getExpression(functionName + args).getFunction(); } - - @Test - public void testAggregationFunctionWithMultipleArgs() { - QueryContext queryContext = - QueryContextConverterUtils.getQueryContext("SELECT DISTINCT column1, column2, column3 FROM testTable"); - AggregationFunction aggregationFunction = - AggregationFunctionFactory.getAggregationFunction(queryContext.getSelectExpressions().get(0).getFunction(), - queryContext); - assertTrue(aggregationFunction instanceof DistinctAggregationFunction); - assertEquals(aggregationFunction.getType(), AggregationFunctionType.DISTINCT); - assertEquals(aggregationFunction.getInputExpressions(), - Arrays.asList(ExpressionContext.forIdentifier("column1"), ExpressionContext.forIdentifier("column2"), - ExpressionContext.forIdentifier("column3"))); - } } diff --git a/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java b/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java index 817a03c9a5..f430c2abf4 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java @@ -67,6 +67,7 @@ public class BrokerRequestToQueryContextConverterTest { assertEquals(selectExpressions.size(), 1); assertEquals(selectExpressions.get(0), ExpressionContext.forIdentifier("*")); assertEquals(selectExpressions.get(0).toString(), "*"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); assertNull(queryContext.getGroupByExpressions()); @@ -91,6 +92,7 @@ public class BrokerRequestToQueryContextConverterTest { new FunctionContext(FunctionContext.Type.AGGREGATION, "count", Collections.singletonList(ExpressionContext.forIdentifier("*"))))); assertEquals(selectExpressions.get(0).toString(), "count(*)"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); assertNull(queryContext.getGroupByExpressions()); @@ -115,6 +117,7 @@ public class BrokerRequestToQueryContextConverterTest { assertEquals(selectExpressions.get(0).toString(), "foo"); assertEquals(selectExpressions.get(1), ExpressionContext.forIdentifier("bar")); assertEquals(selectExpressions.get(1).toString(), "bar"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); List<OrderByExpressionContext> orderByExpressions = queryContext.getOrderByExpressions(); @@ -139,12 +142,14 @@ public class BrokerRequestToQueryContextConverterTest { QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query); assertEquals(queryContext.getTableName(), "testTable"); List<ExpressionContext> selectExpressions = queryContext.getSelectExpressions(); - assertEquals(selectExpressions.size(), 1); - assertEquals(selectExpressions.get(0), ExpressionContext.forFunction( - new FunctionContext(FunctionContext.Type.AGGREGATION, "distinct", - Arrays.asList(ExpressionContext.forIdentifier("foo"), ExpressionContext.forIdentifier("bar"), - ExpressionContext.forIdentifier("foobar"))))); - assertEquals(selectExpressions.get(0).toString(), "distinct(foo,bar,foobar)"); + assertEquals(selectExpressions.size(), 3); + assertEquals(selectExpressions.get(0), ExpressionContext.forIdentifier("foo")); + assertEquals(selectExpressions.get(0).toString(), "foo"); + assertEquals(selectExpressions.get(1), ExpressionContext.forIdentifier("bar")); + assertEquals(selectExpressions.get(1).toString(), "bar"); + assertEquals(selectExpressions.get(2), ExpressionContext.forIdentifier("foobar")); + assertEquals(selectExpressions.get(2).toString(), "foobar"); + assertTrue(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); assertNull(queryContext.getGroupByExpressions()); @@ -186,6 +191,7 @@ public class BrokerRequestToQueryContextConverterTest { Arrays.asList(ExpressionContext.forLiteralContext(FieldSpec.DataType.STRING, "456"), ExpressionContext.forIdentifier("foobar"))))); assertEquals(selectExpressions.get(1).toString(), "sub('456',foobar)"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); assertNull(queryContext.getGroupByExpressions()); @@ -225,22 +231,19 @@ public class BrokerRequestToQueryContextConverterTest { QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query); assertEquals(queryContext.getTableName(), "testTable"); List<ExpressionContext> selectExpressions = queryContext.getSelectExpressions(); - int numSelectExpressions = selectExpressions.size(); - assertTrue(numSelectExpressions == 1 || numSelectExpressions == 3); - ExpressionContext aggregationExpression = selectExpressions.get(numSelectExpressions - 1); - assertEquals(aggregationExpression, ExpressionContext.forFunction( + assertEquals(selectExpressions.size(), 3); + assertEquals(selectExpressions.get(0), ExpressionContext.forFunction( + new FunctionContext(FunctionContext.Type.TRANSFORM, "sub", + Arrays.asList(ExpressionContext.forIdentifier("foo"), ExpressionContext.forIdentifier("bar"))))); + assertEquals(selectExpressions.get(0).toString(), "sub(foo,bar)"); + assertEquals(selectExpressions.get(1), ExpressionContext.forIdentifier("bar")); + assertEquals(selectExpressions.get(1).toString(), "bar"); + assertEquals(selectExpressions.get(2), ExpressionContext.forFunction( new FunctionContext(FunctionContext.Type.AGGREGATION, "sum", Collections.singletonList( ExpressionContext.forFunction(new FunctionContext(FunctionContext.Type.TRANSFORM, "add", Arrays.asList(ExpressionContext.forIdentifier("foo"), ExpressionContext.forIdentifier("bar")))))))); - assertEquals(aggregationExpression.toString(), "sum(add(foo,bar))"); - if (numSelectExpressions == 3) { - assertEquals(selectExpressions.get(0), ExpressionContext.forFunction( - new FunctionContext(FunctionContext.Type.TRANSFORM, "sub", - Arrays.asList(ExpressionContext.forIdentifier("foo"), ExpressionContext.forIdentifier("bar"))))); - assertEquals(selectExpressions.get(0).toString(), "sub(foo,bar)"); - assertEquals(selectExpressions.get(1), ExpressionContext.forIdentifier("bar")); - assertEquals(selectExpressions.get(1).toString(), "bar"); - } + assertEquals(selectExpressions.get(2).toString(), "sum(add(foo,bar))"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); List<ExpressionContext> groupByExpressions = queryContext.getGroupByExpressions(); @@ -284,6 +287,7 @@ public class BrokerRequestToQueryContextConverterTest { assertEquals(selectExpressions.size(), 1); assertEquals(selectExpressions.get(0), ExpressionContext.forIdentifier("*")); assertEquals(selectExpressions.get(0).toString(), "*"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); FilterContext filter = queryContext.getFilter(); assertNotNull(filter); @@ -328,6 +332,7 @@ public class BrokerRequestToQueryContextConverterTest { assertEquals(selectExpressions.get(0).toString(), "sum(foo)"); assertEquals(selectExpressions.get(1), ExpressionContext.forIdentifier("bar")); assertEquals(selectExpressions.get(1).toString(), "bar"); + assertFalse(queryContext.isDistinct()); List<String> aliasList = queryContext.getAliasList(); assertEquals(aliasList.size(), 2); assertEquals(aliasList.get(0), "a"); @@ -371,6 +376,7 @@ public class BrokerRequestToQueryContextConverterTest { assertEquals(selectExpressions.get(0).toString(), "sum(foo)"); assertEquals(selectExpressions.get(1), ExpressionContext.forIdentifier("bar")); assertEquals(selectExpressions.get(1).toString(), "bar"); + assertFalse(queryContext.isDistinct()); assertEquals(getAliasCount(queryContext.getAliasList()), 0); assertNull(queryContext.getFilter()); List<ExpressionContext> groupByExpressions = queryContext.getGroupByExpressions(); diff --git a/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java b/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java index 34dc84805f..9bd4d39e35 100644 --- a/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java +++ b/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java @@ -145,8 +145,7 @@ public class CalciteRexExpressionParser { private static Expression convertDistinctAndSelectListToFunctionExpression(RexExpression.FunctionCall rexCall, PinotQuery pinotQuery) { - String functionName = AggregationFunctionType.DISTINCT.getName(); - Expression functionExpression = getFunctionExpression(functionName); + Expression functionExpression = getFunctionExpression("distinct"); for (RexExpression node : rexCall.getFunctionOperands()) { Expression columnExpression = toExpression(node, pinotQuery); if (columnExpression.getType() == ExpressionType.IDENTIFIER && columnExpression.getIdentifier().getName() diff --git a/pinot-query-runtime/src/test/java/org/apache/pinot/query/runtime/operator/LeafStageTransferableBlockOperatorTest.java b/pinot-query-runtime/src/test/java/org/apache/pinot/query/runtime/operator/LeafStageTransferableBlockOperatorTest.java index dc2d2dcb75..2c3b1704da 100644 --- a/pinot-query-runtime/src/test/java/org/apache/pinot/query/runtime/operator/LeafStageTransferableBlockOperatorTest.java +++ b/pinot-query-runtime/src/test/java/org/apache/pinot/query/runtime/operator/LeafStageTransferableBlockOperatorTest.java @@ -33,7 +33,6 @@ import org.apache.pinot.core.operator.blocks.results.AggregationResultsBlock; import org.apache.pinot.core.operator.blocks.results.DistinctResultsBlock; import org.apache.pinot.core.operator.blocks.results.GroupByResultsBlock; import org.apache.pinot.core.operator.blocks.results.SelectionResultsBlock; -import org.apache.pinot.core.query.aggregation.function.DistinctAggregationFunction; import org.apache.pinot.core.query.distinct.DistinctTable; import org.apache.pinot.core.query.request.ServerQueryRequest; import org.apache.pinot.core.query.request.context.QueryContext; @@ -210,7 +209,7 @@ public class LeafStageTransferableBlockOperatorTest { DataSchema schema = new DataSchema(new String[]{"intCol", "strCol"}, new DataSchema.ColumnDataType[]{DataSchema.ColumnDataType.INT, DataSchema.ColumnDataType.STRING}); List<InstanceResponseBlock> resultsBlockList = Collections.singletonList(new InstanceResponseBlock( - new DistinctResultsBlock(mock(DistinctAggregationFunction.class), new DistinctTable(schema, + new DistinctResultsBlock(new DistinctTable(schema, Arrays.asList(new Record(new Object[]{1, "foo"}), new Record(new Object[]{2, "bar"})))), queryContext)); LeafStageTransferableBlockOperator operator = new LeafStageTransferableBlockOperator(OperatorTestUtil.getDefaultContext(), @@ -232,7 +231,7 @@ public class LeafStageTransferableBlockOperatorTest { DataSchema schema = new DataSchema(new String[]{"strCol", "intCol"}, new DataSchema.ColumnDataType[]{DataSchema.ColumnDataType.STRING, DataSchema.ColumnDataType.INT}); List<InstanceResponseBlock> resultsBlockList = Collections.singletonList(new InstanceResponseBlock( - new DistinctResultsBlock(mock(DistinctAggregationFunction.class), new DistinctTable(schema, + new DistinctResultsBlock(new DistinctTable(schema, Arrays.asList(new Record(new Object[]{"foo", 1}), new Record(new Object[]{"bar", 2})))), queryContext)); LeafStageTransferableBlockOperator operator = new LeafStageTransferableBlockOperator(OperatorTestUtil.getDefaultContext(), @@ -348,9 +347,9 @@ public class LeafStageTransferableBlockOperatorTest { new DataSchema.ColumnDataType[]{DataSchema.ColumnDataType.STRING, DataSchema.ColumnDataType.INT}); // When: - List<InstanceResponseBlock> responseBlockList = Collections.singletonList(new InstanceResponseBlock( - new DistinctResultsBlock(mock(DistinctAggregationFunction.class), - new DistinctTable(resultSchema, Collections.emptyList())), queryContext)); + List<InstanceResponseBlock> responseBlockList = Collections.singletonList( + new InstanceResponseBlock(new DistinctResultsBlock(new DistinctTable(resultSchema, Collections.emptyList())), + queryContext)); LeafStageTransferableBlockOperator operator = new LeafStageTransferableBlockOperator(OperatorTestUtil.getDefaultContext(), getStaticBlockProcessor(responseBlockList), getStaticServerQueryRequests(responseBlockList.size()), diff --git a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/AggregationFunctionType.java b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/AggregationFunctionType.java index 5201fdcd2b..a58e76f1f8 100644 --- a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/AggregationFunctionType.java +++ b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/AggregationFunctionType.java @@ -104,7 +104,6 @@ public enum AggregationFunctionType { PERCENTILERAWTDIGESTMV("percentileRawTDigestMV"), PERCENTILEKLLMV("percentileKLLMV"), PERCENTILERAWKLLMV("percentileRawKLLMV"), - DISTINCT("distinct"), // boolean aggregate functions BOOLAND("boolAnd"), --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org