You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by sh...@apache.org on 2018/06/14 09:28:39 UTC
[kylin] 04/10: KYLIN-3360 correct count(column)
This is an automated email from the ASF dual-hosted git repository.
shaofengshi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kylin.git
commit 1c9b6792dfc5714e936bc098d7b634bc8aa94f98
Author: Zhong <nj...@apache.org>
AuthorDate: Thu May 10 10:00:55 2018 +0800
KYLIN-3360 correct count(column)
---
.../apache/calcite/sql2rel/SqlToRelConverter.java | 2 +-
.../apache/kylin/query/relnode/ColumnRowType.java | 11 +++++
.../kylin/query/relnode/OLAPAggregateRel.java | 52 ++++++++++++++++++++--
.../apache/kylin/query/relnode/OLAPContext.java | 35 +++++++++++++++
4 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index fb5bb19..519a73b 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -4996,7 +4996,7 @@ public class SqlToRelConverter {
// special case for COUNT(*): delete the *
if (operand instanceof SqlIdentifier) {
SqlIdentifier id = (SqlIdentifier) operand;
- if (id.isStar() || isSimpleCount(call)) { /* OVERRIDE POINT */
+ if (id.isStar()) {
assert call.operandCount() == 1;
assert args.isEmpty();
break;
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/ColumnRowType.java b/query/src/main/java/org/apache/kylin/query/relnode/ColumnRowType.java
index 778d681..65a00e6 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/ColumnRowType.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/ColumnRowType.java
@@ -20,6 +20,7 @@ package org.apache.kylin.query.relnode;
import java.util.List;
+import org.apache.kylin.common.util.Pair;
import org.apache.kylin.metadata.expression.ColumnTupleExpression;
import org.apache.kylin.metadata.expression.NoneTupleExpression;
import org.apache.kylin.metadata.expression.TupleExpression;
@@ -70,6 +71,16 @@ public class ColumnRowType {
return -1;
}
+ public Pair<TblColRef, TupleExpression> replaceColumnByIndex(int index, TblColRef newColumn,
+ TupleExpression newTupleExpr) {
+ if (index < 0 || index >= columns.size()) {
+ return null;
+ }
+ TblColRef oldCol = columns.set(index, newColumn);
+ TupleExpression oldExpr = sourceColumns.set(index, newTupleExpr);
+ return new Pair<>(oldCol, oldExpr);
+ }
+
public TupleExpression getSourceColumnsByIndex(int i) {
TupleExpression result = null;
if (sourceColumns != null) {
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPAggregateRel.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPAggregateRel.java
index 2444daa..0eff905 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPAggregateRel.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPAggregateRel.java
@@ -47,6 +47,7 @@ import org.apache.calcite.schema.FunctionParameter;
import org.apache.calcite.schema.impl.AggregateFunctionImpl;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.fun.SqlCountAggFunction;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.fun.SqlSumAggFunction;
import org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction;
@@ -58,13 +59,18 @@ import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.validate.SqlUserDefinedAggFunction;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.Util;
+import org.apache.kylin.common.util.Pair;
import org.apache.kylin.measure.MeasureTypeFactory;
import org.apache.kylin.measure.ParamAsMeasureCount;
+import org.apache.kylin.metadata.expression.CaseTupleExpression;
import org.apache.kylin.metadata.expression.ColumnTupleExpression;
import org.apache.kylin.metadata.expression.ExpressionColCollector;
import org.apache.kylin.metadata.expression.ExpressionCountDistributor;
import org.apache.kylin.metadata.expression.NumberTupleExpression;
import org.apache.kylin.metadata.expression.TupleExpression;
+import org.apache.kylin.metadata.filter.ColumnTupleFilter;
+import org.apache.kylin.metadata.filter.CompareTupleFilter;
+import org.apache.kylin.metadata.filter.TupleFilter;
import org.apache.kylin.metadata.model.DynamicFunctionDesc;
import org.apache.kylin.metadata.model.FunctionDesc;
import org.apache.kylin.metadata.model.MeasureDesc;
@@ -130,6 +136,7 @@ public class OLAPAggregateRel extends Aggregate implements OLAPRel {
OLAPContext context;
ColumnRowType columnRowType;
private boolean afterAggregate;
+ private Map<Integer, AggregateCall> hackAggCalls;
private List<AggregateCall> rewriteAggCalls;
private List<TblColRef> groups;
private List<FunctionDesc> aggregations;
@@ -271,7 +278,9 @@ public class OLAPAggregateRel extends Aggregate implements OLAPRel {
void buildAggregations() {
ColumnRowType inputColumnRowType = ((OLAPRel) getInput()).getColumnRowType();
this.aggregations = Lists.newArrayList();
- for (AggregateCall aggCall : this.rewriteAggCalls) {
+ this.hackAggCalls = Maps.newHashMap();
+ for (int i = 0; i < this.rewriteAggCalls.size(); i++) {
+ AggregateCall aggCall = this.rewriteAggCalls.get(i);
ParameterDesc parameter = null;
List<Integer> argList = aggCall.getArgList();
// By default all args are included, UDFs can define their own in getParamAsMeasureCount method.
@@ -309,6 +318,30 @@ public class OLAPAggregateRel extends Aggregate implements OLAPRel {
this.aggregations.add(sumDynFunc);
continue;
}
+ } else if (aggCall.getAggregation() instanceof SqlCountAggFunction && !aggCall.isDistinct()) {
+ if (tupleExpr instanceof ColumnTupleExpression) {
+ TblColRef srcCol = ((ColumnTupleExpression) tupleExpr).getColumn();
+ if (this.context.belongToFactTable(srcCol)) {
+ tupleExpr = getCountColumnExpression(srcCol);
+
+ TblColRef column = TblColRef.newInnerColumn(tupleExpr.getDigest(),
+ TblColRef.InnerDataTypeEnum.LITERAL);
+
+ SumDynamicFunctionDesc sumDynFunc = new SumDynamicFunctionDesc(
+ ParameterDesc.newInstance(column), tupleExpr);
+
+ inputColumnRowType.replaceColumnByIndex(iRowIdx, column, tupleExpr);
+
+ AggregateCall newAggCall = AggregateCall.create(SqlStdOperatorTable.SUM, false,
+ aggCall.getArgList(), -1, aggCall.getType(), aggCall.getName());
+ this.hackAggCalls.put(i, newAggCall);
+
+ this.context.dynamicFields.put(column, aggCall.getType());
+
+ this.aggregations.add(sumDynFunc);
+ continue;
+ }
+ }
}
}
String expression = getAggrFuncName(aggCall);
@@ -337,9 +370,10 @@ public class OLAPAggregateRel extends Aggregate implements OLAPRel {
// only rewrite the innermost aggregation
if (needRewrite()) {
// rewrite the aggCalls
- this.rewriteAggCalls = new ArrayList<AggregateCall>(aggCalls.size());
+ this.rewriteAggCalls = Lists.newArrayListWithExpectedSize(aggCalls.size());
for (int i = 0; i < this.aggCalls.size(); i++) {
- AggregateCall aggCall = this.aggCalls.get(i);
+ AggregateCall aggCall = this.hackAggCalls.get(i) != null ? this.hackAggCalls.get(i)
+ : this.aggCalls.get(i);
FunctionDesc cubeFunc = this.context.aggregations.get(i);
// filter needn,t rewrite aggfunc
// if it's not a cube, then the "needRewriteField func" should not resort to any rewrite fields,
@@ -568,4 +602,16 @@ public class OLAPAggregateRel extends Aggregate implements OLAPRel {
return super.explainTerms(pw).item("ctx",
context == null ? "" : String.valueOf(context.id) + "@" + context.realization);
}
+
+ private TupleExpression getCountColumnExpression(TblColRef colRef) {
+ List<Pair<TupleFilter, TupleExpression>> whenList = Lists.newArrayListWithExpectedSize(1);
+ TupleFilter whenFilter = new CompareTupleFilter(TupleFilter.FilterOperatorEnum.ISNULL);
+ whenFilter.addChild(new ColumnTupleFilter(colRef));
+ whenList.add(new Pair<TupleFilter, TupleExpression>(whenFilter, new NumberTupleExpression(0)));
+
+ TupleExpression elseExpr = new ColumnTupleExpression(SumDynamicFunctionDesc.mockCntCol);
+ TupleExpression ret = new CaseTupleExpression(whenList, elseExpr);
+ ret.setDigest("_KY_COUNT(" + colRef.getName() + ")");
+ return ret;
+ }
}
diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
index 1132cd4..20533ad 100644
--- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
+++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPContext.java
@@ -41,7 +41,9 @@ import org.apache.kylin.metadata.model.FunctionDesc;
import org.apache.kylin.metadata.model.JoinDesc;
import org.apache.kylin.metadata.model.JoinsTree;
import org.apache.kylin.metadata.model.MeasureDesc;
+import org.apache.kylin.metadata.model.TableRef;
import org.apache.kylin.metadata.model.TblColRef;
+import org.apache.kylin.metadata.project.ProjectManager;
import org.apache.kylin.metadata.realization.IRealization;
import org.apache.kylin.metadata.realization.SQLDigest;
import org.apache.kylin.metadata.realization.SQLDigest.SQLCall;
@@ -52,6 +54,7 @@ import org.apache.kylin.storage.StorageContext;
import org.apache.kylin.storage.hybrid.HybridInstance;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
/**
*/
@@ -208,6 +211,38 @@ public class OLAPContext {
return false;
}
+ public boolean belongToFactTable(TblColRef tblColRef) {
+ if (!belongToContextTables(tblColRef)) {
+ return false;
+ }
+ KylinConfig kylinConfig = olapSchema.getConfig();
+ String projectName = olapSchema.getProjectName();
+ String factTableName = firstTableScan.getOlapTable().getTableName();
+ Set<IRealization> realizations = ProjectManager.getInstance(kylinConfig).getRealizationsByTable(projectName,
+ factTableName);
+ for (IRealization real : realizations) {
+ DataModelDesc model = real.getModel();
+ TblColRef.fixUnknownModel(model, tblColRef.getTableRef().getTableIdentity(), tblColRef);
+
+ // cannot be a measure column
+ Set<String> metrics = Sets.newHashSet(model.getMetrics());
+ if (metrics.contains(tblColRef.getIdentity())) {
+ tblColRef.unfixTableRef();
+ return false;
+ }
+
+ // must belong to a fact table
+ for (TableRef factTable : model.getFactTables()) {
+ if (factTable.getColumns().contains(tblColRef)) {
+ tblColRef.unfixTableRef();
+ return true;
+ }
+ }
+ tblColRef.unfixTableRef();
+ }
+ return false;
+ }
+
public void setReturnTupleInfo(RelDataType rowType, ColumnRowType columnRowType) {
TupleInfo info = new TupleInfo();
List<RelDataTypeField> fieldList = rowType.getFieldList();
--
To stop receiving notification emails like this one, please contact
shaofengshi@apache.org.