LENS-647 : Fix multi fact query with expressions
Project: http://git-wip-us.apache.org/repos/asf/incubator-lens/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-lens/commit/f1387c31 Tree: http://git-wip-us.apache.org/repos/asf/incubator-lens/tree/f1387c31 Diff: http://git-wip-us.apache.org/repos/asf/incubator-lens/diff/f1387c31 Branch: refs/heads/LENS-581 Commit: f1387c31537eb7f73ba2de503e7a17120df1e691 Parents: c8d38f7 Author: Amareshwari Sriramadasu <[email protected]> Authored: Fri Jul 10 12:19:10 2015 +0530 Committer: Amareshwari Sriramadasu <[email protected]> Committed: Fri Jul 10 12:19:10 2015 +0530 ---------------------------------------------------------------------- .../apache/lens/cube/parse/CandidateFact.java | 10 +- .../cube/parse/CandidateTablePruneCause.java | 9 +- .../lens/cube/parse/CubeQueryContext.java | 4 +- .../lens/cube/parse/ExpressionResolver.java | 65 ++++--- .../lens/cube/parse/TestBaseCubeQueries.java | 171 +++++++++++++------ 5 files changed, 174 insertions(+), 85 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java ---------------------------------------------------------------------- diff --git a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java index 63d2508..86c420b 100644 --- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java +++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateFact.java @@ -190,10 +190,10 @@ public class CandidateFact implements CandidateTable { int currentChild = 0; for (int i = 0; i < cubeql.getSelectAST().getChildCount(); i++) { ASTNode selectExpr = (ASTNode) this.selectAST.getChild(currentChild); - Set<String> exprCols = getColsInExpr(cubeCols, selectExpr); + Set<String> exprCols = getColsInExpr(cubeql, cubeCols, selectExpr); if (getColumns().containsAll(exprCols)) { selectIndices.add(i); - if (cubeql.getQueriedDimAttrs().containsAll(exprCols)) { + if (cubeql.getCube().getDimAttributeNames().containsAll(exprCols)) { dimFieldIndices.add(i); } ASTNode aliasNode = HQLParser.findNodeByPath(selectExpr, Identifier); @@ -225,7 +225,8 @@ public class CandidateFact implements CandidateTable { // TODO } - private Set<String> getColsInExpr(final Set<String> cubeCols, ASTNode expr) throws SemanticException { + private Set<String> getColsInExpr(final CubeQueryContext cubeql, final Set<String> cubeCols, + ASTNode expr) throws SemanticException { final Set<String> cubeColsInExpr = new HashSet<String>(); HQLParser.bft(expr, new ASTNodeVisitor() { @Override @@ -244,9 +245,10 @@ public class CandidateFact implements CandidateTable { cubeColsInExpr.add(column); } } else if (node.getToken().getType() == DOT) { + String alias = HQLParser.findNodeByPath(node, TOK_TABLE_OR_COL, Identifier).getText().toLowerCase(); ASTNode colIdent = (ASTNode) node.getChild(1); String column = colIdent.getText().toLowerCase(); - if (cubeCols.contains(column)) { + if (cubeql.getAliasForTableName(cubeql.getCube()).equalsIgnoreCase(alias) && cubeCols.contains(column)) { cubeColsInExpr.add(column); } } http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java ---------------------------------------------------------------------- diff --git a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java index 75d5581..9ea43bb 100644 --- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java +++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CandidateTablePruneCause.java @@ -36,10 +36,11 @@ import lombok.NoArgsConstructor; @JsonWriteNullProperties(false) @Data @NoArgsConstructor - public class CandidateTablePruneCause { public enum CandidateTablePruneCode { + // other fact set element is removed + ELEMENT_IN_SET_PRUNED("Other candidate from measure covering set is pruned"), FACT_NOT_AVAILABLE_IN_RANGE("No facts available for all of these time ranges: %s") { @Override Object[] getFormatPlaceholders(Set<CandidateTablePruneCause> causes) { @@ -70,6 +71,9 @@ public class CandidateTablePruneCause { return new String[]{columns.toString()}; } }, + // candidate table tries to get denormalized field from dimension and the + // referred dimension is invalid. + INVALID_DENORM_TABLE("Referred dimension is invalid in one of the candidate tables"), // column not valid in cube table COLUMN_NOT_VALID("Column not valid in cube table"), // column not found in cube table @@ -92,9 +96,6 @@ public class CandidateTablePruneCause { } } }, - // candidate table tries to get denormalized field from dimension and the - // referred dimension is invalid. - INVALID_DENORM_TABLE("Referred dimension is invalid in one of the candidate tables"), // missing storage tables for cube table MISSING_STORAGES("Missing storage tables for the cube table"), // no candidate storges for cube table, storage cause will have why each http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java ---------------------------------------------------------------------- diff --git a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java index 57c075c..39b13cc 100644 --- a/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java +++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/CubeQueryContext.java @@ -1196,10 +1196,12 @@ public class CubeQueryContext implements TrackQueriedColumns { Set<CandidateFact> cfacts = i.next(); if (!candidateFacts.containsAll(cfacts)) { LOG.info("Not considering fact table set:" + cfacts - + " as they have non candidate tables and facts missing because of" + pruneCause); + + " as they have non candidate tables and facts missing because of " + pruneCause); i.remove(); } } + // prune candidate facts + pruneCandidateFactWithCandidateSet(CandidateTablePruneCode.ELEMENT_IN_SET_PRUNED); } /** http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java ---------------------------------------------------------------------- diff --git a/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java b/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java index b2997dd..895cb06 100644 --- a/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java +++ b/lens-cube/src/main/java/org/apache/lens/cube/parse/ExpressionResolver.java @@ -32,6 +32,7 @@ import org.apache.lens.cube.metadata.CubeInterface; import org.apache.lens.cube.metadata.Dimension; import org.apache.lens.cube.metadata.ExprColumn; import org.apache.lens.cube.metadata.ExprColumn.ExprSpec; +import org.apache.lens.cube.parse.CandidateTablePruneCause.CandidateTablePruneCode; import org.apache.lens.cube.parse.HQLParser.ASTNodeVisitor; import org.apache.lens.cube.parse.HQLParser.TreeNode; @@ -204,6 +205,16 @@ class ExpressionResolver implements ContextRewriter { } return false; } + + boolean isEvaluable(CandidateTable cTable) { + if (directlyAvailableIn.contains(cTable)) { + return true; + } + if (evaluableExpressions.get(cTable) == null) { + return false; + } + return !evaluableExpressions.get(cTable).isEmpty(); + } } static class ExprSpecContext implements TrackQueriedColumns { @@ -395,13 +406,7 @@ class ExpressionResolver implements ContextRewriter { // checks if expr is evaluable public boolean isEvaluable(String expr, CandidateTable cTable) { ExpressionContext ec = getExpressionContext(expr, cubeql.getAliasForTableName(cTable.getBaseTable().getName())); - if (ec.directlyAvailableIn.contains(cTable)) { - return true; - } - if (ec.evaluableExpressions.get(cTable) == null) { - return false; - } - return !ec.evaluableExpressions.get(cTable).isEmpty(); + return ec.isEvaluable(cTable); } /** @@ -671,24 +676,40 @@ class ExpressionResolver implements ContextRewriter { cubeql.getExprCtx().pruneExpressions(); // prune candidate facts without any valid expressions if (cubeql.getCube() != null && !cubeql.getCandidateFacts().isEmpty()) { - for (Iterator<CandidateFact> i = cubeql.getCandidateFacts().iterator(); i.hasNext();) { - CandidateFact cfact = i.next(); - for (Map.Entry<String, Set<ExpressionContext>> ecEntry : exprCtx.allExprsQueried.entrySet()) { - Set<ExpressionContext> ecSet = ecEntry.getValue(); - for (ExpressionContext ec : ecSet) { - if (ec.getSrcTable().getName().equals(cfact.getBaseTable().getName())) { - if (!ec.directlyAvailableIn.contains(cfact) - && (ec.evaluableExpressions.get(cfact) == null - || ec.evaluableExpressions.get(cfact).isEmpty())) { - log.info("Not considering fact table:{} as {} is not evaluable", cfact, ec.exprCol.getName()); - cubeql.addFactPruningMsgs(cfact.fact, - CandidateTablePruneCause.expressionNotEvaluable(ec.exprCol.getName())); - i.remove(); + for (Map.Entry<String, Set<ExpressionContext>> ecEntry : exprCtx.allExprsQueried.entrySet()) { + String expr = ecEntry.getKey(); + Set<ExpressionContext> ecSet = ecEntry.getValue(); + for (ExpressionContext ec : ecSet) { + if (ec.getSrcTable().getName().equals(cubeql.getCube().getName())) { + if (cubeql.getQueriedExprsWithMeasures().contains(expr)) { + for (Iterator<Set<CandidateFact>> sItr = cubeql.getCandidateFactSets().iterator(); sItr.hasNext();) { + Set<CandidateFact> factSet = sItr.next(); + boolean evaluableInSet = false; + for (CandidateFact cfact : factSet) { + if (ec.isEvaluable(cfact)) { + evaluableInSet = true; + } + } + if (!evaluableInSet) { + log.info("Not considering fact table set:{} as {} is not evaluable", factSet, ec.exprCol.getName()); + sItr.remove(); + } + } + } else { + for (Iterator<CandidateFact> i = cubeql.getCandidateFacts().iterator(); i.hasNext();) { + CandidateFact cfact = i.next(); + if (!ec.isEvaluable(cfact)) { + log.info("Not considering fact table:{} as {} is not evaluable", cfact, ec.exprCol.getName()); + cubeql.addFactPruningMsgs(cfact.fact, + CandidateTablePruneCause.expressionNotEvaluable(ec.exprCol.getName())); + i.remove(); + } } } } } } + cubeql.pruneCandidateFactWithCandidateSet(CandidateTablePruneCode.EXPRESSION_NOT_EVALUABLE); } // prune candidate dims without any valid expressions if (cubeql.getDimensions() != null && !cubeql.getDimensions().isEmpty()) { @@ -699,9 +720,7 @@ class ExpressionResolver implements ContextRewriter { Set<ExpressionContext> ecSet = ecEntry.getValue(); for (ExpressionContext ec : ecSet) { if (ec.getSrcTable().getName().equals(cdim.getBaseTable().getName())) { - if (!ec.directlyAvailableIn.contains(cdim) - && (ec.evaluableExpressions.get(cdim) == null - || ec.evaluableExpressions.get(cdim).isEmpty())) { + if (!ec.isEvaluable(cdim)) { log.info("Not considering dim table:{} as {} is not evaluable", cdim, ec.exprCol.getName()); cubeql.addDimPruningMsgs(dim, cdim.dimtable, CandidateTablePruneCause.expressionNotEvaluable(ec.exprCol.getName())); http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/f1387c31/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java ---------------------------------------------------------------------- diff --git a/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java b/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java index 53996c4..f65bd28 100644 --- a/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java +++ b/lens-cube/src/test/java/org/apache/lens/cube/parse/TestBaseCubeQueries.java @@ -33,6 +33,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.lens.cube.metadata.UpdatePeriod; +import org.apache.lens.cube.parse.CandidateTablePruneCause.CandidateTablePruneCode; import org.apache.lens.server.api.error.LensException; import org.apache.commons.lang.time.DateUtils; @@ -42,6 +43,7 @@ import org.apache.hadoop.hive.ql.parse.ASTNode; import org.apache.hadoop.hive.ql.parse.SemanticException; import org.antlr.runtime.CommonToken; +import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -83,18 +85,18 @@ public class TestBaseCubeQueries extends TestQueryRewrite { String columnSetsStr = matcher.group(1); assertNotEquals(columnSetsStr.indexOf("stateid"), -1); assertNotEquals(columnSetsStr.indexOf("msr3, msr13"), -1); - assertEquals(pruneCauses.getDetails(), - new HashMap<String, List<CandidateTablePruneCause>>() { - { - put("testfact3_base,testfact3_raw_base", Arrays.asList(CandidateTablePruneCause.columnNotFound("stateid"))); - put("testfact_deprecated,testfact2_raw_base,testfact2_base", - Arrays.asList(CandidateTablePruneCause.columnNotFound("msr3", "msr13"))); - } - } - ); + assertEquals(pruneCauses.getDetails().get("testfact3_base,testfact3_raw_base"), + Arrays.asList(CandidateTablePruneCause.columnNotFound("stateid"))); + assertEquals(pruneCauses.getDetails().get("testfact_deprecated,testfact2_raw_base,testfact2_base"), + Arrays.asList(CandidateTablePruneCause.columnNotFound("msr3", "msr13"))); + assertTrue(pruneCauses.getDetails().containsKey("testfact1_base,testfact1_raw_base") + || pruneCauses.getDetails().containsKey("testfact1_raw_base,testfact1_base")); + String fact1BaseKey = pruneCauses.getDetails().containsKey("testfact1_base,testfact1_raw_base") + ? "testfact1_base,testfact1_raw_base" : "testfact1_raw_base,testfact1_base"; + assertEquals(pruneCauses.getDetails().get(fact1BaseKey), + Arrays.asList(new CandidateTablePruneCause(CandidateTablePruneCode.ELEMENT_IN_SET_PRUNED))); } - @Test public void testCommonDimensions() throws Exception { String hqlQuery = rewrite("select dim1, SUM(msr1) from basecube" + " where " + TWO_DAYS_RANGE, conf); @@ -132,8 +134,15 @@ public class TestBaseCubeQueries extends TestQueryRewrite { } @Test - public void testMultipleFacts() throws Exception { - String hqlQuery = rewrite("select roundedmsr2, msr12 from basecube" + " where " + TWO_DAYS_RANGE, conf); + public void testMultiFactQueryWithNoDimensionsSelected() throws Exception { + CubeQueryContext ctx = rewriteCtx("select roundedmsr2, msr12 from basecube" + " where " + TWO_DAYS_RANGE, conf); + Set<String> candidateFacts = new HashSet<String>(); + for (CandidateFact cfact : ctx.getCandidateFacts()) { + candidateFacts.add(cfact.getName().toLowerCase()); + } + Assert.assertTrue(candidateFacts.contains("testfact1_base")); + Assert.assertTrue(candidateFacts.contains("testfact2_base")); + String hqlQuery = ctx.toHQL(); String expected1 = getExpectedQuery(cubeName, "select sum(basecube.msr12) msr12 FROM ", null, null, getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); @@ -147,17 +156,20 @@ public class TestBaseCubeQueries extends TestQueryRewrite { || lower.startsWith("select mq1.roundedmsr2 roundedmsr2, mq2.msr12 msr12 from "), hqlQuery); assertTrue(lower.contains("mq1 full outer join") && lower.endsWith("mq2"), hqlQuery); assertFalse(lower.contains("<=>"), hqlQuery); + } - hqlQuery = rewrite("select dim1, roundedmsr2, msr12 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + @Test + public void testMultiFactQueryWithSingleCommonDimension() throws Exception { + String hqlQuery = rewrite("select dim1, roundedmsr2, msr12 from basecube" + " where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, sum(basecube.msr12) msr12 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact1_BASE")); TestCubeRewriter.compareContains(expected1, hqlQuery); TestCubeRewriter.compareContains(expected2, hqlQuery); - lower = hqlQuery.toLowerCase(); + String lower = hqlQuery.toLowerCase(); assertTrue( lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq2.roundedmsr2 roundedmsr2, mq1.msr12 msr12 from ") || lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq1.roundedmsr2 roundedmsr2, mq2.msr12 msr12" @@ -165,18 +177,44 @@ public class TestBaseCubeQueries extends TestQueryRewrite { assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"), hqlQuery); + } + @Test + public void testMultiFactQueryWithSingleCommonDimensionWithLightestFactFirst() throws Exception { + Configuration tConf = new Configuration(conf); + tConf.setBoolean(CubeQueryConfUtil.LIGHTEST_FACT_FIRST, true); + String hqlQuery = rewrite("select dim1, roundedmsr2, msr12 from basecube" + " where " + TWO_DAYS_RANGE, tConf); + String expected1 = + getExpectedQuery(cubeName, "select basecube.dim1 dim1, sum(basecube.msr12) msr12 FROM ", null, + " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); + String expected2 = + getExpectedQuery(cubeName, "select basecube.dim1 dim1, round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null, + " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact1_BASE")); + TestCubeRewriter.compareContains(expected1, hqlQuery); + TestCubeRewriter.compareContains(expected2, hqlQuery); + String lower = hqlQuery.toLowerCase(); + assertTrue( + lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq2.roundedmsr2 roundedmsr2, mq1.msr12 msr12 from ") + || lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq1.roundedmsr2 roundedmsr2, mq2.msr12 msr12" + + " from "), hqlQuery); + + assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"), + hqlQuery); + } + + @Test + public void testMultiFactQueryWithSingleCommonDimensionWithColumnsSwapped() throws Exception { // columns in select interchanged - hqlQuery = rewrite("select dim1, msr12, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String hqlQuery = rewrite("select dim1, msr12, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, sum(basecube.msr12) msr12 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact1_BASE")); TestCubeRewriter.compareContains(expected1, hqlQuery); TestCubeRewriter.compareContains(expected2, hqlQuery); - lower = hqlQuery.toLowerCase(); + String lower = hqlQuery.toLowerCase(); assertTrue( lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq2.msr12 msr12, mq1.roundedmsr2 roundedmsr2 from ") || lower.startsWith("select coalesce(mq1.dim1, mq2.dim1) dim1, mq1.msr12 msr12, mq2.roundedmsr2 roundedmsr2" @@ -184,13 +222,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite { assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"), hqlQuery); + } + @Test + public void testMultiFactQueryInvolvingThreeFactTables() throws Exception { // query with 3 fact tables - hqlQuery = rewrite("select dim1, msr12, roundedmsr2, msr13, msr3 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String hqlQuery = rewrite("select dim1, msr12, roundedmsr2, msr13, msr3 from basecube where " + TWO_DAYS_RANGE, + conf); + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, sum(basecube.msr12) msr12 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, round(sum(basecube.msr2)/1000) roundedmsr2, max(basecube.msr3) msr3 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact1_BASE")); @@ -221,13 +263,16 @@ public class TestBaseCubeQueries extends TestQueryRewrite { + " mq2.roundedmsr2 roundedmsr2, mq1.msr13 msr13, mq2.msr3 msr3 from "), hqlQuery); assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.contains("mq2 full outer join ") && hqlQuery.endsWith("mq3 on mq1.dim1 <=> mq2.dim1 AND mq1.dim1 <=> mq3.dim1"), hqlQuery); + } + @Test + public void testMultiFactQueryWithTwoCommonDimensions() throws Exception { // query two dim attributes - hqlQuery = rewrite("select dim1, dim11, msr12, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String hqlQuery = rewrite("select dim1, dim11, msr12, roundedmsr2 from basecube where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, basecube.dim11 dim11, sum(basecube.msr12) msr12 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, basecube.dim11 dim11, round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact1_BASE")); @@ -242,13 +287,16 @@ public class TestBaseCubeQueries extends TestQueryRewrite { assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1 AND mq1.dim11 <=> mq2.dim11"), hqlQuery); + } + @Test + public void testMultiFactQueryWithNoAggregates() throws Exception { // no aggregates in the query - hqlQuery = rewrite("select dim1, msr11, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String hqlQuery = rewrite("select dim1, msr11, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, basecube.msr11 msr11 FROM ", null, null, getWhereForHourly2days(cubeName, "C1_testfact2_raw_base")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, round(basecube.msr2/1000) roundedmsr2 FROM ", null, null, getWhereForHourly2days(cubeName, "C1_testfact1_raw_base")); TestCubeRewriter.compareContains(expected1, hqlQuery); @@ -260,14 +308,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite { assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"), hqlQuery); + } + @Test + public void testMultiFactQueryWithColumnAliases() throws Exception { // query with aliases passed - hqlQuery = + String hqlQuery = rewrite("select dim1 d1, msr12 `my msr12`, roundedmsr2 m2 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 d1, sum(basecube.msr12) expr2 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 d1, round(sum(basecube.msr2)/1000) m2 FROM ", null, " group by basecube.dim1", getWhereForDailyAndHourly2days(cubeName, "C1_testFact1_BASE")); TestCubeRewriter.compareContains(expected1, hqlQuery); @@ -278,13 +329,16 @@ public class TestBaseCubeQueries extends TestQueryRewrite { hqlQuery.toLowerCase().startsWith("select coalesce(mq1.d1, mq2.d1) d1, mq1.expr2 `my msr12`, mq2.m2 m2 from "), hqlQuery); assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.d1 <=> mq2.d1"), hqlQuery); + } - // query with non default aggregate - hqlQuery = rewrite("select dim1, avg(msr12), avg(msr2) from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + @Test + public void testMultiFactQueryWithNoDefaultAggregates() throws Exception { + // query with non default aggregate + String hqlQuery = rewrite("select dim1, avg(msr12), avg(msr2) from basecube" + " where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, avg(basecube.msr12) msr12 FROM ", null, " group by basecube.dim1", getWhereForHourly2days(cubeName, "C1_testfact2_raw_base")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim1 dim1, avg(basecube.msr2)) msr2 FROM ", null, " group by basecube.dim1", getWhereForHourly2days(cubeName, "C1_testfact1_raw_base")); TestCubeRewriter.compareContains(expected1, hqlQuery); @@ -296,14 +350,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite { assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim1 <=> mq2.dim1"), hqlQuery); + } + @Test + public void testMultiFactQueryWithJoins() throws Exception { // query with join - hqlQuery = rewrite("select testdim2.name, msr12, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String hqlQuery = rewrite("select testdim2.name, msr12, roundedmsr2 from basecube where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select testdim2.name name, sum(basecube.msr12) msr12 FROM ", " JOIN " + getDbName() + "c1_testdim2tbl testdim2 ON basecube.dim2 = " + " testdim2.id and (testdim2.dt = 'latest') ", null, " group by testdim2.name", null, getWhereForDailyAndHourly2days(cubeName, "C1_testFact2_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select testdim2.name name, round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", " JOIN " + getDbName() + "c1_testdim2tbl testdim2 ON basecube.dim2 = " + " testdim2.id and (testdim2.dt = 'latest') ", null, " group by testdim2.name", null, @@ -316,14 +373,17 @@ public class TestBaseCubeQueries extends TestQueryRewrite { "select coalesce(mq1.name, mq2.name) name, mq1.msr12 msr12, mq2.roundedmsr2 roundedmsr2 from "), hqlQuery); assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.name <=> mq2.name"), hqlQuery); + } + @Test + public void testMultiFactQueryWithDenormColumn() throws Exception { // query with denorm variable - hqlQuery = rewrite("select dim2, msr13, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = + String hqlQuery = rewrite("select dim2, msr13, roundedmsr2 from basecube" + " where " + TWO_DAYS_RANGE, conf); + String expected1 = getExpectedQuery(cubeName, "select testdim2.id dim2, max(basecube.msr13) msr13 FROM ", " JOIN " + getDbName() + "c1_testdim2tbl testdim2 ON basecube.dim12 = " + " testdim2.id and (testdim2.dt = 'latest') ", null, " group by testdim2.id", null, getWhereForHourly2days(cubeName, "C1_testFact3_RAW_BASE")); - expected2 = + String expected2 = getExpectedQuery(cubeName, "select basecube.dim2 dim2, round(sum(basecube.msr2)/1000) roundedmsr2 FROM ", null, " group by basecube.dim2", getWhereForHourly2days(cubeName, "C1_testfact1_raw_base")); TestCubeRewriter.compareContains(expected1, hqlQuery); @@ -334,33 +394,38 @@ public class TestBaseCubeQueries extends TestQueryRewrite { "select coalesce(mq1.dim2, mq2.dim2) dim2, mq1.msr13 msr13, mq2.roundedmsr2 roundedmsr2 from "), hqlQuery); assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.dim2 <=> mq2.dim2"), hqlQuery); + } + @Test + public void testMultiFactQueryWithExpressionInvolvingDenormVariable() throws Exception { // query with expression - // TODO allow expression to be answered from denorm columns - /* - hqlQuery = + // The expression to be answered from denorm columns + String hqlQuery = rewrite( "select booleancut, round(sum(msr2)/1000), avg(msr13 + msr14) from basecube" + " where " + TWO_DAYS_RANGE, conf); - expected1 = - getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND testdim2.id != 10 expr1," + String expected1 = + getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND testdim2.id != 10 booleancut," + " avg(basecube.msr13 + basecube.msr14) expr3 FROM ", " JOIN " + getDbName() + "c1_testdim2tbl testdim2 ON basecube.dim12 = " + " testdim2.id and (testdim2.dt = 'latest') ", null, " group by basecube.dim1 != 'x' AND testdim2.id != 10", null, getWhereForHourly2days(cubeName, "C1_testfact3_raw_base")); - expected2 = - getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND basecube.dim2 != 10 expr1," + String expected2 = + getExpectedQuery(cubeName, "select basecube.dim1 != 'x' AND basecube.dim2 != 10 booleancut," + " round(sum(basecube.msr2)/1000) msr2 FROM ", null, " group by basecube.dim1 != 'x' AND basecube.dim2 != 10", getWhereForHourly2days(cubeName, "C1_testfact1_raw_base")); TestCubeRewriter.compareContains(expected1, hqlQuery); TestCubeRewriter.compareContains(expected2, hqlQuery); assertTrue(hqlQuery.toLowerCase() - .startsWith("select coalesce(mq1.expr1, mq2.expr1) expr1, mq2.msr2 msr2, mq1.expr3 expr3 from ") + .startsWith("select coalesce(mq1.booleancut, mq2.booleancut) booleancut, mq2.msr2 msr2," + + " mq1.expr3 expr3 from ") || hqlQuery.toLowerCase() - .startsWith("select coalesce(mq1.expr1, mq2.expr1) expr1, mq1.msr2 msr2, mq2.expr3 expr3 from "), hqlQuery); - assertTrue(hqlQuery.contains("mq1 full outer join ") && hqlQuery.endsWith("mq2 on mq1.expr1 <=> mq2.expr1"), - hqlQuery);*/ + .startsWith("select coalesce(mq1.booleancut, mq2.booleancut) booleancut, mq1.msr2 msr2," + + " mq2.expr3 expr3 from "), hqlQuery); + assertTrue(hqlQuery.contains("mq1 full outer join ") + && hqlQuery.endsWith("mq2 on mq1.booleancut <=> mq2.booleancut"), + hqlQuery); } @Test
