You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2014/09/26 23:07:28 UTC

git commit: [OPTIQ-425] Add FilterAggregateTransposeRule, that pushes a filter through an aggregate.

Repository: incubator-optiq
Updated Branches:
  refs/heads/master 232a8f4da -> a5665df97


[OPTIQ-425] Add FilterAggregateTransposeRule, that pushes a filter through an aggregate.


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/a5665df9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/a5665df9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/a5665df9

Branch: refs/heads/master
Commit: a5665df971c128bfcc83e143c61522fecff942e2
Parents: 232a8f4
Author: Harish Butani <hb...@hortonworks.com>
Authored: Fri Sep 26 12:37:42 2014 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Sep 26 13:40:06 2014 -0700

----------------------------------------------------------------------
 .../optiq/prepare/OptiqPrepareImpl.java         |   1 +
 .../net/hydromatic/optiq/tools/Programs.java    |   1 +
 .../rel/rules/AggregateFilterTransposeRule.java |   2 +
 .../rel/rules/FilterAggregateTransposeRule.java | 109 +++++++++++++++++++
 .../net/hydromatic/optiq/test/JdbcTest.java     |   7 +-
 .../org/eigenbase/test/RelOptRulesTest.java     |  10 +-
 .../org/eigenbase/test/RelOptRulesTest.xml      |  23 ++++
 7 files changed, 148 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java b/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
