This is an automated email from the ASF dual-hosted git repository.

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit bb3889e860cc7472e31ba39ac6d3d5a0e3c59463
Author: Julian Hyde <[email protected]>
AuthorDate: Tue Sep 24 14:03:32 2019 -0700

    [CALCITE-3369] In LatticeSuggester, recommend lattices based on UNION 
queries
---
 .../calcite/materialize/LatticeSuggester.java      | 30 +++++++++++-----
 .../calcite/materialize/LatticeSuggesterTest.java  | 41 +++++++++++++++++++---
 2 files changed, 58 insertions(+), 13 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/materialize/LatticeSuggester.java 
b/core/src/main/java/org/apache/calcite/materialize/LatticeSuggester.java
index 30f337e..d752196 100644
--- a/core/src/main/java/org/apache/calcite/materialize/LatticeSuggester.java
+++ b/core/src/main/java/org/apache/calcite/materialize/LatticeSuggester.java
@@ -28,6 +28,7 @@ import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.SetOp;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.rules.FilterJoinRule;
@@ -133,10 +134,14 @@ public class LatticeSuggester {
     final RelNode r2 = planner.findBestExp();
 
     final Query q = new Query(space);
-    final Frame frame = frame(q, r2);
-    if (frame == null) {
-      return ImmutableList.of();
-    }
+    final List<Frame> frameList = new ArrayList<>();
+    frames(frameList, q, r2);
+    final List<Lattice> lattices = new ArrayList<>();
+    frameList.forEach(frame -> addFrame(q, frame, lattices));
+    return ImmutableList.copyOf(lattices);
+  }
+
+  private void addFrame(Query q, Frame frame, List<Lattice> lattices) {
     final AttributedDirectedGraph<TableRef, StepRef> g =
         AttributedDirectedGraph.create(new StepRef.Factory());
     final Multimap<Pair<TableRef, TableRef>, IntPair> map =
@@ -163,7 +168,7 @@ public class LatticeSuggester {
     // If the join graph is cyclic, we can't use it.
     final Set<TableRef> cycles = new CycleDetector<>(g).findCycles();
     if (!cycles.isEmpty()) {
-      return ImmutableList.of();
+      return;
     }
 
     // Translate the query graph to mutable nodes
@@ -205,7 +210,6 @@ public class LatticeSuggester {
     }
 
     // Transcribe the hierarchy of mutable nodes to immutable nodes
-    final List<Lattice> lattices = new ArrayList<>();
     for (MutableNode rootNode : rootNodes) {
       if (rootNode.isCyclic()) {
         continue;
@@ -221,7 +225,7 @@ public class LatticeSuggester {
         for (ColRef arg : measure.arguments) {
           if (arg == null) {
             // Cannot handle expressions, e.g. "sum(x + 1)" yet
-            return ImmutableList.of();
+            return;
           }
         }
         latticeBuilder.addMeasure(
@@ -263,7 +267,6 @@ public class LatticeSuggester {
       final Lattice lattice1 = findMatch(lattice0, rootNode);
       lattices.add(lattice1);
     }
-    return ImmutableList.copyOf(lattices);
   }
 
   /** Derives the alias of an expression that is the argument to a measure.
@@ -399,6 +402,17 @@ public class LatticeSuggester {
     return c3;
   }
 
+  private void frames(List<Frame> frames, final Query q, RelNode r) {
+    if (r instanceof SetOp) {
+      r.getInputs().forEach(input -> frames(frames, q, input));
+    } else {
+      final Frame frame = frame(q, r);
+      if (frame != null) {
+        frames.add(frame);
+      }
+    }
+  }
+
   private Frame frame(final Query q, RelNode r) {
     if (r instanceof Sort) {
       final Sort sort = (Sort) r;
diff --git 
a/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java 
b/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
index c13898b..a7163ce 100644
--- 
a/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/materialize/LatticeSuggesterTest.java
@@ -49,6 +49,7 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.List;
@@ -707,16 +708,46 @@ public class LatticeSuggesterTest {
     assertThat(t.addQuery(q), isGraphs(g, "[]"));
   }
 
+  @Test public void testUnion() throws Exception {
+    checkUnion("union");
+    checkUnion("union all");
+    checkUnion("intersect");
+    checkUnion("except");
+  }
+
+  private void checkUnion(String setOp) throws Exception {
+    final Tester t = new Tester().foodmart().withEvolve(true);
+    final String q = "select \"t\".\"time_id\"\n"
+        + "from \"time_by_day\" as \"t\",\n"
+        + " \"sales_fact_1997\" as \"s\"\n"
+        + "where \"s\".\"time_id\" = \"t\".\"time_id\"\n"
+        + setOp + "\n"
+        + "select min(\"unit_sales\")\n"
+        + "from \"sales_fact_1997\" as \"s\" join \"product\" as \"p\"\n"
+        + " using (\"product_id\")\n"
+        + "group by \"s\".\"customer_id\"";
+
+    // Adding a query generates two lattices
+    final List<Lattice> latticeList = t.addQuery(q);
+    assertThat(latticeList.size(), is(2));
+
+    // But because of 'evolve' flag, the lattices are merged into a single
+    // lattice
+    final String g = "sales_fact_1997 (product:product_id 
time_by_day:time_id)";
+    final String measures = "[MIN(sales_fact_1997.unit_sales)]";
+    assertThat(t.s.getLatticeSet(), isGraphs(g, measures));
+  }
+
   /** Creates a matcher that matches query graphs to strings. */
-  private BaseMatcher<List<Lattice>> isGraphs(
+  private BaseMatcher<Collection<Lattice>> isGraphs(
       String... strings) {
     final List<String> expectedList = Arrays.asList(strings);
-    return new BaseMatcher<List<Lattice>>() {
+    return new BaseMatcher<Collection<Lattice>>() {
       public boolean matches(Object item) {
         //noinspection unchecked
-        return item instanceof List
-            && ((List) item).size() * 2 == expectedList.size()
-            && allEqual((List) item, expectedList);
+        return item instanceof Collection
+            && ((Collection<Object>) item).size() * 2 == expectedList.size()
+            && allEqual(ImmutableList.copyOf((Collection) item), expectedList);
       }
 
       private boolean allEqual(List<Lattice> items,

Reply via email to