From 720d5c63e838da99393a1e0d1f1c2787d864d5e9 Mon Sep 17 00:00:00 2001 From: sunyerui Date: Thu, 28 Jul 2016 19:05:14 +0800 Subject: [PATCH] KYLIN-1732 Support Window Function --- .../adapter/enumerable/EnumerableWindowBridge.java | 39 ++++++ .../org/apache/kylin/query/ITKylinQueryTest.java | 5 + .../test/resources/query/sql_window/query00.sql | 20 +++ .../test/resources/query/sql_window/query01.sql | 20 +++ .../test/resources/query/sql_window/query02.sql | 20 +++ .../test/resources/query/sql_window/query03.sql | 23 ++++ .../test/resources/query/sql_window/query04.sql | 22 ++++ .../test/resources/query/sql_window/query05.sql | 26 ++++ .../test/resources/query/sql_window/query06.sql | 23 ++++ .../test/resources/query/sql_window/query07.sql | 23 ++++ .../test/resources/query/sql_window/query08.sql | 23 ++++ .../test/resources/query/sql_window/query09.sql | 26 ++++ .../apache/kylin/query/optrule/OLAPWindowRule.java | 46 +++++++ .../apache/kylin/query/relnode/OLAPProjectRel.java | 7 +- .../apache/kylin/query/relnode/OLAPTableScan.java | 2 + .../apache/kylin/query/relnode/OLAPWindowRel.java | 146 +++++++++++++++++++++ 16 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java create mode 100644 kylin-it/src/test/resources/query/sql_window/query00.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query01.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query02.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query03.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query04.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query05.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query06.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query07.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query08.sql create mode 100644 kylin-it/src/test/resources/query/sql_window/query09.sql create mode 100644 query/src/main/java/org/apache/kylin/query/optrule/OLAPWindowRule.java create mode 100644 query/src/main/java/org/apache/kylin/query/relnode/OLAPWindowRel.java diff --git a/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java b/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java new file mode 100644 index 0000000..13a33e3 --- /dev/null +++ b/atopcalcite/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindowBridge.java @@ -0,0 +1,39 @@ +/* + * 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.enumerable; + +import org.apache.calcite.plan.RelOptCluster; +import org.apache.calcite.plan.RelTraitSet; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Window; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.rex.RexLiteral; + +import java.util.List; + +/** + * EnumerableWindow cant'be created out of package, here's hack of workaround + */ +public class EnumerableWindowBridge { + + public static EnumerableWindow createEnumerableWindow(RelOptCluster cluster, RelTraitSet traits, RelNode child, + List constants, RelDataType rowType, List groups) { + return new EnumerableWindow(cluster, traits, child, constants, rowType, groups); + } +} diff --git a/kylin-it/src/test/java/org/apache/kylin/query/ITKylinQueryTest.java b/kylin-it/src/test/java/org/apache/kylin/query/ITKylinQueryTest.java index 7541d00..0c29491 100644 --- a/kylin-it/src/test/java/org/apache/kylin/query/ITKylinQueryTest.java +++ b/kylin-it/src/test/java/org/apache/kylin/query/ITKylinQueryTest.java @@ -273,6 +273,11 @@ public class ITKylinQueryTest extends KylinTestBase { this.batchExecuteQuery(getQueryFolderPrefix() + "src/test/resources/query/sql_grouping"); } + @Test + public void testWindowQuery() throws Exception { + this.batchExecuteQuery(getQueryFolderPrefix() + "src/test/resources/query/sql_window"); + } + private void assertLimitWasEnabled() { OLAPContext context = getFirstOLAPContext(); assertTrue(context.storageContext.isLimitEnabled()); diff --git a/kylin-it/src/test/resources/query/sql_window/query00.sql b/kylin-it/src/test/resources/query/sql_window/query00.sql new file mode 100644 index 0000000..dbf3a15 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query00.sql @@ -0,0 +1,20 @@ +-- +-- 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. +-- +select lstg_format_name, sum(price) as GMV, row_number() over() +from test_kylin_fact +group by lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query01.sql b/kylin-it/src/test/resources/query/sql_window/query01.sql new file mode 100644 index 0000000..9bc8b23 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query01.sql @@ -0,0 +1,20 @@ +-- +-- 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. +-- +select lstg_format_name, sum(price) as GMV, count(lstg_format_name) over(partition by lstg_format_name) +from test_kylin_fact +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query02.sql b/kylin-it/src/test/resources/query/sql_window/query02.sql new file mode 100644 index 0000000..0c1b953 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query02.sql @@ -0,0 +1,20 @@ +-- +-- 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. +-- +select lstg_format_name, avg(sum(price)) over(partition by lstg_format_name) +from test_kylin_fact +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query03.sql b/kylin-it/src/test/resources/query/sql_window/query03.sql new file mode 100644 index 0000000..da02cc0 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query03.sql @@ -0,0 +1,23 @@ +-- +-- 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. +-- +select lstg_format_name, +sum(sum(price)) over(partition by lstg_format_name), +max(sum(price)) over(partition by lstg_format_name), +min(sum(price)) over(partition by lstg_format_name) +from test_kylin_fact +group by cal_dt, lstg_format_name \ No newline at end of file diff --git a/kylin-it/src/test/resources/query/sql_window/query04.sql b/kylin-it/src/test/resources/query/sql_window/query04.sql new file mode 100644 index 0000000..f5ed7b5 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query04.sql @@ -0,0 +1,22 @@ +-- +-- 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. +-- +select cal_dt, lstg_format_name, sum(price), +rank() over(partition by lstg_format_name order by cal_dt) as "RANK", +dense_rank() over(partition by lstg_format_name order by cal_dt) as "DENSE_RANK" +from test_kylin_fact +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query05.sql b/kylin-it/src/test/resources/query/sql_window/query05.sql new file mode 100644 index 0000000..c1555fd --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query05.sql @@ -0,0 +1,26 @@ +-- +-- 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. +-- +select cal_dt, lstg_format_name, sum(price) as GMV, +first_value(sum(price)) over(partition by lstg_format_name order by cal_dt) as "first", +last_value(sum(price)) over(partition by lstg_format_name order by cal_dt) as "current", +lag(sum(price), 1, 0.0) over(partition by lstg_format_name order by cal_dt) as "prev", +lead(sum(price), 1, 0.0) over(partition by lstg_format_name order by cal_dt) as "next", +ntile(4) over (partition by lstg_format_name order by cal_dt) as "quarter" +from test_kylin_fact +where cal_dt < '2012-02-01' +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query06.sql b/kylin-it/src/test/resources/query/sql_window/query06.sql new file mode 100644 index 0000000..d79243b --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query06.sql @@ -0,0 +1,23 @@ +-- +-- 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. +-- +select cal_dt, lstg_format_name, sum(price) as GMV, +(case lag(sum(price), 1, 0.0) over(partition by lstg_format_name order by cal_dt) +when 0.0 then 0 else sum(price)/lag(sum(price), 1, 0.0) over(partition by lstg_format_name order by cal_dt) end) as "prev" +from test_kylin_fact +where cal_dt < '2012-02-01' +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query07.sql b/kylin-it/src/test/resources/query/sql_window/query07.sql new file mode 100644 index 0000000..8eb0d77 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query07.sql @@ -0,0 +1,23 @@ +-- +-- 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. +-- +select cal_dt, lstg_format_name, sum(price) as GMV, +first_value(sum(price)) over (partition by lstg_format_name order by cal_dt rows 2 preceding) as "prev 2 rows", +last_value(sum(price)) over (partition by lstg_format_name order by cal_dt rows 2 following) as "next 2 rows" +from test_kylin_fact +where cal_dt < '2012-02-01' +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query08.sql b/kylin-it/src/test/resources/query/sql_window/query08.sql new file mode 100644 index 0000000..828932f --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query08.sql @@ -0,0 +1,23 @@ +-- +-- 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. +-- +select cal_dt, lstg_format_name, sum(price) as GMV, +first_value(sum(price)) over (partition by lstg_format_name order by cast(cal_dt as timestamp) range interval '3' day preceding) as "prev 3 days", +last_value(sum(price)) over (partition by lstg_format_name order by cast(cal_dt as timestamp) range interval '3' day following) as "next 3 days" +from test_kylin_fact +where cal_dt < '2012-02-01' +group by cal_dt, lstg_format_name diff --git a/kylin-it/src/test/resources/query/sql_window/query09.sql b/kylin-it/src/test/resources/query/sql_window/query09.sql new file mode 100644 index 0000000..37514d2 --- /dev/null +++ b/kylin-it/src/test/resources/query/sql_window/query09.sql @@ -0,0 +1,26 @@ +-- +-- 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. +-- +select * from( + select cal_dt, lstg_format_name, sum(price) as GMV, + 100*sum(price)/first_value(sum(price)) over (partition by lstg_format_name order by cast(cal_dt as timestamp) range interval '1' day PRECEDING) as "last_day", + first_value(sum(price)) over (partition by lstg_format_name order by cast(cal_dt as timestamp) range cast(366 as INTERVAL day) preceding) + from test_kylin_fact as "last_year" + where cal_dt between '2013-01-08' and '2013-01-15' or cal_dt between '2013-01-07' and '2013-01-15' or cal_dt between '2012-01-01' and '2012-01-15' + group by cal_dt, lstg_format_name +)t +where cal_dt between '2013-01-06' and '2013-01-15' diff --git a/query/src/main/java/org/apache/kylin/query/optrule/OLAPWindowRule.java b/query/src/main/java/org/apache/kylin/query/optrule/OLAPWindowRule.java new file mode 100644 index 0000000..74d1b10 --- /dev/null +++ b/query/src/main/java/org/apache/kylin/query/optrule/OLAPWindowRule.java @@ -0,0 +1,46 @@ +/* + * 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.query.optrule; + +import org.apache.calcite.plan.Convention; +import org.apache.calcite.plan.RelTraitSet; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.convert.ConverterRule; +import org.apache.calcite.rel.core.Window; +import org.apache.kylin.query.relnode.OLAPRel; +import org.apache.kylin.query.relnode.OLAPWindowRel; + +/** + */ +public class OLAPWindowRule extends ConverterRule { + + public static final OLAPWindowRule INSTANCE = new OLAPWindowRule(); + + public OLAPWindowRule() { + super(Window.class, Convention.NONE, OLAPRel.CONVENTION, "OLAPWindowRule"); + } + + @Override + public RelNode convert(RelNode rel) { + final Window window = (Window) rel; + final RelTraitSet traitSet = window.getTraitSet().replace(OLAPRel.CONVENTION); + final RelNode input = window.getInput(); + return new OLAPWindowRel(rel.getCluster(), traitSet, convert(input, OLAPRel.CONVENTION), window.constants, window.getRowType(), window.groups); + } +} diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java index aec4811..0a8a15f 100644 --- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java +++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPProjectRel.java @@ -44,6 +44,7 @@ import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexOver; import org.apache.calcite.rex.RexProgram; import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.fun.SqlCaseOperator; @@ -89,10 +90,14 @@ public class OLAPProjectRel extends Project implements OLAPRel { /** * Since the project under aggregate maybe reduce expressions by {@link org.apache.kylin.query.optrule.AggregateProjectReduceRule}, * consider the count of expressions into cost, the reduced project will be used. + * + * Made RexOver much more expensive so we can transform into {@link org.apache.kylin.query.relnode.OLAPWindowRel} + * by rules in {@link org.apache.calcite.rel.rules.ProjectToWindowRule} */ @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { - return super.computeSelfCost(planner, mq).multiplyBy(.05).multiplyBy(getProjects().size()); + boolean hasRexOver = RexOver.containsOver(getProjects(), null); + return super.computeSelfCost(planner, mq).multiplyBy(.05).multiplyBy(getProjects().size() * (hasRexOver ? 50 : 1)); } @Override diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java index bd5b154..381ced4 100644 --- a/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java +++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPTableScan.java @@ -69,6 +69,7 @@ import org.apache.kylin.query.optrule.OLAPProjectRule; import org.apache.kylin.query.optrule.OLAPSortRule; import org.apache.kylin.query.optrule.OLAPToEnumerableConverterRule; import org.apache.kylin.query.optrule.OLAPUnionRule; +import org.apache.kylin.query.optrule.OLAPWindowRule; import org.apache.kylin.query.schema.OLAPSchema; import org.apache.kylin.query.schema.OLAPTable; @@ -133,6 +134,7 @@ public class OLAPTableScan extends TableScan implements OLAPRel, EnumerableRel { planner.addRule(OLAPLimitRule.INSTANCE); planner.addRule(OLAPSortRule.INSTANCE); planner.addRule(OLAPUnionRule.INSTANCE); + planner.addRule(OLAPWindowRule.INSTANCE); // Support translate the grouping aggregate into union of simple aggregates planner.addRule(AggregateMultipleExpandRule.INSTANCE); diff --git a/query/src/main/java/org/apache/kylin/query/relnode/OLAPWindowRel.java b/query/src/main/java/org/apache/kylin/query/relnode/OLAPWindowRel.java new file mode 100644 index 0000000..8688944 --- /dev/null +++ b/query/src/main/java/org/apache/kylin/query/relnode/OLAPWindowRel.java @@ -0,0 +1,146 @@ +/* + * 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.query.relnode; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.calcite.adapter.enumerable.EnumerableWindowBridge; +import org.apache.calcite.adapter.enumerable.EnumerableConvention; +import org.apache.calcite.adapter.enumerable.EnumerableRel; +import org.apache.calcite.plan.RelOptCluster; +import org.apache.calcite.plan.RelOptCost; +import org.apache.calcite.plan.RelOptPlanner; +import org.apache.calcite.plan.RelTrait; +import org.apache.calcite.plan.RelTraitSet; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.RelWriter; +import org.apache.calcite.rel.core.AggregateCall; +import org.apache.calcite.rel.core.Window; +import org.apache.calcite.rel.metadata.RelMetadataQuery; + +import com.google.common.base.Preconditions; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.rex.RexLiteral; +import org.apache.kylin.metadata.model.TblColRef; + +/** + */ +public class OLAPWindowRel extends Window implements OLAPRel { + private ColumnRowType columnRowType; + private OLAPContext context; + + public OLAPWindowRel(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, List constants, RelDataType rowType, List groups) { + super(cluster, traitSet, input, constants, rowType, groups); + Preconditions.checkArgument(getConvention() == CONVENTION); + Preconditions.checkArgument(getConvention() == input.getConvention()); + } + + @Override + public Window copy(RelTraitSet traitSet, List inputs) { + assert inputs.size() == 1; + return new OLAPWindowRel(getCluster(), traitSet, inputs.get(0), constants, rowType, groups); + } + + @Override + public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq).multiplyBy(.05); + } + + @Override + public RelWriter explainTerms(RelWriter pw) { + return super.explainTerms(pw) + .itemIf("constants", constants, !constants.isEmpty()) + .itemIf("groups", groups, !groups.isEmpty()); + } + + @Override + public void implementOLAP(OLAPImplementor implementor) { + for (RelNode child : getInputs()) { + implementor.visitChild(child, this); + } + + this.columnRowType = buildColumnRowType(); + this.context = implementor.getContext(); + } + + private ColumnRowType buildColumnRowType() { + OLAPRel olapChild = (OLAPRel) getInput(0); + ColumnRowType inputColumnRowType = olapChild.getColumnRowType(); + + List columns = new ArrayList<>(); + // the input col always be collected by left + columns.addAll(inputColumnRowType.getAllColumns()); + + // add window aggregate calls column + for (Group group : groups) { + for (AggregateCall aggrCall : group.getAggregateCalls(this)) { + TblColRef aggrCallCol = TblColRef.newInnerColumn(aggrCall.getName(), TblColRef.InnerDataTypeEnum.LITERAL); + columns.add(aggrCallCol); + } + } + return new ColumnRowType(columns); + } + + @Override + public void implementRewrite(RewriteImplementor implementor) { + for (RelNode child : getInputs()) { + implementor.visitChild(this, child); + } + } + + @Override + public EnumerableRel implementEnumerable(List inputs) { + ArrayList relInputs = new ArrayList<>(inputs.size()); + for (EnumerableRel input : inputs) { + if (input instanceof OLAPRel) { + ((OLAPRel) input).replaceTraitSet(EnumerableConvention.INSTANCE); + } + relInputs.add(input); + } + return EnumerableWindowBridge.createEnumerableWindow(getCluster(), traitSet, inputs.get(0), constants, rowType, groups); + } + + @Override + public OLAPContext getContext() { + return context; + } + + @Override + public ColumnRowType getColumnRowType() { + return columnRowType; + } + + @Override + public boolean hasSubQuery() { + for (RelNode child : getInputs()) { + if (((OLAPRel)child).hasSubQuery()) { + return true; + } + } + return false; + } + + @Override + public RelTraitSet replaceTraitSet(RelTrait trait) { + RelTraitSet oldTraitSet = this.traitSet; + this.traitSet = this.traitSet.replace(trait); + return oldTraitSet; + } +} -- 2.3.2 (Apple Git-55)