You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by jc...@apache.org on 2016/12/16 13:58:30 UTC
[4/6] hive git commit: HIVE-14496: Enable Calcite rewriting with
materialized views (Jesus Camacho Rodriguez, reviewed by Ashutosh Chauhan)
http://git-wip-us.apache.org/repos/asf/hive/blob/3da29fe7/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/HiveMaterializedViewFilterScanRule.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/HiveMaterializedViewFilterScanRule.java b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/HiveMaterializedViewFilterScanRule.java
new file mode 100644
index 0000000..38d7906
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/HiveMaterializedViewFilterScanRule.java
@@ -0,0 +1,91 @@
+/**
+ * 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.hadoop.hive.ql.optimizer.calcite.rules.views;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.calcite.plan.RelOptMaterialization;
+import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.volcano.VolcanoPlanner;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Filter;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.hadoop.hive.ql.optimizer.calcite.HiveRelFactories;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Planner rule that replaces (if possible)
+ * a {@link org.apache.calcite.rel.core.Project}
+ * on a {@link org.apache.calcite.rel.core.Filter}
+ * on a {@link org.apache.calcite.rel.core.TableScan}
+ * to use a Materialized View.
+ */
+public class HiveMaterializedViewFilterScanRule extends RelOptRule {
+
+ public static final HiveMaterializedViewFilterScanRule INSTANCE =
+ new HiveMaterializedViewFilterScanRule(HiveRelFactories.HIVE_BUILDER);
+
+
+ //~ Constructors -----------------------------------------------------------
+
+ /** Creates a HiveMaterializedViewFilterScanRule. */
+ protected HiveMaterializedViewFilterScanRule(RelBuilderFactory relBuilderFactory) {
+ super(operand(Project.class, operand(Filter.class, operand(TableScan.class, null, none()))),
+ relBuilderFactory, "MaterializedViewFilterScanRule");
+ }
+
+ //~ Methods ----------------------------------------------------------------
+
+ public void onMatch(RelOptRuleCall call) {
+ final Project project = call.rel(0);
+ final Filter filter = call.rel(1);
+ final TableScan scan = call.rel(2);
+ apply(call, project, filter, scan);
+ }
+
+ protected void apply(RelOptRuleCall call, Project project, Filter filter, TableScan scan) {
+ RelOptPlanner planner = call.getPlanner();
+ List<RelOptMaterialization> materializations =
+ (planner instanceof VolcanoPlanner)
+ ? ((VolcanoPlanner) planner).getMaterializations()
+ : ImmutableList.<RelOptMaterialization>of();
+ if (!materializations.isEmpty()) {
+ RelNode root = project.copy(project.getTraitSet(), Collections.singletonList(
+ filter.copy(filter.getTraitSet(), Collections.singletonList(
+ (RelNode) scan))));
+ // Costing is done in transformTo(), so we call it repeatedly with all applicable
+ // materialized views and cheapest one will be picked
+ List<RelOptMaterialization> applicableMaterializations =
+ VolcanoPlanner.getApplicableMaterializations(root, materializations);
+ for (RelOptMaterialization materialization : applicableMaterializations) {
+ List<RelNode> subs = new MaterializedViewSubstitutionVisitor(
+ materialization.queryRel, root, relBuilderFactory).go(materialization.tableRel);
+ for (RelNode s : subs) {
+ call.transformTo(s);
+ }
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hive/blob/3da29fe7/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/MaterializedViewSubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/MaterializedViewSubstitutionVisitor.java b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/MaterializedViewSubstitutionVisitor.java
new file mode 100644
index 0000000..e32f1a6
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/views/MaterializedViewSubstitutionVisitor.java
@@ -0,0 +1,292 @@
+/**
+ * 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.hadoop.hive.ql.optimizer.calcite.rules.views;
+
+import java.util.List;
+
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.tools.RelBuilderFactory;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Extension to {@link SubstitutionVisitor}.
+ *
+ * TODO: Remove when we upgrade to Calcite version using builders.
+ */
+public class MaterializedViewSubstitutionVisitor extends SubstitutionVisitor {
+ private static final ImmutableList<UnifyRule> EXTENDED_RULES =
+ ImmutableList.<UnifyRule>builder()
+ .addAll(DEFAULT_RULES)
+ .add(ProjectToProjectUnifyRule1.INSTANCE)
+ .add(FilterToFilterUnifyRule1.INSTANCE)
+ .add(FilterToProjectUnifyRule1.INSTANCE)
+ .build();
+
+ public MaterializedViewSubstitutionVisitor(RelNode target_, RelNode query_) {
+ super(target_, query_, EXTENDED_RULES);
+ }
+
+ public MaterializedViewSubstitutionVisitor(RelNode target_, RelNode query_,
+ RelBuilderFactory relBuilderFactory) {
+ super(target_, query_, EXTENDED_RULES, relBuilderFactory);
+ }
+
+ public List<RelNode> go(RelNode replacement_) {
+ return super.go(replacement_);
+ }
+
+ /**
+ * Implementation of {@link SubstitutionVisitor.UnifyRule} that matches a
+ * {@link SubstitutionVisitor.MutableProject} to a
+ * {@link SubstitutionVisitor.MutableProject} where the condition of the target
+ * relation is weaker.
+ *
+ * <p>Example: target has a weaker condition and contains all columns selected
+ * by query</p>
+ * <ul>
+ * <li>query: Project(projects: [$2, $0])
+ * Filter(condition: >($1, 20))
+ * Scan(table: [hr, emps])</li>
+ * <li>target: Project(projects: [$0, $1, $2])
+ * Filter(condition: >($1, 10))
+ * Scan(table: [hr, emps])</li>
+ * </ul>
+ */
+ private static class ProjectToProjectUnifyRule1 extends AbstractUnifyRule {
+ public static final ProjectToProjectUnifyRule1 INSTANCE =
+ new ProjectToProjectUnifyRule1();
+
+ private ProjectToProjectUnifyRule1() {
+ super(operand(MutableProject.class, query(0)),
+ operand(MutableProject.class, target(0)), 1);
+ }
+
+ @Override protected UnifyResult apply(UnifyRuleCall call) {
+ final MutableProject query = (MutableProject) call.query;
+
+ final List<RelDataTypeField> oldFieldList =
+ query.getInput().getRowType().getFieldList();
+ final List<RelDataTypeField> newFieldList =
+ call.target.getRowType().getFieldList();
+ List<RexNode> newProjects;
+ try {
+ newProjects = transformRex(query.getProjects(), oldFieldList, newFieldList);
+ } catch (MatchFailed e) {
+ return null;
+ }
+
+ final MutableProject newProject =
+ MutableProject.of(
+ query.getRowType(), call.target, newProjects);
+
+ final MutableRel newProject2 = MutableRels.strip(newProject);
+ return call.result(newProject2);
+ }
+
+ @Override protected UnifyRuleCall match(SubstitutionVisitor visitor,
+ MutableRel query, MutableRel target) {
+ assert query instanceof MutableProject && target instanceof MutableProject;
+
+ if (queryOperand.matches(visitor, query)) {
+ if (targetOperand.matches(visitor, target)) {
+ return null;
+ } else if (targetOperand.isWeaker(visitor, target)) {
+
+ final MutableProject queryProject = (MutableProject) query;
+ if (queryProject.getInput() instanceof MutableFilter) {
+ final MutableFilter innerFilter =
+ (MutableFilter) queryProject.getInput();
+ RexNode newCondition;
+ try {
+ newCondition = transformRex(innerFilter.getCondition(),
+ innerFilter.getInput().getRowType().getFieldList(),
+ target.getRowType().getFieldList());
+ } catch (MatchFailed e) {
+ return null;
+ }
+ final MutableFilter newFilter = MutableFilter.of(target,
+ newCondition);
+
+ return visitor.new UnifyRuleCall(this, query, newFilter,
+ copy(visitor.slots, slotCount));
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of {@link SubstitutionVisitor.UnifyRule} that matches a
+ * {@link SubstitutionVisitor.MutableFilter} to a
+ * {@link SubstitutionVisitor.MutableFilter} where the condition of the target
+ * relation is weaker.
+ *
+ * <p>Example: target has a weaker condition</p>
+ * <ul>
+ * <li>query: Filter(condition: >($1, 20))
+ * Scan(table: [hr, emps])</li>
+ * <li>target: Filter(condition: >($1, 10))
+ * Scan(table: [hr, emps])</li>
+ * </ul>
+ */
+ private static class FilterToFilterUnifyRule1 extends AbstractUnifyRule {
+ public static final FilterToFilterUnifyRule1 INSTANCE =
+ new FilterToFilterUnifyRule1();
+
+ private FilterToFilterUnifyRule1() {
+ super(operand(MutableFilter.class, query(0)),
+ operand(MutableFilter.class, target(0)), 1);
+ }
+
+ public UnifyResult apply(UnifyRuleCall call) {
+ final MutableFilter query = (MutableFilter) call.query;
+ final MutableFilter target = (MutableFilter) call.target;
+ final MutableFilter newFilter = MutableFilter.of(target, query.getCondition());
+ return call.result(newFilter);
+ }
+
+ @Override protected UnifyRuleCall match(SubstitutionVisitor visitor,
+ MutableRel query, MutableRel target) {
+ if (queryOperand.matches(visitor, query)) {
+ if (targetOperand.matches(visitor, target)) {
+ if (visitor.isWeaker(query, target)) {
+ return visitor.new UnifyRuleCall(this, query, target,
+ copy(visitor.slots, slotCount));
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of {@link SubstitutionVisitor.UnifyRule} that matches a
+ * {@link SubstitutionVisitor.MutableFilter} to a
+ * {@link SubstitutionVisitor.MutableProject} on top of a
+ * {@link SubstitutionVisitor.MutableFilter} where the condition of the target
+ * relation is weaker.
+ *
+ * <p>Example: target has a weaker condition and is a permutation projection of
+ * its child relation</p>
+ * <ul>
+ * <li>query: Filter(condition: >($1, 20))
+ * Scan(table: [hr, emps])</li>
+ * <li>target: Project(projects: [$1, $0, $2, $3, $4])
+ * Filter(condition: >($1, 10))
+ * Scan(table: [hr, emps])</li>
+ * </ul>
+ */
+ private static class FilterToProjectUnifyRule1 extends AbstractUnifyRule {
+ public static final FilterToProjectUnifyRule1 INSTANCE =
+ new FilterToProjectUnifyRule1();
+
+ private FilterToProjectUnifyRule1() {
+ super(
+ operand(MutableFilter.class, query(0)),
+ operand(MutableProject.class,
+ operand(MutableFilter.class, target(0))), 1);
+ }
+
+ public UnifyResult apply(UnifyRuleCall call) {
+ final MutableRel query = call.query;
+
+ final List<RelDataTypeField> oldFieldList =
+ query.getRowType().getFieldList();
+ final List<RelDataTypeField> newFieldList =
+ call.target.getRowType().getFieldList();
+ List<RexNode> newProjects;
+ try {
+ newProjects = transformRex(
+ (List<RexNode>) call.getCluster().getRexBuilder().identityProjects(
+ query.getRowType()),
+ oldFieldList, newFieldList);
+ } catch (MatchFailed e) {
+ return null;
+ }
+
+ final MutableProject newProject =
+ MutableProject.of(
+ query.getRowType(), call.target, newProjects);
+
+ final MutableRel newProject2 = MutableRels.strip(newProject);
+ return call.result(newProject2);
+ }
+
+ @Override protected UnifyRuleCall match(SubstitutionVisitor visitor,
+ MutableRel query, MutableRel target) {
+ assert query instanceof MutableFilter && target instanceof MutableProject;
+
+ if (queryOperand.matches(visitor, query)) {
+ if (targetOperand.matches(visitor, target)) {
+ if (visitor.isWeaker(query, ((MutableProject) target).getInput())) {
+ final MutableFilter filter = (MutableFilter) query;
+ RexNode newCondition;
+ try {
+ newCondition = transformRex(filter.getCondition(),
+ filter.getInput().getRowType().getFieldList(),
+ target.getRowType().getFieldList());
+ } catch (MatchFailed e) {
+ return null;
+ }
+ final MutableFilter newFilter = MutableFilter.of(target,
+ newCondition);
+ return visitor.new UnifyRuleCall(this, query, newFilter,
+ copy(visitor.slots, slotCount));
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ private static RexNode transformRex(RexNode node,
+ final List<RelDataTypeField> oldFields,
+ final List<RelDataTypeField> newFields) {
+ List<RexNode> nodes =
+ transformRex(ImmutableList.of(node), oldFields, newFields);
+ return nodes.get(0);
+ }
+
+ private static List<RexNode> transformRex(
+ List<RexNode> nodes,
+ final List<RelDataTypeField> oldFields,
+ final List<RelDataTypeField> newFields) {
+ RexShuttle shuttle = new RexShuttle() {
+ @Override public RexNode visitInputRef(RexInputRef ref) {
+ RelDataTypeField f = oldFields.get(ref.getIndex());
+ for (int index = 0; index < newFields.size(); index++) {
+ RelDataTypeField newf = newFields.get(index);
+ if (f.getKey().equals(newf.getKey())
+ && f.getValue() == newf.getValue()) {
+ return new RexInputRef(index, f.getValue());
+ }
+ }
+ throw MatchFailed.INSTANCE;
+ }
+ };
+ return shuttle.apply(nodes);
+ }
+}
+
+// End MaterializedViewSubstitutionVisitor.java