calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [1/4] calcite git commit: Druid adapter: Add enum Granularity
Date Thu, 19 Jan 2017 23:47:33 GMT
Repository: calcite
Updated Branches:
  refs/heads/master aadc62d4c -> e5c9f2ed3


Druid adapter: Add enum Granularity


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

Branch: refs/heads/master
Commit: a621902869d0e95b8b46c58e33e870ef1a76c17e
Parents: aadc62d
Author: Julian Hyde <jhyde@apache.org>
Authored: Tue Jan 17 16:13:11 2017 -0800
Committer: Julian Hyde <jhyde@apache.org>
Committed: Thu Jan 19 10:43:45 2017 -0800

----------------------------------------------------------------------
 .../adapter/druid/DruidDateTimeUtils.java       | 11 +++-
 .../calcite/adapter/druid/DruidQuery.java       | 16 ++---
 .../calcite/adapter/druid/Granularity.java      | 36 ++++++++++
 .../org/apache/calcite/test/DruidAdapterIT.java | 69 +++++++++++++++++---
 4 files changed, 112 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/a6219028/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
----------------------------------------------------------------------
diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
index 4c81b60..84ae181 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
@@ -259,7 +259,7 @@ public class DruidDateTimeUtils {
    * @param call the function call
    * @return the granularity, or null if it cannot be inferred
    */
-  public static String extractGranularity(RexCall call) {
+  public static Granularity extractGranularity(RexCall call) {
     if (call.getKind() != SqlKind.FLOOR
         || call.getOperands().size() != 2) {
       return null;
@@ -271,14 +271,21 @@ public class DruidDateTimeUtils {
     }
     switch (timeUnit) {
     case YEAR:
+      return Granularity.YEAR;
     case QUARTER:
+      return Granularity.QUARTER;
     case MONTH:
+      return Granularity.MONTH;
     case WEEK:
+      return Granularity.WEEK;
     case DAY:
+      return Granularity.DAY;
     case HOUR:
+      return Granularity.HOUR;
     case MINUTE:
+      return Granularity.MINUTE;
     case SECOND:
-      return timeUnit.name();
+      return Granularity.SECOND;
     default:
       return null;
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6219028/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
----------------------------------------------------------------------
diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
index 46832fa..97d4484 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java
@@ -441,7 +441,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
     // executed as a Timeseries, TopN, or GroupBy in Druid
     final List<String> dimensions = new ArrayList<>();
     final List<JsonAggregation> aggregations = new ArrayList<>();
-    String granularity = "all";
+    Granularity granularity = Granularity.ALL;
     Direction timeSeriesDirection = null;
     JsonLimit limit = null;
     if (groupSet != null) {
@@ -461,7 +461,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
             final String origin = druidTable.getRowType(getCluster().getTypeFactory())
                 .getFieldList().get(ref.getIndex()).getName();
             if (origin.equals(druidTable.timestampFieldName)) {
-              granularity = "none";
+              granularity = Granularity.NONE;
               builder.add(s);
               assert timePositionIdx == -1;
               timePositionIdx = groupKey;
@@ -472,7 +472,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
           } else if (project instanceof RexCall) {
             // Call, check if we should infer granularity
             final RexCall call = (RexCall) project;
-            final String funcGranularity =
+            final Granularity funcGranularity =
                 DruidDateTimeUtils.extractGranularity(call);
             if (funcGranularity != null) {
               granularity = funcGranularity;
@@ -491,7 +491,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
         for (int groupKey : groupSet) {
           final String s = fieldNames.get(groupKey);
           if (s.equals(druidTable.timestampFieldName)) {
-            granularity = "NONE";
+            granularity = Granularity.NONE;
             builder.add(s);
             assert timePositionIdx == -1;
             timePositionIdx = groupKey;
@@ -562,7 +562,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
         generator.writeStringField("dataSource", druidTable.dataSource);
         generator.writeBooleanField("descending", timeSeriesDirection != null
             && timeSeriesDirection == Direction.DESCENDING);
-        generator.writeStringField("granularity", granularity);
+        generator.writeStringField("granularity", granularity.value);
         writeFieldIf(generator, "filter", jsonFilter);
         writeField(generator, "aggregations", aggregations);
         writeFieldIf(generator, "postAggregations", null);
@@ -576,7 +576,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
 
         generator.writeStringField("queryType", "topN");
         generator.writeStringField("dataSource", druidTable.dataSource);
-        generator.writeStringField("granularity", granularity);
+        generator.writeStringField("granularity", granularity.value);
         generator.writeStringField("dimension", dimensions.get(0));
         generator.writeStringField("metric", fieldNames.get(collationIndexes.get(0)));
         writeFieldIf(generator, "filter", jsonFilter);
@@ -600,7 +600,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
 
         generator.writeStringField("queryType", "groupBy");
         generator.writeStringField("dataSource", druidTable.dataSource);
-        generator.writeStringField("granularity", granularity);
+        generator.writeStringField("granularity", granularity.value);
         writeField(generator, "dimensions", dimensions);
         writeFieldIf(generator, "limitSpec", limit);
         writeFieldIf(generator, "filter", jsonFilter);
@@ -622,7 +622,7 @@ public class DruidQuery extends AbstractRelNode implements BindableRel
{
         writeFieldIf(generator, "filter", jsonFilter);
         writeField(generator, "dimensions", translator.dimensions);
         writeField(generator, "metrics", translator.metrics);
-        generator.writeStringField("granularity", granularity);
+        generator.writeStringField("granularity", granularity.value);
 
         generator.writeFieldName("pagingSpec");
         generator.writeStartObject();

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6219028/druid/src/main/java/org/apache/calcite/adapter/druid/Granularity.java
----------------------------------------------------------------------
diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/Granularity.java b/druid/src/main/java/org/apache/calcite/adapter/druid/Granularity.java
new file mode 100644
index 0000000..b3f1e85
--- /dev/null
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/Granularity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.calcite.adapter.druid;
+
+/** Granularity of a Druid query. */
+public enum Granularity {
+  ALL,
+  YEAR,
+  QUARTER,
+  MONTH,
+  WEEK,
+  DAY,
+  HOUR,
+  MINUTE,
+  SECOND,
+  NONE;
+
+  /** JSON attribute value in a Druid query. */
+  public final String value = name().toLowerCase();
+}
+
+// End Granularity.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/a6219028/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
----------------------------------------------------------------------
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
index 3a52814..75331b7 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
@@ -182,7 +182,7 @@ public class DruidAdapterIT {
         + "  BindableProject(EXPR$0=[$1])\n"
         + "    DruidQuery(table=[[wiki, wikiticker]], intervals=[[1900-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z]],
projects=[[FLOOR($0, FLAG(DAY)), $1]], groups=[{0}], aggs=[[SUM($1)]])\n";
     final String druidQuery = "{'queryType':'timeseries',"
-        + "'dataSource':'wikiticker','descending':false,'granularity':'DAY',"
+        + "'dataSource':'wikiticker','descending':false,'granularity':'day',"
         + "'aggregations':[{'type':'longSum','name':'EXPR$0','fieldName':'added'}],"
         + "'intervals':['1900-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z']}";
     sql(sql, WIKI_AUTO2)
@@ -220,7 +220,7 @@ public class DruidAdapterIT {
         + "EnumerableInterpreter\n"
         + "  DruidQuery(table=[[wiki, wikiticker]], intervals=[[1900-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z]],
projects=[[FLOOR($0, FLAG(DAY)), $1]], groups=[{0}], aggs=[[SUM($1)]])\n";
     final String druidQuery = "{'queryType':'timeseries',"
-        + "'dataSource':'wikiticker','descending':false,'granularity':'DAY',"
+        + "'dataSource':'wikiticker','descending':false,'granularity':'day',"
         + "'aggregations':[{'type':'longSum','name':'EXPR$1','fieldName':'added'}],"
         + "'intervals':['1900-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z']}";
     sql(sql, WIKI_AUTO2)
@@ -239,11 +239,11 @@ public class DruidAdapterIT {
         + "order by \"s\" desc";
     final String explain = "PLAN="
         + "EnumerableInterpreter\n"
-        + "  BindableSort(sort0=[$0], dir0=[DESC])\n"
-        + "    BindableProject(s=[$2], page=[$0], day=[$1])\n"
+        + "  BindableProject(s=[$2], page=[$0], day=[$1])\n"
+        + "    BindableSort(sort0=[$2], dir0=[DESC])\n"
         + "      DruidQuery(table=[[wiki, wikiticker]], intervals=[[1900-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z]],
projects=[[$17, FLOOR($0, FLAG(DAY)), $1]], groups=[{0, 1}], aggs=[[SUM($2)]])\n";
     final String druidQuery = "{'queryType':'groupBy',"
-        + "'dataSource':'wikiticker','granularity':'DAY','dimensions':['page'],"
+        + "'dataSource':'wikiticker','granularity':'day','dimensions':['page'],"
         + "'limitSpec':{'type':'default'},"
         + "'aggregations':[{'type':'longSum','name':'s','fieldName':'added'}],"
         + "'intervals':['1900-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z']}";
@@ -433,6 +433,55 @@ public class DruidAdapterIT {
         .queryContains(druidChecker(druidQuery));
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-1578">[CALCITE-1578]
+   * Druid adapter: wrong semantics of topN query limit with granularity</a>. */
+  @Test public void testGroupBySortLimit() {
+    final String sql = "select \"brand_name\", \"gender\", sum(\"unit_sales\") as s\n"
+        + "from \"foodmart\"\n"
+        + "group by \"brand_name\", \"gender\"\n"
+        + "order by s desc limit 3";
+    final String druidQuery = "{'queryType':'groupBy','dataSource':'foodmart',"
+        + "'granularity':'all','dimensions':['brand_name','gender'],"
+        + "'limitSpec':{'type':'default','limit':3,'columns':[{'dimension':'S','direction':'descending'}]},"
+        + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'}],"
+        + "'intervals':['1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z']}";
+    final String explain = "PLAN=EnumerableInterpreter\n"
+        + "  DruidQuery(table=[[foodmart, foodmart]], "
+        + "intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], "
+        + "groups=[{2, 39}], aggs=[[SUM($89)]], sort0=[2], dir0=[DESC], fetch=[3])\n";
+    sql(sql)
+        .runs()
+        .returnsOrdered("brand_name=Hermanos; gender=M; S=4286",
+            "brand_name=Hermanos; gender=F; S=4183",
+            "brand_name=Tell Tale; gender=F; S=4033")
+        .explainContains(explain)
+        .queryContains(druidChecker(druidQuery));
+  }
+
+  @Test public void testGroupBySingleSortLimit() {
+    final String sql = "select \"brand_name\", sum(\"unit_sales\") as s\n"
+        + "from \"foodmart\"\n"
+        + "group by \"brand_name\"\n"
+        + "order by s desc limit 3";
+    final String druidQuery = "{'queryType':'topN','dataSource':'foodmart',"
+        + "'granularity':'all','dimension':'brand_name','metric':'S',"
+        + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'}],"
+        + "'intervals':['1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z'],"
+        + "'threshold':3}";
+    final String explain = "PLAN=EnumerableInterpreter\n"
+        + "  DruidQuery(table=[[foodmart, foodmart]], "
+        + "intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]], "
+        + "groups=[{2}], aggs=[[SUM($89)]], sort0=[1], dir0=[DESC], fetch=[3])\n";
+    sql(sql)
+        .runs()
+        .returnsOrdered("brand_name=Hermanos; S=8469",
+            "brand_name=Tell Tale; S=7877",
+            "brand_name=Ebony; S=7438")
+        .explainContains(explain)
+        .queryContains(druidChecker(druidQuery));
+  }
+
   /** Tests a query that contains no GROUP BY and is therefore executed as a
    * Druid "select" query. */
   @Test public void testFilterSortDesc() {
@@ -693,7 +742,7 @@ public class DruidAdapterIT {
         + "from \"foodmart\"\n"
         + "group by floor(\"timestamp\" to MONTH)";
     String druidQuery = "{'queryType':'timeseries','dataSource':'foodmart',"
-        + "'descending':false,'granularity':'MONTH',"
+        + "'descending':false,'granularity':'month',"
         + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'},"
         + "{'type':'count','name':'C','fieldName':'store_sqft'}],"
         + "'intervals':['1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z']}";
@@ -709,7 +758,7 @@ public class DruidAdapterIT {
         + "from \"foodmart\"\n"
         + "group by floor(\"timestamp\" to DAY)";
     String druidQuery = "{'queryType':'timeseries','dataSource':'foodmart',"
-        + "'descending':false,'granularity':'DAY',"
+        + "'descending':false,'granularity':'day',"
         + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'},"
         + "{'type':'count','name':'C','fieldName':'store_sqft'}],"
         + "'intervals':['1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z']}";
@@ -727,7 +776,7 @@ public class DruidAdapterIT {
         + " \"timestamp\" < '1998-01-01 00:00:00'\n"
         + "group by floor(\"timestamp\" to MONTH)";
     String druidQuery = "{'queryType':'timeseries','dataSource':'foodmart',"
-        + "'descending':false,'granularity':'MONTH',"
+        + "'descending':false,'granularity':'month',"
         + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'},"
         + "{'type':'count','name':'C','fieldName':'store_sqft'}],"
         + "'intervals':['1996-01-01T00:00:00.000Z/1998-01-01T00:00:00.000Z']}";
@@ -749,7 +798,7 @@ public class DruidAdapterIT {
         + "  BindableProject(S=[$2], M=[$3], P=[$0])\n"
         + "    DruidQuery(table=[[foodmart, foodmart]], intervals=[[1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z]],
projects=[[$30, FLOOR($0, FLAG(MONTH)), $89]], groups=[{0, 1}], aggs=[[SUM($2), MAX($2)]],
sort0=[2], dir0=[DESC], fetch=[3])";
     final String druidQuery = "{'queryType':'topN','dataSource':'foodmart',"
-        + "'granularity':'MONTH','dimension':'state_province','metric':'S',"
+        + "'granularity':'month','dimension':'state_province','metric':'S',"
         + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'},"
         + "{'type':'longMax','name':'M','fieldName':'unit_sales'}],"
         + "'intervals':['1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z'],'threshold':3}";
@@ -773,7 +822,7 @@ public class DruidAdapterIT {
         + "  BindableProject(S=[$2], M=[$3], P=[$0])\n"
         + "    DruidQuery(table=[[foodmart, foodmart]], intervals=[[1997-01-01T00:00:00.000Z/1997-09-01T00:00:00.000Z]],
projects=[[$30, FLOOR($0, FLAG(DAY)), $89]], groups=[{0, 1}], aggs=[[SUM($2), MAX($2)]], sort0=[2],
dir0=[DESC], fetch=[3])";
     final String druidQuery = "{'queryType':'topN','dataSource':'foodmart',"
-        + "'granularity':'DAY','dimension':'state_province','metric':'S',"
+        + "'granularity':'day','dimension':'state_province','metric':'S',"
         + "'aggregations':[{'type':'longSum','name':'S','fieldName':'unit_sales'},"
         + "{'type':'longMax','name':'M','fieldName':'unit_sales'}],"
         + "'intervals':['1997-01-01T00:00:00.000Z/1997-09-01T00:00:00.000Z'],'threshold':3}";


Mime
View raw message