index a34d80c..9907a5b 100644
--- a/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
+++ b/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
@@ -132,6 +132,7 @@ public class OptiqPrepareImpl implements OptiqPrepare {
           PushFilterPastJoinRule.FILTER_ON_JOIN,
           RemoveDistinctAggregateRule.INSTANCE,
           ReduceAggregatesRule.INSTANCE,
+          FilterAggregateTransposeRule.INSTANCE,
           SwapJoinRule.INSTANCE,
           PushJoinThroughJoinRule.RIGHT,
           PushJoinThroughJoinRule.LEFT,

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/tools/Programs.java b/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
index cfa2cdb..2b7fe78 100644
--- a/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
+++ b/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
@@ -95,6 +95,7 @@ public class Programs {
           PushFilterPastJoinRule.FILTER_ON_JOIN,
           RemoveDistinctAggregateRule.INSTANCE,
           ReduceAggregatesRule.INSTANCE,
+          FilterAggregateTransposeRule.INSTANCE,
           SwapJoinRule.INSTANCE,
           PushJoinThroughJoinRule.RIGHT,
           PushJoinThroughJoinRule.LEFT,

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/main/java/org/eigenbase/rel/rules/AggregateFilterTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/AggregateFilterTransposeRule.java b/core/src/main/java/org/eigenbase/rel/rules/AggregateFilterTransposeRule.java
index 44a5818..06693fa 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/AggregateFilterTransposeRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/AggregateFilterTransposeRule.java
@@ -50,6 +50,8 @@ import com.google.common.collect.Lists;
  * away. The rule might be beneficial if the predicate is very expensive to
  * evaluate. The main use of the rule is to match a query that has a filter
  * under an aggregate to an existing aggregate table.
+ *
+ * @see org.eigenbase.rel.rules.FilterAggregateTransposeRule
  */
 public class AggregateFilterTransposeRule extends RelOptRule {
   public static final AggregateFilterTransposeRule INSTANCE =

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/main/java/org/eigenbase/rel/rules/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/eigenbase/rel/rules/FilterAggregateTransposeRule.java
new file mode 100644
index 0000000..0ff4b58
--- /dev/null
+++ b/core/src/main/java/org/eigenbase/rel/rules/FilterAggregateTransposeRule.java
@@ -0,0 +1,109 @@
+/*
+ * 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.eigenbase.rel.rules;
+
+import java.util.BitSet;
+import java.util.List;
+
+import org.eigenbase.rel.*;
+import org.eigenbase.relopt.*;
+import org.eigenbase.reltype.RelDataTypeField;
+import org.eigenbase.rex.*;
+
+import net.hydromatic.optiq.util.BitSets;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+/**
+ * Planner rule that pushes a {@link FilterRelBase}
+ * past a {@link AggregateRelBase}.
+ *
+ * @see org.eigenbase.rel.rules.AggregateFilterTransposeRule
+ */
+public class FilterAggregateTransposeRule extends RelOptRule {
+
+  /** The default instance of
+   * {@link FilterAggregateTransposeRule}.
+   *
+   * <p>It matches any kind of agg. or filter */
+  public static final FilterAggregateTransposeRule INSTANCE =
+      new FilterAggregateTransposeRule(FilterRelBase.class,
+          RelFactories.DEFAULT_FILTER_FACTORY,
+          AggregateRelBase.class);
+
+  private final RelFactories.FilterFactory filterFactory;
+
+  //~ Constructors -----------------------------------------------------------
+
+  /**
+   * Creates a PushFilterPastAggRule.
+   *
+   * <p>If {@code filterFactory} is null, creates the same kind of filter as
+   * matched in the rule. Similarly {@code aggregateFactory}.</p>
+   */
+  public FilterAggregateTransposeRule(
+      Class<? extends FilterRelBase> filterClass,
+      RelFactories.FilterFactory filterFactory,
+      Class<? extends AggregateRelBase> aggregateClass) {
+    super(
+        operand(filterClass,
+            operand(aggregateClass, any())));
+    this.filterFactory = filterFactory;
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  // implement RelOptRule
+  public void onMatch(RelOptRuleCall call) {
+    final FilterRelBase filterRel = call.rel(0);
+    final AggregateRelBase aggRel = call.rel(1);
+
+    final List<RexNode> conditions =
+        RelOptUtil.conjunctions(filterRel.getCondition());
+    final BitSet groupKeys = aggRel.getGroupSet();
+    final RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();
+    final List<RelDataTypeField> origFields =
+        aggRel.getRowType().getFieldList();
+    final int[] adjustments = new int[origFields.size()];
+    final List<RexNode> pushedConditions = Lists.newArrayList();
+
+    for (RexNode condition : conditions) {
+      BitSet rCols = RelOptUtil.InputFinder.bits(condition);
+      if (BitSets.contains(groupKeys, rCols)) {
+        pushedConditions.add(
+            condition.accept(
+                new RelOptUtil.RexInputConverter(rexBuilder, origFields,
+                    aggRel.getInput(0).getRowType().getFieldList(),
+                    adjustments)));
+      }
+    }
+
+    final RexNode pushedCondition = RexUtil.composeConjunction(rexBuilder,
+        pushedConditions, true);
+
+    if (pushedCondition != null) {
+      RelNode newFilterRel = filterFactory.createFilter(aggRel.getInput(0),
+          pushedCondition);
+      RelNode newAggRel = aggRel.copy(aggRel.getTraitSet(),
+          ImmutableList.of(newFilterRel));
+      call.transformTo(newAggRel);
+    }
+  }
+}
+
+// End FilterAggregateTransposeRule.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index d87476f..9ce3b1a 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -2072,10 +2072,9 @@ public class JdbcTest {
         .explainContains(
             "EnumerableCalcRel(expr#0..8=[{inputs}], c0=[$t3], c1=[$t2], c2=[$t1], c3=[$t0], c4=[$t8], c5=[$t8], c6=[$t6], c7=[$t4], c8=[$t7], c9=[$t5])\n"
             + "  EnumerableSortRel(sort0=[$3], sort1=[$2], sort2=[$1], sort3=[$8], dir0=[ASC-nulls-last], dir1=[ASC-nulls-last], dir2=[ASC-nulls-last], dir3=[ASC-nulls-last])\n"
-            + "    EnumerableCalcRel(expr#0..8=[{inputs}], expr#9=['%Jeanne%'], expr#10=[LIKE($t8, $t9)], proj#0..8=[{exprs}], $condition=[$t10])\n"
-            + "      EnumerableAggregateRel(group=[{0, 1, 2, 3, 4, 5, 6, 7, 8}])\n"
-            + "        EnumerableCalcRel(expr#0..9=[{inputs}], expr#10=[CAST($t0):INTEGER], expr#11=[1997], expr#12=[=($t10, $t11)], $f0=[$t1], $f1=[$t2], $f2=[$t3], $f3=[$t4], $f4=[$t5], $f5=[$t6], $f6=[$t7], $f7=[$t8], $f8=[$t9], $f9=[$t0], $condition=[$t12])\n"
-            + "          EnumerableTableAccessRel(table=[[foodmart, m{12, 18, 27, 28, 30, 35, 36, 37, 40, 46}]])")
+            + "    EnumerableAggregateRel(group=[{0, 1, 2, 3, 4, 5, 6, 7, 8}])\n"
+            + "      EnumerableCalcRel(expr#0..9=[{inputs}], expr#10=[CAST($t0):INTEGER], expr#11=[1997], expr#12=[=($t10, $t11)], expr#13=['%Jeanne%'], expr#14=[LIKE($t9, $t13)], expr#15=[AND($t12, $t14)], $f0=[$t1], $f1=[$t2], $f2=[$t3], $f3=[$t4], $f4=[$t5], $f5=[$t6], $f6=[$t7], $f7=[$t8], $f8=[$t9], $f9=[$t0], $condition=[$t15])\n"
+            + "        EnumerableTableAccessRel(table=[[foodmart, m{12, 18, 27, 28, 30, 35, 36, 37, 40, 46}]])")
         .runs();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java b/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
index b6bc208..095d7d4 100644
--- a/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
@@ -29,6 +29,7 @@ import org.eigenbase.rel.rules.AggregateProjectMergeRule;
 import org.eigenbase.rel.rules.CoerceInputsRule;
 import org.eigenbase.rel.rules.ConvertMultiJoinRule;
 import org.eigenbase.rel.rules.ExtractJoinFilterRule;
+import org.eigenbase.rel.rules.FilterAggregateTransposeRule;
 import org.eigenbase.rel.rules.FilterToCalcRule;
 import org.eigenbase.rel.rules.MergeCalcRule;
 import org.eigenbase.rel.rules.MergeProjectRule;
@@ -163,6 +164,14 @@ public class RelOptRulesTest extends RelOptTestBase {
         + " where d.name = 'Charlie'");
   }
 
+  @Test public void testPushFilterPastAgg() {
+    checkPlanning(
+        FilterAggregateTransposeRule.INSTANCE,
+        "select dname, c from"
+        + " (select name dname, count(*) as c from dept group by name) t"
+        + " where dname = 'Charlie'");
+  }
+
   @Test public void testSemiJoinRule() {
     final HepProgram preProgram =
         HepProgram.builder()
@@ -183,7 +192,6 @@ public class RelOptRulesTest extends RelOptTestBase {
   }
 
   protected void semiJoinTrim() {
-
     final DiffRepository diffRepos = getDiffRepos();
     String sql = diffRepos.expand(null, "${sql}");
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a5665df9/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
index 07eeb68..7016804 100644
--- a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
@@ -108,6 +108,29 @@ ProjectRel(EXPR$0=[1])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testPushFilterPastAgg">
+        <Resource name="sql">
+            <![CDATA[select dname, c from (select name dname, count(*) as c from dept group by name) t where dname = 'Charlie']]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+ProjectRel(DNAME=[$0], C=[$1])
+  FilterRel(condition=[=($0, 'Charlie')])
+    AggregateRel(group=[{0}], C=[COUNT()])
+      ProjectRel(DNAME=[$1])
+        TableAccessRel(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+ProjectRel(DNAME=[$0], C=[$1])
+  AggregateRel(group=[{0}], C=[COUNT()])
+    FilterRel(condition=[=($0, 'Charlie')])
+      ProjectRel(DNAME=[$1])
+        TableAccessRel(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testReduceAverage">
         <Resource name="sql">
             <![CDATA[select name, max(name), avg(deptno), min(name) from sales.dept group by name]]>