KYLIN-2575 code refactors
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/aed840f9 Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/aed840f9 Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/aed840f9 Branch: refs/heads/master Commit: aed840f9343e3e62a711517900c357a091e75619 Parents: 8906d13 Author: Hongbin Ma <mahong...@apache.org> Authored: Mon Aug 21 11:51:15 2017 +0800 Committer: Hongbin Ma <m...@kyligence.io> Committed: Mon Aug 21 22:55:59 2017 +0800 ---------------------------------------------------------------------- .../apache/kylin/common/KylinConfigBase.java | 18 +- .../common/util/CaseInsensitiveString.java | 63 +++++++ .../kylin/common/util/CliCommandExecutor.java | 5 +- .../org/apache/kylin/common/util/BasicTest.java | 8 +- .../cube/cuboid/DefaultCuboidScheduler.java | 18 +- .../org/apache/kylin/cube/model/CubeDesc.java | 92 ++++++---- .../cube/model/TooManyCuboidException.java | 25 +++ .../org/apache/kylin/cube/CubeDescTest.java | 7 +- .../org/apache/kylin/job/JoinedFlatTable.java | 2 +- .../apache/kylin/metadata/model/ColumnDesc.java | 15 +- .../metadata/model/ComputedColumnDesc.java | 73 ++++++-- .../kylin/metadata/model/DataModelDesc.java | 21 ++- .../metadata/model/tool/CalciteParser.java | 102 ++--------- .../kylin/metadata/project/ProjectManager.java | 9 +- .../kylin/model/tool/CalciteParserTest.java | 16 -- .../gtrecord/GTCubeStorageQueryBase.java | 54 ++++-- .../localmeta/cube_desc/ci_inner_join_cube.json | 46 +++-- .../localmeta/cube_desc/ci_left_join_cube.json | 46 +++-- .../cube_desc/ut_inner_join_cube_partial.json | 28 +-- .../model_desc/ci_inner_join_model.json | 52 ++++-- .../model_desc/ci_left_join_model.json | 54 ++++-- .../query/sql_computedcolumn/query01.sql | 2 +- .../query/sql_computedcolumn/query02.sql | 2 +- .../query/sql_computedcolumn/query03.sql | 2 +- .../query/sql_verifyCount/query01.sql.expected | 2 +- .../query/sql_verifyCount/query03.sql.expected | 2 +- .../query/sql_verifyCount/query04.sql.expected | 2 +- .../query/sql_verifyCount/query10.sql.expected | 2 +- .../query/sql_verifyCount/query11.sql.expected | 2 +- .../query/adhoc/PushDownRunnerJdbcImpl.java | 2 +- .../query/enumerator/LookupTableEnumerator.java | 2 +- .../kylin/query/relnode/ColumnRowType.java | 4 + .../kylin/query/relnode/OLAPProjectRel.java | 2 +- .../kylin/query/relnode/OLAPTableScan.java | 2 +- .../apache/kylin/query/schema/OLAPSchema.java | 12 +- .../kylin/query/schema/OLAPSchemaFactory.java | 2 +- .../apache/kylin/query/schema/OLAPTable.java | 22 ++- .../query/util/KeywordDefaultDirtyHack.java | 2 +- .../apache/kylin/query/util/PushDownUtil.java | 174 ++++++++++--------- .../org/apache/kylin/query/util/QueryUtil.java | 25 ++- .../kylin/query/util/PushDownUtilTest.java | 43 ++++- .../apache/kylin/query/util/QueryUtilTest.java | 10 +- .../rest/controller2/ModelControllerV2.java | 34 +++- .../apache/kylin/rest/service/ModelService.java | 113 +++++++++++- .../apache/kylin/rest/service/QueryService.java | 75 ++++---- 45 files changed, 861 insertions(+), 433 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java ---------------------------------------------------------------------- diff --git a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java index df74f5e..0f5f3a9 100644 --- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java +++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java @@ -605,7 +605,7 @@ abstract public class KylinConfigBase implements Serializable { public Map<String, String> getKafkaConfigOverride() { return getPropertiesByPrefix("kylin.source.kafka.config-override."); } - + // ============================================================================ // SOURCE.JDBC // ============================================================================ @@ -613,23 +613,23 @@ abstract public class KylinConfigBase implements Serializable { public String getJdbcConnectionUrl() { return getOptional("kylin.source.jdbc.connection-url"); } - + public String getJdbcDriver() { return getOptional("kylin.source.jdbc.driver"); } - + public String getJdbcDialect() { return getOptional("kylin.source.jdbc.dialect"); } - + public String getJdbcUser() { return getOptional("kylin.source.jdbc.user"); } - + public String getJdbcPass() { return getOptional("kylin.source.jdbc.pass"); } - + public String getSqoopHome() { return getOptional("kylin.source.jdbc.sqoop-home"); } @@ -1042,9 +1042,9 @@ abstract public class KylinConfigBase implements Serializable { return getOptional("kylin.query.pushdown.runner-class-name", ""); } - public String getPushDownConverterClassName() { - return getOptional("kylin.query.pushdown.converter-class-name", - "org.apache.kylin.source.adhocquery.HivePushDownConverter"); + public String[] getPushDownConverterClassNames() { + return getOptionalStringArray("kylin.query.pushdown.converter-class-names", + new String[] { "org.apache.kylin.source.adhocquery.HivePushDownConverter" }); } public String getJdbcUrl() { http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-common/src/main/java/org/apache/kylin/common/util/CaseInsensitiveString.java ---------------------------------------------------------------------- diff --git a/core-common/src/main/java/org/apache/kylin/common/util/CaseInsensitiveString.java b/core-common/src/main/java/org/apache/kylin/common/util/CaseInsensitiveString.java new file mode 100644 index 0000000..4389aab --- /dev/null +++ b/core-common/src/main/java/org/apache/kylin/common/util/CaseInsensitiveString.java @@ -0,0 +1,63 @@ +/* + * 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.kylin.common.util; + +/** + * A string wrapper that makes .equals a caseInsensitive match + * <p> + * a collection that wraps a String mapping in CaseInsensitiveStrings will still accept a String but will now + * return a caseInsensitive match rather than a caseSensitive one + * </p> + */ +public class CaseInsensitiveString { + String str; + + private CaseInsensitiveString(String str) { + this.str = str; + } + + public static CaseInsensitiveString wrap(String str) { + return new CaseInsensitiveString(str); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null) + return false; + + if (o.getClass() == getClass()) { //is another CaseInsensitiveString + CaseInsensitiveString that = (CaseInsensitiveString) o; + return (str != null) ? str.equalsIgnoreCase(that.str) : that.str == null; + } else { + return false; + } + + } + + @Override + public int hashCode() { + return (str != null) ? str.toUpperCase().hashCode() : 0; + } + + @Override + public String toString() { + return str; + } +} http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-common/src/main/java/org/apache/kylin/common/util/CliCommandExecutor.java ---------------------------------------------------------------------- diff --git a/core-common/src/main/java/org/apache/kylin/common/util/CliCommandExecutor.java b/core-common/src/main/java/org/apache/kylin/common/util/CliCommandExecutor.java index 9d41c86..0b6ac90 100644 --- a/core-common/src/main/java/org/apache/kylin/common/util/CliCommandExecutor.java +++ b/core-common/src/main/java/org/apache/kylin/common/util/CliCommandExecutor.java @@ -89,9 +89,10 @@ public class CliCommandExecutor { } if (r.getFirst() != 0) - throw new IOException("OS command error exit with " + r.getFirst() // + throw new IOException("OS command error exit with return code: " + r.getFirst() // + + ", error message: " + r.getSecond() + "The command is: \n" + command + (remoteHost == null ? "" : " (remoteHost:" + remoteHost + ")") // - + " -- " + command + "\n" + r.getSecond()); + ); return r; } http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-common/src/test/java/org/apache/kylin/common/util/BasicTest.java ---------------------------------------------------------------------- diff --git a/core-common/src/test/java/org/apache/kylin/common/util/BasicTest.java b/core-common/src/test/java/org/apache/kylin/common/util/BasicTest.java index 5512147b..fe89f24 100644 --- a/core-common/src/test/java/org/apache/kylin/common/util/BasicTest.java +++ b/core-common/src/test/java/org/apache/kylin/common/util/BasicTest.java @@ -81,6 +81,8 @@ public class BasicTest { @Test public void testxx() throws InterruptedException { + System.out.println( + "((?<![\\p{L}_0-9\\.\\\"])(\\\"[\\p{L}_0-9]+\\\"\\.)?(\\\"[\\p{L}_0-9]+\\\")(?![\\p{L}_0-9\\.\\\"]))"); System.out.println(0x8fL); byte[] space = new byte[100]; ByteBuffer buffer = ByteBuffer.wrap(space, 10, 20); @@ -190,8 +192,10 @@ public class BasicTest { System.out.println(time(c.getTimeInMillis())); a.setTimeInMillis(current); - b.set(a.get(Calendar.YEAR), a.get(Calendar.MONTH), a.get(Calendar.DAY_OF_MONTH), a.get(Calendar.HOUR_OF_DAY), a.get(Calendar.MINUTE)); - c.set(a.get(Calendar.YEAR), a.get(Calendar.MONTH), a.get(Calendar.DAY_OF_MONTH), a.get(Calendar.HOUR_OF_DAY), 0); + b.set(a.get(Calendar.YEAR), a.get(Calendar.MONTH), a.get(Calendar.DAY_OF_MONTH), a.get(Calendar.HOUR_OF_DAY), + a.get(Calendar.MINUTE)); + c.set(a.get(Calendar.YEAR), a.get(Calendar.MONTH), a.get(Calendar.DAY_OF_MONTH), a.get(Calendar.HOUR_OF_DAY), + 0); System.out.println(time(b.getTimeInMillis())); System.out.println(time(c.getTimeInMillis())); http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java index 1c18b69..f7d22da 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/cuboid/DefaultCuboidScheduler.java @@ -36,6 +36,7 @@ import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.util.Pair; import org.apache.kylin.cube.model.AggregationGroup; import org.apache.kylin.cube.model.CubeDesc; +import org.apache.kylin.cube.model.TooManyCuboidException; import com.google.common.base.Predicate; import com.google.common.collect.Iterators; @@ -47,13 +48,13 @@ public class DefaultCuboidScheduler extends CuboidScheduler { private final long max; private final Set<Long> allCuboidIds; private final Map<Long, List<Long>> parent2child; - + public DefaultCuboidScheduler(CubeDesc cubeDesc) { super(cubeDesc); - + int size = this.cubeDesc.getRowkey().getRowKeyColumns().length; this.max = (long) Math.pow(2, size) - 1; - + Pair<Set<Long>, Map<Long, List<Long>>> pair = buildTreeBottomUp(); this.allCuboidIds = pair.getFirst(); this.parent2child = pair.getSecond(); @@ -145,7 +146,8 @@ public class DefaultCuboidScheduler extends CuboidScheduler { maxCombination = maxCombination < 0 ? Long.MAX_VALUE : maxCombination; while (!children.isEmpty()) { if (cuboidHolder.size() > maxCombination) { - throw new IllegalStateException("Too many cuboids for the cube. Cuboid combination reached " + cuboidHolder.size() + " and limit is " + maxCombination + ". Abort calculation."); + throw new IllegalStateException("Too many cuboids for the cube. Cuboid combination reached " + + cuboidHolder.size() + " and limit is " + maxCombination + ". Abort calculation."); } cuboidHolder.addAll(children); children = getOnTreeParentsByLayer(children); @@ -251,7 +253,7 @@ public class DefaultCuboidScheduler extends CuboidScheduler { return parentCandidate; } - + /** * Get all valid cuboids for agg group, ignoring padding * @param agg agg group @@ -265,7 +267,7 @@ public class DefaultCuboidScheduler extends CuboidScheduler { Set<Long> children = getLowestCuboids(agg); while (!children.isEmpty()) { if (cuboidHolder.size() > cubeDesc.getConfig().getCubeAggrGroupMaxCombination()) { - throw new IllegalStateException("too many combination for the aggregation group"); + throw new TooManyCuboidException("Holder size larger than kylin.cube.aggrgroup.max-combination"); } cuboidHolder.addAll(children); children = getOnTreeParentsByLayer(children, agg); @@ -341,12 +343,12 @@ public class DefaultCuboidScheduler extends CuboidScheduler { } return false; } - + private boolean checkDimCap(AggregationGroup agg, long cuboidID) { int dimCap = agg.getDimCap(); if (dimCap <= 0) return true; - + return Long.bitCount(cuboidID) <= dimCap; } http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java index 439e484..0e22587 100644 --- a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java @@ -114,7 +114,8 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { @Override public String toString() { - return "DeriveInfo [type=" + type + ", join=" + join + ", columns=" + Arrays.toString(columns) + ", isOneToOne=" + isOneToOne + "]"; + return "DeriveInfo [type=" + type + ", join=" + join + ", columns=" + Arrays.toString(columns) + + ", isOneToOne=" + isOneToOne + "]"; } } @@ -286,7 +287,8 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { throw new RuntimeException("Cannot get host info for " + derived); } - public Map<Array<TblColRef>, List<DeriveInfo>> getHostToDerivedInfo(List<TblColRef> rowCols, Collection<TblColRef> wantedCols) { + public Map<Array<TblColRef>, List<DeriveInfo>> getHostToDerivedInfo(List<TblColRef> rowCols, + Collection<TblColRef> wantedCols) { Map<Array<TblColRef>, List<DeriveInfo>> result = new HashMap<Array<TblColRef>, List<DeriveInfo>>(); for (Entry<Array<TblColRef>, List<DeriveInfo>> entry : hostToDerivedMap.entrySet()) { Array<TblColRef> hostCols = entry.getKey(); @@ -496,12 +498,15 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { KylinVersion cubeVersion = new KylinVersion(getVersion()); KylinVersion kylinVersion = KylinVersion.getCurrentVersion(); if (!kylinVersion.isCompatibleWith(cubeVersion)) { - logger.info("checkSignature on {} is skipped as the its version {} is different from kylin version {}", getName(), cubeVersion, kylinVersion); + logger.info("checkSignature on {} is skipped as the its version {} is different from kylin version {}", + getName(), cubeVersion, kylinVersion); return true; } if (kylinVersion.isCompatibleWith(cubeVersion) && !kylinVersion.isSignatureCompatibleWith(cubeVersion)) { - logger.info("checkSignature on {} is skipped as the its version is {} (not signature compatible but compatible) ", getName(), cubeVersion); + logger.info( + "checkSignature on {} is skipped as the its version is {} (not signature compatible but compatible) ", + getName(), cubeVersion); return true; } @@ -606,7 +611,9 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { // check all dimension columns are presented on rowkey List<TblColRef> dimCols = listDimensionColumnsExcludingDerived(true); - checkState(rowkey.getRowKeyColumns().length == dimCols.size(), "RowKey columns count (%s) doesn't match dimensions columns count (%s)", rowkey.getRowKeyColumns().length, dimCols.size()); + checkState(rowkey.getRowKeyColumns().length == dimCols.size(), + "RowKey columns count (%s) doesn't match dimensions columns count (%s)", + rowkey.getRowKeyColumns().length, dimCols.size()); initDictionaryDesc(); amendAllColumns(); @@ -615,7 +622,7 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { public CuboidScheduler getCuboidScheduler() { if (cuboidScheduler != null) return cuboidScheduler; - + synchronized (this) { if (cuboidScheduler == null) { cuboidScheduler = CuboidScheduler.getInstance(this); @@ -632,22 +639,25 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { int index = 0; for (AggregationGroup agg : getAggregationGroups()) { - long combination = 0L; try { - combination = agg.calculateCuboidCombination(); - } catch (Exception ex) { - combination = config.getCubeAggrGroupMaxCombination() + 1; - } finally { + long combination = agg.calculateCuboidCombination(); + if (combination > config.getCubeAggrGroupMaxCombination()) { - String msg = "Aggregation group " + index + " has too many combinations, use 'mandatory'/'hierarchy'/'joint' to optimize; or update 'kylin.cube.aggrgroup.max-combination' to a bigger value."; - logger.error("Aggregation group " + index + " has " + combination + " combinations;"); - logger.error(msg); - throw new IllegalStateException(msg); + String msg = "Aggregation group " + index + " of Cube Desc " + this.name + + " has too many combinations: " + combination + + ". Use 'mandatory'/'hierarchy'/'joint' to optimize; or update 'kylin.cube.aggrgroup.max-combination' to a bigger value."; + throw new TooManyCuboidException(msg); } + } catch (TooManyCuboidException tmce) { + throw tmce; + } catch (Exception e) { + throw new IllegalStateException("Unknown error while calculating cuboid number for " + // + "Aggregation group " + index + " of Cube Desc " + this.name, e); } index++; } + } public void validateAggregationGroups() { @@ -678,50 +688,64 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { Set<String> jointDims = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); getDims(jointDimsList, jointDims, agg.getSelectRule().jointDims); - if (!includeDims.containsAll(mandatoryDims) || !includeDims.containsAll(hierarchyDims) || !includeDims.containsAll(jointDims)) { + if (!includeDims.containsAll(mandatoryDims) || !includeDims.containsAll(hierarchyDims) + || !includeDims.containsAll(jointDims)) { List<String> notIncluded = Lists.newArrayList(); - final Iterable<String> all = Iterables.unmodifiableIterable(Iterables.concat(mandatoryDims, hierarchyDims, jointDims)); + final Iterable<String> all = Iterables + .unmodifiableIterable(Iterables.concat(mandatoryDims, hierarchyDims, jointDims)); for (String dim : all) { if (includeDims.contains(dim) == false) { notIncluded.add(dim); } } Collections.sort(notIncluded); - logger.error("Aggregation group " + index + " Include dimensions not containing all the used dimensions"); - throw new IllegalStateException("Aggregation group " + index + " 'includes' dimensions not include all the dimensions:" + notIncluded.toString()); + logger.error( + "Aggregation group " + index + " Include dimensions not containing all the used dimensions"); + throw new IllegalStateException("Aggregation group " + index + + " 'includes' dimensions not include all the dimensions:" + notIncluded.toString()); } if (CollectionUtils.containsAny(mandatoryDims, hierarchyDims)) { - logger.warn("Aggregation group " + index + " mandatory dimensions overlap with hierarchy dimensions: " + ensureOrder(CollectionUtils.intersection(mandatoryDims, hierarchyDims))); + logger.warn("Aggregation group " + index + " mandatory dimensions overlap with hierarchy dimensions: " + + ensureOrder(CollectionUtils.intersection(mandatoryDims, hierarchyDims))); } if (CollectionUtils.containsAny(mandatoryDims, jointDims)) { - logger.warn("Aggregation group " + index + " mandatory dimensions overlap with joint dimensions: " + ensureOrder(CollectionUtils.intersection(mandatoryDims, jointDims))); + logger.warn("Aggregation group " + index + " mandatory dimensions overlap with joint dimensions: " + + ensureOrder(CollectionUtils.intersection(mandatoryDims, jointDims))); } if (CollectionUtils.containsAny(hierarchyDims, jointDims)) { logger.error("Aggregation group " + index + " hierarchy dimensions overlap with joint dimensions"); - throw new IllegalStateException("Aggregation group " + index + " hierarchy dimensions overlap with joint dimensions: " + ensureOrder(CollectionUtils.intersection(hierarchyDims, jointDims))); + throw new IllegalStateException( + "Aggregation group " + index + " hierarchy dimensions overlap with joint dimensions: " + + ensureOrder(CollectionUtils.intersection(hierarchyDims, jointDims))); } if (hasSingleOrNone(hierarchyDimsList)) { logger.error("Aggregation group " + index + " require at least 2 dimensions in a hierarchy"); - throw new IllegalStateException("Aggregation group " + index + " require at least 2 dimensions in a hierarchy."); + throw new IllegalStateException( + "Aggregation group " + index + " require at least 2 dimensions in a hierarchy."); } if (hasSingleOrNone(jointDimsList)) { logger.error("Aggregation group " + index + " require at least 2 dimensions in a joint"); - throw new IllegalStateException("Aggregation group " + index + " require at least 2 dimensions in a joint"); + throw new IllegalStateException( + "Aggregation group " + index + " require at least 2 dimensions in a joint"); } Pair<Boolean, Set<String>> overlap = hasOverlap(hierarchyDimsList, hierarchyDims); if (overlap.getFirst() == true) { - logger.error("Aggregation group " + index + " a dimension exist in more than one hierarchy: " + ensureOrder(overlap.getSecond())); - throw new IllegalStateException("Aggregation group " + index + " a dimension exist in more than one hierarchy: " + ensureOrder(overlap.getSecond())); + logger.error("Aggregation group " + index + " a dimension exist in more than one hierarchy: " + + ensureOrder(overlap.getSecond())); + throw new IllegalStateException("Aggregation group " + index + + " a dimension exist in more than one hierarchy: " + ensureOrder(overlap.getSecond())); } overlap = hasOverlap(jointDimsList, jointDims); if (overlap.getFirst() == true) { - logger.error("Aggregation group " + index + " a dimension exist in more than one joint: " + ensureOrder(overlap.getSecond())); - throw new IllegalStateException("Aggregation group " + index + " a dimension exist in more than one joint: " + ensureOrder(overlap.getSecond())); + logger.error("Aggregation group " + index + " a dimension exist in more than one joint: " + + ensureOrder(overlap.getSecond())); + throw new IllegalStateException("Aggregation group " + index + + " a dimension exist in more than one joint: " + ensureOrder(overlap.getSecond())); } index++; @@ -849,7 +873,8 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { return new String[][] { cols, extra }; } - private void initDerivedMap(TblColRef[] hostCols, DeriveType type, JoinDesc join, TblColRef[] derivedCols, String[] extra) { + private void initDerivedMap(TblColRef[] hostCols, DeriveType type, JoinDesc join, TblColRef[] derivedCols, + String[] extra) { if (hostCols.length == 0 || derivedCols.length == 0) throw new IllegalStateException("host/derived columns must not be empty"); @@ -870,7 +895,8 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { for (int i = 0; i < derivedCols.length; i++) { TblColRef derivedCol = derivedCols[i]; - boolean isOneToOne = type == DeriveType.PK_FK || ArrayUtils.contains(hostCols, derivedCol) || (extra != null && extra[i].contains("1-1")); + boolean isOneToOne = type == DeriveType.PK_FK || ArrayUtils.contains(hostCols, derivedCol) + || (extra != null && extra[i].contains("1-1")); derivedToHostMap.put(derivedCol, new DeriveInfo(type, join, hostCols, isOneToOne)); } @@ -902,7 +928,8 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { whatsLeft.add(derCol); } if (whatsLeft.size() > 0) { - infoList.add(new DeriveInfo(type, join, (TblColRef[]) whatsLeft.toArray(new TblColRef[whatsLeft.size()]), false)); + infoList.add(new DeriveInfo(type, join, (TblColRef[]) whatsLeft.toArray(new TblColRef[whatsLeft.size()]), + false)); } } @@ -993,7 +1020,8 @@ public class CubeDesc extends RootPersistentEntity implements IEngineAware { } for (int i = 0; i < measures.size(); i++) { - checkState(checkEachMeasureExist.get(i), "measure (%s) does not exist in column familyï¼or measure duplicates", measures.get(i)); + checkState(checkEachMeasureExist.get(i), + "measure (%s) does not exist in column familyï¼or measure duplicates", measures.get(i)); } } http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-cube/src/main/java/org/apache/kylin/cube/model/TooManyCuboidException.java ---------------------------------------------------------------------- diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/TooManyCuboidException.java b/core-cube/src/main/java/org/apache/kylin/cube/model/TooManyCuboidException.java new file mode 100644 index 0000000..cfa41e4 --- /dev/null +++ b/core-cube/src/main/java/org/apache/kylin/cube/model/TooManyCuboidException.java @@ -0,0 +1,25 @@ +/* + * 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.kylin.cube.model; + +public class TooManyCuboidException extends RuntimeException { + + public TooManyCuboidException(String message) { + super(message); + } +} http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-cube/src/test/java/org/apache/kylin/cube/CubeDescTest.java ---------------------------------------------------------------------- diff --git a/core-cube/src/test/java/org/apache/kylin/cube/CubeDescTest.java b/core-cube/src/test/java/org/apache/kylin/cube/CubeDescTest.java index 0bbc874..b8c19c4 100644 --- a/core-cube/src/test/java/org/apache/kylin/cube/CubeDescTest.java +++ b/core-cube/src/test/java/org/apache/kylin/cube/CubeDescTest.java @@ -44,6 +44,7 @@ import org.apache.kylin.cube.model.CubeDesc.DeriveInfo; import org.apache.kylin.cube.model.CubeDesc.DeriveType; import org.apache.kylin.cube.model.DimensionDesc; import org.apache.kylin.cube.model.SelectRule; +import org.apache.kylin.cube.model.TooManyCuboidException; import org.apache.kylin.metadata.model.MeasureDesc; import org.apache.kylin.metadata.model.TblColRef; import org.junit.After; @@ -204,8 +205,8 @@ public class CubeDescTest extends LocalFileMetadataTestCase { @Test public void testBadInit4() throws Exception { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Aggregation group 0 has too many combinations, use 'mandatory'/'hierarchy'/'joint' to optimize; or update 'kylin.cube.aggrgroup.max-combination' to a bigger value."); + thrown.expect(TooManyCuboidException.class); + thrown.expectMessage("Aggregation group 0 of Cube Desc test_kylin_cube_with_slr_desc has too many combinations: 31. Use 'mandatory'/'hierarchy'/'joint' to optimize; or update 'kylin.cube.aggrgroup.max-combination' to a bigger value."); CubeDesc cubeDesc = CubeDescManager.getInstance(getTestConfig()).getCubeDesc(CUBE_WITH_SLR_DESC); try { @@ -312,7 +313,7 @@ public class CubeDescTest extends LocalFileMetadataTestCase { } } - thrown.expect(IllegalStateException.class); + thrown.expect(TooManyCuboidException.class); CubeDescManager.clearCache(); CubeDesc cubeDesc = CubeDescManager.getInstance(getTestConfig()).getCubeDesc("ut_cube_desc_combination_int_overflow"); cubeDesc.init(getTestConfig()); http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-job/src/main/java/org/apache/kylin/job/JoinedFlatTable.java ---------------------------------------------------------------------- diff --git a/core-job/src/main/java/org/apache/kylin/job/JoinedFlatTable.java b/core-job/src/main/java/org/apache/kylin/job/JoinedFlatTable.java index 5ea2335..acb29e1 100644 --- a/core-job/src/main/java/org/apache/kylin/job/JoinedFlatTable.java +++ b/core-job/src/main/java/org/apache/kylin/job/JoinedFlatTable.java @@ -148,7 +148,7 @@ public class JoinedFlatTable { return sql.toString(); } - private static void appendJoinStatement(IJoinedFlatTableDesc flatDesc, StringBuilder sql, boolean singleLine) { + public static void appendJoinStatement(IJoinedFlatTableDesc flatDesc, StringBuilder sql, boolean singleLine) { final String sep = singleLine ? " " : "\n"; Set<TableRef> dimTableCache = new HashSet<>(); http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-metadata/src/main/java/org/apache/kylin/metadata/model/ColumnDesc.java ---------------------------------------------------------------------- diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/ColumnDesc.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/ColumnDesc.java index 3c84c96..394300e 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/ColumnDesc.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/ColumnDesc.java @@ -21,7 +21,6 @@ package org.apache.kylin.metadata.model; import java.io.Serializable; import org.apache.kylin.metadata.datatype.DataType; -import org.apache.kylin.metadata.model.tool.CalciteParser; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; @@ -198,8 +197,7 @@ public class ColumnDesc implements Serializable { Preconditions.checkState(computedColumnExpr != null); Preconditions.checkState(tableAlias != null); - String s = CalciteParser.insertAliasInExpr(computedColumnExpr, tableAlias); - return s; + return computedColumnExpr; } public boolean isComputedColumnn() { @@ -223,6 +221,17 @@ public class ColumnDesc implements Serializable { } } + // for test mainly + public static ColumnDesc mockup(TableDesc table, int oneBasedColumnIndex, String name, String datatype) { + ColumnDesc desc = new ColumnDesc(); + String id = "" + oneBasedColumnIndex; + desc.setId(id); + desc.setName(name); + desc.setDatatype(datatype); + desc.init(table); + return desc; + } + @Override public int hashCode() { final int prime = 31; http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-metadata/src/main/java/org/apache/kylin/metadata/model/ComputedColumnDesc.java ---------------------------------------------------------------------- diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/ComputedColumnDesc.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/ComputedColumnDesc.java index 10a7dd3..ab8a634 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/ComputedColumnDesc.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/ComputedColumnDesc.java @@ -17,20 +17,30 @@ */ package org.apache.kylin.metadata.model; +import java.io.Serializable; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; import org.apache.kylin.metadata.model.tool.CalciteParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Preconditions; -import java.io.Serializable; - @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) public class ComputedColumnDesc implements Serializable { + private static final Logger logger = LoggerFactory.getLogger(ComputedColumnDesc.class); + + @JsonProperty + private String tableIdentity; // the alias in the model where the computed column belong to @JsonProperty - private String tableIdentity; + @JsonInclude(JsonInclude.Include.NON_NULL) + private String tableAlias; @JsonProperty - private String columnName; + private String columnName; // the new col name @JsonProperty private String expression; @JsonProperty @@ -38,21 +48,56 @@ public class ComputedColumnDesc implements Serializable { @JsonProperty private String comment; - public void init() { + public void init(Set<String> aliasSet, String rootFactTableName) { Preconditions.checkNotNull(tableIdentity, "tableIdentity is null"); Preconditions.checkNotNull(columnName, "columnName is null"); Preconditions.checkNotNull(expression, "expression is null"); Preconditions.checkNotNull(datatype, "datatype is null"); - Preconditions.checkState(tableIdentity.equals(tableIdentity.trim()), "tableIdentity of ComputedColumnDesc has heading/tailing whitespace"); - Preconditions.checkState(columnName.equals(columnName.trim()), "columnName of ComputedColumnDesc has heading/tailing whitespace"); - Preconditions.checkState(datatype.equals(datatype.trim()), "datatype of ComputedColumnDesc has heading/tailing whitespace"); + if (tableAlias == null) // refer to comment of handleLegacyCC() + tableAlias = tableIdentity.substring(tableIdentity.indexOf(".") + 1); + + Preconditions.checkState(tableIdentity.equals(tableIdentity.trim()), + "tableIdentity of ComputedColumnDesc has heading/tailing whitespace"); + Preconditions.checkState(tableAlias.equals(tableAlias.trim()), + "tableAlias of ComputedColumnDesc has heading/tailing whitespace"); + Preconditions.checkState(columnName.equals(columnName.trim()), + "columnName of ComputedColumnDesc has heading/tailing whitespace"); + Preconditions.checkState(datatype.equals(datatype.trim()), + "datatype of ComputedColumnDesc has heading/tailing whitespace"); tableIdentity = tableIdentity.toUpperCase(); + tableAlias = tableAlias.toUpperCase(); columnName = columnName.toUpperCase(); - if ("true".equals(System.getProperty("needCheckCC"))) - CalciteParser.ensureNoTableNameExists(expression); + if (!tableIdentity.contains(rootFactTableName) || !tableAlias.equals(rootFactTableName)) { + throw new IllegalArgumentException("Computed column has to be defined on fact table"); + } + + if ("true".equals(System.getProperty("needCheckCC"))) { //conditional execute this because of the calcite dependency is to available every where + try { + CalciteParser.ensureAliasInExpr(expression, aliasSet); + } catch (Exception e) { + String legacyHandled = handleLegacyCC(expression, rootFactTableName, aliasSet); + if (legacyHandled != null) { + expression = legacyHandled; + } else { + throw e; + } + } + } + } + + private String handleLegacyCC(String expr, String rootFact, Set<String> aliasSet) { + try { + CalciteParser.ensureNoAliasInExpr(expr); + String ret = CalciteParser.insertAliasInExpr(expr, rootFact); + CalciteParser.ensureAliasInExpr(ret, aliasSet); + return ret; + } catch (Exception e) { + logger.error("failed to handle legacy CC " + expr); + return null; + } } public String getFullName() { @@ -63,6 +108,10 @@ public class ComputedColumnDesc implements Serializable { return tableIdentity; } + public String getTableAlias() { + return tableAlias; + } + public String getColumnName() { return columnName; } @@ -90,6 +139,8 @@ public class ComputedColumnDesc implements Serializable { if (!tableIdentity.equals(that.tableIdentity)) return false; + if (!StringUtils.equals(tableAlias, that.tableAlias)) + return false; if (!columnName.equals(that.columnName)) return false; if (!expression.equals(that.expression)) @@ -100,6 +151,8 @@ public class ComputedColumnDesc implements Serializable { @Override public int hashCode() { int result = tableIdentity.hashCode(); + if (tableAlias != null) + result = 31 * result + tableAlias.hashCode(); result = 31 * result + columnName.hashCode(); result = 31 * result + expression.hashCode(); result = 31 * result + datatype.hashCode(); http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java ---------------------------------------------------------------------- diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java index 2037420..8fcbc4c 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java @@ -22,6 +22,7 @@ import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -189,6 +190,10 @@ public class DataModelDesc extends RootPersistentEntity { return factTableRefs; } + public Map<String, TableRef> getAliasMap() { + return Collections.unmodifiableMap(aliasMap); + } + public Set<TableRef> getLookupTables() { return lookupTableRefs; } @@ -430,8 +435,9 @@ public class DataModelDesc extends RootPersistentEntity { String alias = join.getAlias(); if (alias == null) { alias = tableDesc.getName(); - join.setAlias(alias); } + alias = alias.toUpperCase(); + join.setAlias(alias); TableRef ref = new TableRef(this, alias, tableDesc); @@ -494,25 +500,26 @@ public class DataModelDesc extends RootPersistentEntity { for (ComputedColumnDesc newCC : this.computedColumnDescs) { - newCC.init(); - final String newCCName = newCC.getFullName(); + newCC.init(aliasMap.keySet(), rootFactTableRef.getAlias()); + final String newCCFullName = newCC.getFullName(); final String newCCColumnName = newCC.getColumnName(); for (Pair<ComputedColumnDesc, DataModelDesc> pair : existingCCs) { DataModelDesc dataModelDesc = pair.getSecond(); ComputedColumnDesc cc = pair.getFirst(); - if (StringUtils.equalsIgnoreCase(cc.getFullName(), newCCName) && !(cc.equals(newCC))) { + if (StringUtils.equalsIgnoreCase(cc.getFullName(), newCCFullName) && !(cc.equals(newCC))) { throw new IllegalArgumentException(String.format( "Column name for computed column %s is already used in model %s, you should apply the same expression ' %s ' here, or use a different column name.", - newCCName, dataModelDesc.getName(), cc.getExpression())); + newCCFullName, dataModelDesc.getName(), cc.getExpression())); } if (isTwoCCDefinitionEquals(cc.getExpression(), newCC.getExpression()) && !StringUtils.equalsIgnoreCase(cc.getColumnName(), newCCColumnName)) { throw new IllegalArgumentException(String.format( - "Expression for computed column %s is already used in model %s, you should use the same column name with ' %s ' .", - newCCName, dataModelDesc.getName(), cc.getColumnName())); + "Expression %s in computed column %s is already defined by computed column %s from model %s, you should use the same column name: ' %s ' .", + newCC.getExpression(), newCCFullName, cc.getFullName(), dataModelDesc.getName(), + cc.getColumnName())); } } existingCCs.add(Pair.newPair(newCC, this)); http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java ---------------------------------------------------------------------- diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java index 01f0b19..08cbf09 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java @@ -21,15 +21,11 @@ package org.apache.kylin.metadata.model.tool; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Objects; import java.util.Set; -import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlIdentifier; -import org.apache.calcite.sql.SqlLiteral; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlNodeList; -import org.apache.calcite.sql.SqlOrderBy; import org.apache.calcite.sql.SqlSelect; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; @@ -54,8 +50,8 @@ public class CalciteParser { try { selectList = ((SqlSelect) CalciteParser.parse(sql)).getSelectList(); } catch (SqlParseException e) { - throw new RuntimeException("Failed to parse expression \'" + sql - + "\', please make sure the expression is valid and no table name exists in the expression"); + throw new RuntimeException( + "Failed to parse expression \'" + sql + "\', please make sure the expression is valid"); } Preconditions.checkArgument(selectList.size() == 1, @@ -66,100 +62,34 @@ public class CalciteParser { public static SqlNode getExpNode(String expr) { return getOnlySelectNode("select " + expr + " from t"); - } - public static SqlNode getFromNode(String sql) { - SqlNode node = null; - try { - node = CalciteParser.parse(sql); - } catch (SqlParseException e) { - throw new RuntimeException( - "Failed to parse expression \'" + sql + "\', please make sure the expression is valid"); - } - //When the sql have limit clause, calcite will parse it as a SqlOrder Object. - SqlNode fromNode = null; - if (node instanceof SqlOrderBy) { - SqlOrderBy orderBy = (SqlOrderBy) node; - fromNode = ((SqlSelect) orderBy.query).getFrom(); - } else { - SqlSelect sqlSelect = (SqlSelect) node; - fromNode = sqlSelect.getFrom(); - } - return fromNode; - } - - public static boolean isNodeEqual(SqlNode node0, SqlNode node1) { - if (node0 == null) { - return node1 == null; - } else if (node1 == null) { - return false; - } - - if (!Objects.equals(node0.getClass().getSimpleName(), node1.getClass().getSimpleName())) { - return false; - } + public static void ensureAliasInExpr(final String expr, final Set<String> aliasSet) { + SqlNode sqlNode = getExpNode(expr); - if (node0 instanceof SqlCall) { - SqlCall thisNode = (SqlCall) node0; - SqlCall thatNode = (SqlCall) node1; - if (!thisNode.getOperator().getName().equalsIgnoreCase(thatNode.getOperator().getName())) { - return false; - } - return isNodeEqual(thisNode.getOperandList(), thatNode.getOperandList()); - } - if (node0 instanceof SqlLiteral) { - SqlLiteral thisNode = (SqlLiteral) node0; - SqlLiteral thatNode = (SqlLiteral) node1; - return Objects.equals(thisNode.getValue(), thatNode.getValue()); - } - if (node0 instanceof SqlNodeList) { - SqlNodeList thisNode = (SqlNodeList) node0; - SqlNodeList thatNode = (SqlNodeList) node1; - if (thisNode.getList().size() != thatNode.getList().size()) { - return false; - } - for (int i = 0; i < thisNode.getList().size(); i++) { - SqlNode thisChild = thisNode.getList().get(i); - final SqlNode thatChild = thatNode.getList().get(i); - if (!isNodeEqual(thisChild, thatChild)) { - return false; + SqlVisitor sqlVisitor = new SqlBasicVisitor() { + @Override + public Object visit(SqlIdentifier id) { + if (id.names.size() < 2 || !aliasSet.contains(id.names.get(0))) { + throw new IllegalArgumentException("Column Identifier in the computed column " + expr + + "expression should comply to ALIAS.COLUMN "); } + return null; } - return true; - } - if (node0 instanceof SqlIdentifier) { - SqlIdentifier thisNode = (SqlIdentifier) node0; - SqlIdentifier thatNode = (SqlIdentifier) node1; - // compare ignore table alias.eg: expression like "a.b + a.c + a.d" ,alias a will be ignored when compared - String name0 = thisNode.names.get(thisNode.names.size() - 1).replace("\"", ""); - String name1 = thatNode.names.get(thatNode.names.size() - 1).replace("\"", ""); - return name0.equalsIgnoreCase(name1); - } - - return false; - } + }; - private static boolean isNodeEqual(List<SqlNode> operands0, List<SqlNode> operands1) { - if (operands0.size() != operands1.size()) { - return false; - } - for (int i = 0; i < operands0.size(); i++) { - if (!isNodeEqual(operands0.get(i), operands1.get(i))) { - return false; - } - } - return true; + sqlNode.accept(sqlVisitor); } - public static void ensureNoTableNameExists(String expr) { + public static void ensureNoAliasInExpr(String expr) { SqlNode sqlNode = getExpNode(expr); SqlVisitor sqlVisitor = new SqlBasicVisitor() { @Override public Object visit(SqlIdentifier id) { if (id.names.size() > 1) { - throw new IllegalArgumentException("SqlIdentifier " + id + " contains DB/Table name"); + throw new IllegalArgumentException( + "Column Identifier in the computed column expression should only contain COLUMN"); } return null; } http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java ---------------------------------------------------------------------- diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java index 82180a9..df5450c 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java @@ -405,7 +405,7 @@ public class ProjectManager { projectInstance.removeExtFilter(filterName); updateProject(projectInstance); } - + public ProjectInstance getProjectOfModel(String model) { for (ProjectInstance prj : projectMap.values()) { if (prj.getModels().contains(model)) @@ -413,7 +413,7 @@ public class ProjectManager { } throw new IllegalStateException("No project found for model " + model); } - + public List<ProjectInstance> findProjects(RealizationType type, String realizationName) { List<ProjectInstance> result = Lists.newArrayList(); for (ProjectInstance prj : projectMap.values()) { @@ -465,11 +465,10 @@ public class ProjectManager { l2Cache.listExposedTables(norm(project)); } - public List<ColumnDesc> listExposedColumns(String project, TableDesc tableDesc) { + public List<ColumnDesc> listExposedColumns(String project, TableDesc tableDesc, boolean exposeMore) { Set<ColumnDesc> exposedColumns = l2Cache.listExposedColumns(norm(project), tableDesc.getIdentity()); - if (config.isPushDownEnabled()) { - // take care of computed columns + if (exposeMore) { Set<ColumnDesc> dedup = Sets.newHashSet(tableDesc.getColumns()); dedup.addAll(exposedColumns); return Lists.newArrayList(dedup); http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java ---------------------------------------------------------------------- diff --git a/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java b/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java index 2da6c9e..6483590 100644 --- a/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java +++ b/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java @@ -103,22 +103,6 @@ public class CalciteParserTest { } - @Test - public void testEqual() throws SqlParseException { - String sql0 = "select a.a + a.b + a.c from t as a"; - String sql1 = "select (((a . a + a.b + a.c))) from t as a"; - String sql2 = "select (a + b) + c from t"; - String sql3 = "select a.a + (a.b + a.c) from t as a"; - - SqlNode sn0 = CalciteParser.getOnlySelectNode(sql0); - SqlNode sn1 = CalciteParser.getOnlySelectNode(sql1); - SqlNode sn2 = CalciteParser.getOnlySelectNode(sql2); - SqlNode sn3 = CalciteParser.getOnlySelectNode(sql3); - - assertEquals(true, CalciteParser.isNodeEqual(sn0, sn1)); - assertEquals(true, CalciteParser.isNodeEqual(sn0, sn2)); - assertEquals(false, CalciteParser.isNodeEqual(sn0, sn3)); - } @Test public void testPosWithBrackets() throws SqlParseException { http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java ---------------------------------------------------------------------- diff --git a/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java b/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java index ea3811c..b40aa5d 100644 --- a/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java +++ b/core-storage/src/main/java/org/apache/kylin/storage/gtrecord/GTCubeStorageQueryBase.java @@ -83,9 +83,10 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { if (cubeDesc.getConfig().isSkippingEmptySegments() && cubeSeg.getInputRecords() == 0) { logger.info("Skip cube segment {} because its input record is 0", cubeSeg); continue; - } + } - scanner = new CubeSegmentScanner(cubeSeg, request.getCuboid(), request.getDimensions(), request.getGroups(), request.getMetrics(), request.getFilter(), request.getHavingFilter(), request.getContext()); + scanner = new CubeSegmentScanner(cubeSeg, request.getCuboid(), request.getDimensions(), request.getGroups(), + request.getMetrics(), request.getFilter(), request.getHavingFilter(), request.getContext()); if (!scanner.isSegmentSkipped()) scanners.add(scanner); } @@ -97,7 +98,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { request.getMetrics(), returnTupleInfo, request.getContext(), sqlDigest); } - protected GTCubeStorageQueryRequest getStorageQueryRequest(StorageContext context, SQLDigest sqlDigest, TupleInfo returnTupleInfo) { + protected GTCubeStorageQueryRequest getStorageQueryRequest(StorageContext context, SQLDigest sqlDigest, + TupleInfo returnTupleInfo) { context.setStorageQuery(this); //cope with queries with no aggregations @@ -143,18 +145,23 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { TupleFilter.collectColumns(filterD, filterColumnD); // set limit push down - enableStorageLimitIfPossible(cuboid, groups, derivedPostAggregation, groupsD, filterD, loosenedColumnD, sqlDigest.aggregations, context); + enableStorageLimitIfPossible(cuboid, groups, derivedPostAggregation, groupsD, filterD, loosenedColumnD, + sqlDigest.aggregations, context); // set whether to aggregate results from multiple partitions enableStreamAggregateIfBeneficial(cuboid, groupsD, context); // set query deadline context.setDeadline(cubeInstance); // push down having clause filter if possible - TupleFilter havingFilter = checkHavingCanPushDown(sqlDigest.havingFilter, groupsD, sqlDigest.aggregations, metrics); + TupleFilter havingFilter = checkHavingCanPushDown(sqlDigest.havingFilter, groupsD, sqlDigest.aggregations, + metrics); - logger.info("Cuboid identified: cube={}, cuboidId={}, groupsD={}, filterD={}, limitPushdown={}, storageAggr={}", cubeInstance.getName(), cuboid.getId(), groupsD, filterColumnD, context.getFinalPushDownLimit(), context.isNeedStorageAggregation()); + logger.info("Cuboid identified: cube={}, cuboidId={}, groupsD={}, filterD={}, limitPushdown={}, storageAggr={}", + cubeInstance.getName(), cuboid.getId(), groupsD, filterColumnD, context.getFinalPushDownLimit(), + context.isNeedStorageAggregation()); - return new GTCubeStorageQueryRequest(cuboid, dimensionsD, groupsD, filterColumnD, metrics, filterD, havingFilter, context); + return new GTCubeStorageQueryRequest(cuboid, dimensionsD, groupsD, filterColumnD, metrics, filterD, + havingFilter, context); } protected abstract String getGTStorage(); @@ -163,11 +170,13 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { return Cuboid.identifyCuboid(cubeDesc, dimensionsD, metrics); } - protected ITupleConverter newCubeTupleConverter(CubeSegment cubeSeg, Cuboid cuboid, Set<TblColRef> selectedDimensions, Set<FunctionDesc> selectedMetrics, int[] gtColIdx, TupleInfo tupleInfo) { + protected ITupleConverter newCubeTupleConverter(CubeSegment cubeSeg, Cuboid cuboid, + Set<TblColRef> selectedDimensions, Set<FunctionDesc> selectedMetrics, int[] gtColIdx, TupleInfo tupleInfo) { return new CubeTupleConverter(cubeSeg, cuboid, selectedDimensions, selectedMetrics, gtColIdx, tupleInfo); } - protected void buildDimensionsAndMetrics(SQLDigest sqlDigest, Collection<TblColRef> dimensions, Collection<FunctionDesc> metrics) { + protected void buildDimensionsAndMetrics(SQLDigest sqlDigest, Collection<TblColRef> dimensions, + Collection<FunctionDesc> metrics) { for (FunctionDesc func : sqlDigest.aggregations) { if (!func.isDimensionAsMetric()) { // use the FunctionDesc from cube desc as much as possible, that has more info such as HLLC precision @@ -177,7 +186,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { for (TblColRef column : sqlDigest.allColumns) { // skip measure columns - if (sqlDigest.metricColumns.contains(column) && !(sqlDigest.groupbyColumns.contains(column) || sqlDigest.filterColumns.contains(column))) { + if (sqlDigest.metricColumns.contains(column) + && !(sqlDigest.groupbyColumns.contains(column) || sqlDigest.filterColumns.contains(column))) { continue; } @@ -226,7 +236,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { if (f instanceof CompareTupleFilter) { CompareTupleFilter compFilter = (CompareTupleFilter) f; // is COL=const ? - if (compFilter.getOperator() == FilterOperatorEnum.EQ && compFilter.getValues().size() == 1 && compFilter.getColumn() != null) { + if (compFilter.getOperator() == FilterOperatorEnum.EQ && compFilter.getValues().size() == 1 + && compFilter.getColumn() != null) { result.add(compFilter.getColumn()); } } @@ -253,7 +264,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { return resultD; } - public boolean isNeedStorageAggregation(Cuboid cuboid, Collection<TblColRef> groupD, Collection<TblColRef> singleValueD) { + public boolean isNeedStorageAggregation(Cuboid cuboid, Collection<TblColRef> groupD, + Collection<TblColRef> singleValueD) { HashSet<TblColRef> temp = Sets.newHashSet(); temp.addAll(groupD); temp.addAll(singleValueD); @@ -345,7 +357,9 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { } } - private void enableStorageLimitIfPossible(Cuboid cuboid, Collection<TblColRef> groups, Set<TblColRef> derivedPostAggregation, Collection<TblColRef> groupsD, TupleFilter filter, Set<TblColRef> loosenedColumnD, Collection<FunctionDesc> functionDescs, StorageContext context) { + private void enableStorageLimitIfPossible(Cuboid cuboid, Collection<TblColRef> groups, + Set<TblColRef> derivedPostAggregation, Collection<TblColRef> groupsD, TupleFilter filter, + Set<TblColRef> loosenedColumnD, Collection<FunctionDesc> functionDescs, StorageContext context) { boolean possible = true; if (!TupleFilter.isEvaluableRecursively(filter)) { @@ -366,15 +380,17 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { // derived aggregation is bad, unless expanded columns are already in group by if (!groups.containsAll(derivedPostAggregation)) { possible = false; - logger.debug("Storage limit push down is impossible because derived column require post aggregation: " + derivedPostAggregation); + logger.debug("Storage limit push down is impossible because derived column require post aggregation: " + + derivedPostAggregation); } //if groupsD is clustered at "head" of the rowkey, then limit push down is possible int size = groupsD.size(); if (!groupsD.containsAll(cuboid.getColumns().subList(0, size))) { possible = false; - logger.debug("Storage limit push down is impossible because groupD is not clustered at head, groupsD: " + groupsD // - + " with cuboid columns: " + cuboid.getColumns()); + logger.debug( + "Storage limit push down is impossible because groupD is not clustered at head, groupsD: " + groupsD // + + " with cuboid columns: " + cuboid.getColumns()); } //if exists measures like max(cal_dt), then it's not a perfect cuboid match, cannot apply limit @@ -402,7 +418,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { } if (!shardByInGroups.isEmpty()) { enabled = false; - logger.debug("Aggregate partition results is not beneficial because shard by columns in groupD: " + shardByInGroups); + logger.debug("Aggregate partition results is not beneficial because shard by columns in groupD: " + + shardByInGroups); } if (!context.isNeedStorageAggregation()) { @@ -434,7 +451,8 @@ public abstract class GTCubeStorageQueryBase implements IStorageQuery { } } - private TupleFilter checkHavingCanPushDown(TupleFilter havingFilter, Set<TblColRef> groupsD, List<FunctionDesc> aggregations, Set<FunctionDesc> metrics) { + private TupleFilter checkHavingCanPushDown(TupleFilter havingFilter, Set<TblColRef> groupsD, + List<FunctionDesc> aggregations, Set<FunctionDesc> metrics) { // must have only one segment Segments<CubeSegment> readySegs = cubeInstance.getSegments(SegmentStatusEnum.READY); if (readySegs.size() != 1) http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/examples/test_case_data/localmeta/cube_desc/ci_inner_join_cube.json ---------------------------------------------------------------------- diff --git a/examples/test_case_data/localmeta/cube_desc/ci_inner_join_cube.json b/examples/test_case_data/localmeta/cube_desc/ci_inner_join_cube.json index 27acdd3..efed0f9 100644 --- a/examples/test_case_data/localmeta/cube_desc/ci_inner_join_cube.json +++ b/examples/test_case_data/localmeta/cube_desc/ci_inner_join_cube.json @@ -131,13 +131,23 @@ }, { "name": "SELLER_COUNTRY_ABBR", - "table": "SELLER_ACCOUNT", - "column": "COUNTRY_ABBR" + "table": "TEST_KYLIN_FACT", + "column": "SELLER_COUNTRY_ABBR" }, { "name": "BUYER_COUNTRY_ABBR", - "table": "BUYER_ACCOUNT", - "column": "COUNTRY_ABBR" + "table": "TEST_KYLIN_FACT", + "column": "BUYER_COUNTRY_ABBR" + }, + { + "name": "SELLER_ID_AND_COUNTRY_NAME", + "table": "TEST_KYLIN_FACT", + "column": "SELLER_ID_AND_COUNTRY_NAME" + }, + { + "name": "BUYER_ID_AND_COUNTRY_NAME", + "table": "TEST_KYLIN_FACT", + "column": "BUYER_ID_AND_COUNTRY_NAME" }, { "name": "BUYER_COUNTRY_NAME", @@ -443,11 +453,19 @@ "encoding": "dict" }, { - "column": "SELLER_ACCOUNT.COUNTRY_ABBR", + "column": "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "encoding": "dict" + }, + { + "column": "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", + "encoding": "dict" + }, + { + "column": "TEST_KYLIN_FACT.SELLER_ID_AND_COUNTRY_NAME", "encoding": "dict" }, { - "column": "BUYER_ACCOUNT.COUNTRY_ABBR", + "column": "TEST_KYLIN_FACT.BUYER_ID_AND_COUNTRY_NAME", "encoding": "dict" } ] @@ -536,7 +554,7 @@ "TEST_KYLIN_FACT.DEAL_YEAR" ] ], - "dim_cap" : 3 + "dim_cap": 3 } }, { @@ -562,8 +580,10 @@ "BUYER_ACCOUNT.ACCOUNT_SELLER_LEVEL", "BUYER_ACCOUNT.ACCOUNT_COUNTRY", "BUYER_COUNTRY.NAME", - "SELLER_ACCOUNT.COUNTRY_ABBR", - "BUYER_ACCOUNT.COUNTRY_ABBR" + "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.SELLER_ID_AND_COUNTRY_NAME", + "TEST_KYLIN_FACT.BUYER_ID_AND_COUNTRY_NAME" ], "select_rule": { "hierarchy_dims": [], @@ -581,8 +601,10 @@ "TEST_KYLIN_FACT.LSTG_FORMAT_NAME", "TEST_KYLIN_FACT.LSTG_SITE_ID", "TEST_KYLIN_FACT.SLR_SEGMENT_CD", - "SELLER_ACCOUNT.COUNTRY_ABBR", - "BUYER_ACCOUNT.COUNTRY_ABBR" + "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.SELLER_ID_AND_COUNTRY_NAME", + "TEST_KYLIN_FACT.BUYER_ID_AND_COUNTRY_NAME" ], [ "TEST_KYLIN_FACT.SELLER_ID", @@ -602,7 +624,7 @@ "BUYER_COUNTRY.NAME" ] ], - "dim_cap" : 5 + "dim_cap": 5 } } ], http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/examples/test_case_data/localmeta/cube_desc/ci_left_join_cube.json ---------------------------------------------------------------------- diff --git a/examples/test_case_data/localmeta/cube_desc/ci_left_join_cube.json b/examples/test_case_data/localmeta/cube_desc/ci_left_join_cube.json index f7ebfc8..6cb0722 100644 --- a/examples/test_case_data/localmeta/cube_desc/ci_left_join_cube.json +++ b/examples/test_case_data/localmeta/cube_desc/ci_left_join_cube.json @@ -131,13 +131,23 @@ }, { "name": "SELLER_COUNTRY_ABBR", - "table": "SELLER_ACCOUNT", - "column": "COUNTRY_ABBR" + "table": "TEST_KYLIN_FACT", + "column": "SELLER_COUNTRY_ABBR" }, { "name": "BUYER_COUNTRY_ABBR", - "table": "BUYER_ACCOUNT", - "column": "COUNTRY_ABBR" + "table": "TEST_KYLIN_FACT", + "column": "BUYER_COUNTRY_ABBR" + }, + { + "name": "SELLER_ID_AND_COUNTRY_NAME", + "table": "TEST_KYLIN_FACT", + "column": "SELLER_ID_AND_COUNTRY_NAME" + }, + { + "name": "BUYER_ID_AND_COUNTRY_NAME", + "table": "TEST_KYLIN_FACT", + "column": "BUYER_ID_AND_COUNTRY_NAME" }, { "name": "BUYER_COUNTRY_NAME", @@ -454,11 +464,19 @@ "encoding": "dict" }, { - "column": "SELLER_ACCOUNT.COUNTRY_ABBR", + "column": "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "encoding": "dict" + }, + { + "column": "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", + "encoding": "dict" + }, + { + "column": "TEST_KYLIN_FACT.SELLER_ID_AND_COUNTRY_NAME", "encoding": "dict" }, { - "column": "BUYER_ACCOUNT.COUNTRY_ABBR", + "column": "TEST_KYLIN_FACT.BUYER_ID_AND_COUNTRY_NAME", "encoding": "dict" } ] @@ -548,7 +566,7 @@ "TEST_KYLIN_FACT.DEAL_YEAR" ] ], - "dim_cap" : 5 + "dim_cap": 5 } }, { @@ -574,8 +592,10 @@ "BUYER_ACCOUNT.ACCOUNT_SELLER_LEVEL", "BUYER_ACCOUNT.ACCOUNT_COUNTRY", "BUYER_COUNTRY.NAME", - "SELLER_ACCOUNT.COUNTRY_ABBR", - "BUYER_ACCOUNT.COUNTRY_ABBR" + "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.SELLER_ID_AND_COUNTRY_NAME", + "TEST_KYLIN_FACT.BUYER_ID_AND_COUNTRY_NAME" ], "select_rule": { "hierarchy_dims": [], @@ -593,8 +613,10 @@ "TEST_KYLIN_FACT.LSTG_FORMAT_NAME", "TEST_KYLIN_FACT.LSTG_SITE_ID", "TEST_KYLIN_FACT.SLR_SEGMENT_CD", - "SELLER_ACCOUNT.COUNTRY_ABBR", - "BUYER_ACCOUNT.COUNTRY_ABBR" + "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.SELLER_ID_AND_COUNTRY_NAME", + "TEST_KYLIN_FACT.BUYER_ID_AND_COUNTRY_NAME" ], [ "TEST_KYLIN_FACT.SELLER_ID", @@ -614,7 +636,7 @@ "BUYER_COUNTRY.NAME" ] ], - "dim_cap" : 3 + "dim_cap": 3 } } ], http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/examples/test_case_data/localmeta/cube_desc/ut_inner_join_cube_partial.json ---------------------------------------------------------------------- diff --git a/examples/test_case_data/localmeta/cube_desc/ut_inner_join_cube_partial.json b/examples/test_case_data/localmeta/cube_desc/ut_inner_join_cube_partial.json index 11d65bd..0e64166 100644 --- a/examples/test_case_data/localmeta/cube_desc/ut_inner_join_cube_partial.json +++ b/examples/test_case_data/localmeta/cube_desc/ut_inner_join_cube_partial.json @@ -130,13 +130,13 @@ }, { "name": "SELLER_COUNTRY_ABBR", - "table": "SELLER_ACCOUNT", - "column": "COUNTRY_ABBR" + "table": "TEST_KYLIN_FACT", + "column": "SELLER_COUNTRY_ABBR" }, { "name": "BUYER_COUNTRY_ABBR", - "table": "BUYER_ACCOUNT", - "column": "COUNTRY_ABBR" + "table": "TEST_KYLIN_FACT", + "column": "BUYER_COUNTRY_ABBR" }, { "name": "BUYER_COUNTRY_NAME", @@ -237,18 +237,20 @@ "encoding": "dict" }, { - "column": "SELLER_ACCOUNT.COUNTRY_ABBR", + "column": "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", "encoding": "dict" }, { - "column": "BUYER_ACCOUNT.COUNTRY_ABBR", + "column": "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR", "encoding": "dict" } ] }, "signature": null, "null_string": null, - "hbase_mapping": { "column_family": [ ] }, + "hbase_mapping": { + "column_family": [] + }, "aggregation_groups": [ { "includes": [ @@ -280,7 +282,7 @@ "TEST_KYLIN_FACT.DEAL_YEAR" ] ], - "dim_cap" : 3 + "dim_cap": 3 } }, { @@ -306,8 +308,8 @@ "BUYER_ACCOUNT.ACCOUNT_SELLER_LEVEL", "BUYER_ACCOUNT.ACCOUNT_COUNTRY", "BUYER_COUNTRY.NAME", - "SELLER_ACCOUNT.COUNTRY_ABBR", - "BUYER_ACCOUNT.COUNTRY_ABBR" + "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR" ], "select_rule": { "hierarchy_dims": [], @@ -325,8 +327,8 @@ "TEST_KYLIN_FACT.LSTG_FORMAT_NAME", "TEST_KYLIN_FACT.LSTG_SITE_ID", "TEST_KYLIN_FACT.SLR_SEGMENT_CD", - "SELLER_ACCOUNT.COUNTRY_ABBR", - "BUYER_ACCOUNT.COUNTRY_ABBR" + "TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR", + "TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR" ], [ "TEST_KYLIN_FACT.SELLER_ID", @@ -346,7 +348,7 @@ "BUYER_COUNTRY.NAME" ] ], - "dim_cap" : 3 + "dim_cap": 3 } } ], http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/examples/test_case_data/localmeta/model_desc/ci_inner_join_model.json ---------------------------------------------------------------------- diff --git a/examples/test_case_data/localmeta/model_desc/ci_inner_join_model.json b/examples/test_case_data/localmeta/model_desc/ci_inner_join_model.json index 5225cf3..dbedc66 100644 --- a/examples/test_case_data/localmeta/model_desc/ci_inner_join_model.json +++ b/examples/test_case_data/localmeta/model_desc/ci_inner_join_model.json @@ -127,21 +127,47 @@ "columnName": "DEAL_AMOUNT", "expression": "PRICE * ITEM_COUNT", "datatype": "decimal", - "comment": "deal amount of inner join model" + "comment": "deal amount of inner join model (with legacy expression format)" }, { "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", "columnName": "DEAL_YEAR", - "expression": "year(CAL_DT)", + "expression": "year(TEST_KYLIN_FACT.CAL_DT)", "datatype": "integer", - "comment": "the year of the deal of the inner join model" + "comment": "the year of the deal" }, { - "tableIdentity": "DEFAULT.TEST_ACCOUNT", - "columnName": "COUNTRY_ABBR", - "expression": "SUBSTR(ACCOUNT_COUNTRY,0,1)", + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "BUYER_ID_AND_COUNTRY_NAME", + "expression": "CONCAT(BUYER_ACCOUNT.ACCOUNT_ID, BUYER_COUNTRY.NAME)", + "datatype": "string", + "comment": "synthetically concat buyer's account id and buyer country" + }, + { + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "SELLER_ID_AND_COUNTRY_NAME", + "expression": "CONCAT(SELLER_ACCOUNT.ACCOUNT_ID, SELLER_COUNTRY.NAME)", + "datatype": "string", + "comment": "synthetically concat seller's account id and seller country" + }, + { + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "BUYER_COUNTRY_ABBR", + "expression": "SUBSTR(BUYER_ACCOUNT.ACCOUNT_COUNTRY,0,1)", + "datatype": "string", + "comment": "first char of country of buyer account" + }, + { + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "SELLER_COUNTRY_ABBR", + "expression": "SUBSTR(SELLER_ACCOUNT.ACCOUNT_COUNTRY,0,1)", "datatype": "string", - "comment": "first char of country of the inner join model" + "comment": "first char of country of seller account" } ], "dimensions": [ @@ -157,7 +183,11 @@ "SLR_SEGMENT_CD", "SELLER_ID", "TEST_COUNT_DISTINCT_BITMAP", - "DEAL_YEAR" + "DEAL_YEAR", + "SELLER_COUNTRY_ABBR", + "BUYER_COUNTRY_ABBR", + "SELLER_ID_AND_COUNTRY_NAME", + "BUYER_ID_AND_COUNTRY_NAME" ] }, { @@ -177,8 +207,7 @@ "ACCOUNT_BUYER_LEVEL", "ACCOUNT_SELLER_LEVEL", "ACCOUNT_COUNTRY", - "ACCOUNT_CONTACT", - "COUNTRY_ABBR" + "ACCOUNT_CONTACT" ] }, { @@ -188,8 +217,7 @@ "ACCOUNT_BUYER_LEVEL", "ACCOUNT_SELLER_LEVEL", "ACCOUNT_COUNTRY", - "ACCOUNT_CONTACT", - "COUNTRY_ABBR" + "ACCOUNT_CONTACT" ] }, { http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/examples/test_case_data/localmeta/model_desc/ci_left_join_model.json ---------------------------------------------------------------------- diff --git a/examples/test_case_data/localmeta/model_desc/ci_left_join_model.json b/examples/test_case_data/localmeta/model_desc/ci_left_join_model.json index 0058425..7220b4d 100644 --- a/examples/test_case_data/localmeta/model_desc/ci_left_join_model.json +++ b/examples/test_case_data/localmeta/model_desc/ci_left_join_model.json @@ -125,23 +125,49 @@ { "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", "columnName": "DEAL_AMOUNT", - "expression": "PRICE * ITEM_COUNT", + "expression": "PRICE * ITEM_COUNT", "datatype": "decimal", - "comment": "deal amount of left join model" + "comment": "deal amount of left join model (with legacy expression format)" }, { "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", "columnName": "DEAL_YEAR", - "expression": "year(CAL_DT)", + "expression": "year(TEST_KYLIN_FACT.CAL_DT)", "datatype": "integer", - "comment": "the year of the deal of the left join model" + "comment": "the year of the deal" }, { - "tableIdentity": "DEFAULT.TEST_ACCOUNT", - "columnName": "COUNTRY_ABBR", - "expression": "SUBSTR(ACCOUNT_COUNTRY,0,1)", + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "BUYER_ID_AND_COUNTRY_NAME", + "expression": "CONCAT(BUYER_ACCOUNT.ACCOUNT_ID, BUYER_COUNTRY.NAME)", + "datatype": "string", + "comment": "synthetically concat buyer's account id and buyer country" + }, + { + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "SELLER_ID_AND_COUNTRY_NAME", + "expression": "CONCAT(SELLER_ACCOUNT.ACCOUNT_ID, SELLER_COUNTRY.NAME)", + "datatype": "string", + "comment": "synthetically concat seller's account id and seller country" + }, + { + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "BUYER_COUNTRY_ABBR", + "expression": "SUBSTR(BUYER_ACCOUNT.ACCOUNT_COUNTRY,0,1)", + "datatype": "string", + "comment": "first char of country of buyer account" + }, + { + "tableIdentity": "DEFAULT.TEST_KYLIN_FACT", + "tableAlias": "TEST_KYLIN_FACT", + "columnName": "SELLER_COUNTRY_ABBR", + "expression": "SUBSTR(SELLER_ACCOUNT.ACCOUNT_COUNTRY,0,1)", "datatype": "string", - "comment": "first char of country of the left join model" + "comment": "first char of country of seller account" } ], "dimensions": [ @@ -157,7 +183,11 @@ "SLR_SEGMENT_CD", "SELLER_ID", "TEST_COUNT_DISTINCT_BITMAP", - "DEAL_YEAR" + "DEAL_YEAR", + "SELLER_COUNTRY_ABBR", + "BUYER_COUNTRY_ABBR", + "SELLER_ID_AND_COUNTRY_NAME", + "BUYER_ID_AND_COUNTRY_NAME" ] }, { @@ -177,8 +207,7 @@ "ACCOUNT_BUYER_LEVEL", "ACCOUNT_SELLER_LEVEL", "ACCOUNT_COUNTRY", - "ACCOUNT_CONTACT", - "COUNTRY_ABBR" + "ACCOUNT_CONTACT" ] }, { @@ -188,8 +217,7 @@ "ACCOUNT_BUYER_LEVEL", "ACCOUNT_SELLER_LEVEL", "ACCOUNT_COUNTRY", - "ACCOUNT_CONTACT", - "COUNTRY_ABBR" + "ACCOUNT_CONTACT" ] }, { http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_computedcolumn/query01.sql ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_computedcolumn/query01.sql b/kylin-it/src/test/resources/query/sql_computedcolumn/query01.sql index 5661c79..6aba6ce 100644 --- a/kylin-it/src/test/resources/query/sql_computedcolumn/query01.sql +++ b/kylin-it/src/test/resources/query/sql_computedcolumn/query01.sql @@ -10,5 +10,5 @@ ON TEST_KYLIN_FACT.LEAF_CATEG_ID = TEST_CATEGORY_GROUPINGS.LEAF_CATEG_ID AND TES INNER JOIN TEST_COUNTRY as SELLER_COUNTRY ON SELLER_ACCOUNT.ACCOUNT_COUNTRY = SELLER_COUNTRY.COUNTRY -where SELLER_ACCOUNT.ACCOUNT_SELLER_LEVEL=1 and SELLER_ACCOUNT.COUNTRY_ABBR in ('I', 'F') +where SELLER_ACCOUNT.ACCOUNT_SELLER_LEVEL=1 and TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR in ('I', 'F') group by SELLER_COUNTRY.NAME, DEAL_YEAR http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_computedcolumn/query02.sql ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_computedcolumn/query02.sql b/kylin-it/src/test/resources/query/sql_computedcolumn/query02.sql index 0e84301..3feafee 100644 --- a/kylin-it/src/test/resources/query/sql_computedcolumn/query02.sql +++ b/kylin-it/src/test/resources/query/sql_computedcolumn/query02.sql @@ -17,5 +17,5 @@ INNER JOIN TEST_COUNTRY as SELLER_COUNTRY ON SELLER_ACCOUNT.ACCOUNT_COUNTRY = SELLER_COUNTRY.COUNTRY -where SELLER_ACCOUNT.ACCOUNT_SELLER_LEVEL=1 and SELLER_ACCOUNT.COUNTRY_ABBR in ('T', 'R') and BUYER_ACCOUNT.COUNTRY_ABBR in ('T', 'R') +where SELLER_ACCOUNT.ACCOUNT_SELLER_LEVEL=1 and TEST_KYLIN_FACT.SELLER_COUNTRY_ABBR in ('T', 'R') and TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR in ('T', 'R') group by SELLER_COUNTRY.NAME, DEAL_YEAR http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_computedcolumn/query03.sql ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_computedcolumn/query03.sql b/kylin-it/src/test/resources/query/sql_computedcolumn/query03.sql index ff8a570..06eabeb 100644 --- a/kylin-it/src/test/resources/query/sql_computedcolumn/query03.sql +++ b/kylin-it/src/test/resources/query/sql_computedcolumn/query03.sql @@ -17,5 +17,5 @@ INNER JOIN TEST_COUNTRY as SELLER_COUNTRY ON SELLER_ACCOUNT.ACCOUNT_COUNTRY = SELLER_COUNTRY.COUNTRY -where SELLER_ACCOUNT.ACCOUNT_SELLER_LEVEL=1 and "SELLER_ACCOUNT"."COUNTRY_ABBR" in ('T', 'R') and BUYER_ACCOUNT.COUNTRY_ABBR in ('T', 'R') +where SELLER_ACCOUNT.ACCOUNT_SELLER_LEVEL=1 and "TEST_KYLIN_FACT"."SELLER_COUNTRY_ABBR" in ('T', 'R') and TEST_KYLIN_FACT.BUYER_COUNTRY_ABBR in ('T', 'R') group by SELLER_COUNTRY.NAME, DEAL_YEAR http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_verifyCount/query01.sql.expected ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_verifyCount/query01.sql.expected b/kylin-it/src/test/resources/query/sql_verifyCount/query01.sql.expected index 11636e7..d2f0772 100644 --- a/kylin-it/src/test/resources/query/sql_verifyCount/query01.sql.expected +++ b/kylin-it/src/test/resources/query/sql_verifyCount/query01.sql.expected @@ -1,2 +1,2 @@ * -13 +17 http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_verifyCount/query03.sql.expected ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_verifyCount/query03.sql.expected b/kylin-it/src/test/resources/query/sql_verifyCount/query03.sql.expected index 349103a..3097aec 100644 --- a/kylin-it/src/test/resources/query/sql_verifyCount/query03.sql.expected +++ b/kylin-it/src/test/resources/query/sql_verifyCount/query03.sql.expected @@ -1,2 +1,2 @@ 10 -15 +19 http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_verifyCount/query04.sql.expected ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_verifyCount/query04.sql.expected b/kylin-it/src/test/resources/query/sql_verifyCount/query04.sql.expected index d10e701..0b28614 100644 --- a/kylin-it/src/test/resources/query/sql_verifyCount/query04.sql.expected +++ b/kylin-it/src/test/resources/query/sql_verifyCount/query04.sql.expected @@ -1,2 +1,2 @@ 100 -13 +17 http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_verifyCount/query10.sql.expected ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_verifyCount/query10.sql.expected b/kylin-it/src/test/resources/query/sql_verifyCount/query10.sql.expected index 11636e7..d2f0772 100644 --- a/kylin-it/src/test/resources/query/sql_verifyCount/query10.sql.expected +++ b/kylin-it/src/test/resources/query/sql_verifyCount/query10.sql.expected @@ -1,2 +1,2 @@ * -13 +17 http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/kylin-it/src/test/resources/query/sql_verifyCount/query11.sql.expected ---------------------------------------------------------------------- diff --git a/kylin-it/src/test/resources/query/sql_verifyCount/query11.sql.expected b/kylin-it/src/test/resources/query/sql_verifyCount/query11.sql.expected index 093e327..a21e30c 100644 --- a/kylin-it/src/test/resources/query/sql_verifyCount/query11.sql.expected +++ b/kylin-it/src/test/resources/query/sql_verifyCount/query11.sql.expected @@ -1,2 +1,2 @@ 10 -13 +17 http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/query/src/main/java/org/apache/kylin/query/adhoc/PushDownRunnerJdbcImpl.java ---------------------------------------------------------------------- diff --git a/query/src/main/java/org/apache/kylin/query/adhoc/PushDownRunnerJdbcImpl.java b/query/src/main/java/org/apache/kylin/query/adhoc/PushDownRunnerJdbcImpl.java index 8001880..751e6b0 100644 --- a/query/src/main/java/org/apache/kylin/query/adhoc/PushDownRunnerJdbcImpl.java +++ b/query/src/main/java/org/apache/kylin/query/adhoc/PushDownRunnerJdbcImpl.java @@ -119,4 +119,4 @@ public class PushDownRunnerJdbcImpl implements IPushDownRunner { } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/kylin/blob/aed840f9/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java ---------------------------------------------------------------------- diff --git a/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java b/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java index 28ee623..9df5557 100644 --- a/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java +++ b/query/src/main/java/org/apache/kylin/query/enumerator/LookupTableEnumerator.java @@ -71,7 +71,7 @@ public class LookupTableEnumerator implements Enumerator<Object[]> { this.allRows = table.getAllRows(); OLAPTable olapTable = (OLAPTable) olapContext.firstTableScan.getOlapTable(); - this.colDescs = olapTable.getExposedColumns(); + this.colDescs = olapTable.getSourceColumns(); this.current = new Object[colDescs.size()]; reset();