All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hadoop.hive.ql.ppd.ExprWalkerInfo Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * 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.ppd;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hive.ql.exec.Operator;
import org.apache.hadoop.hive.ql.lib.NodeProcessorCtx;
import org.apache.hadoop.hive.ql.plan.ExprNodeDesc;
import org.apache.hadoop.hive.ql.plan.OperatorDesc;

/**
 * Context for Expression Walker for determining predicate pushdown candidates
 * It contains a ExprInfo object for each expression that is processed.
 */
public class ExprWalkerInfo implements NodeProcessorCtx {

  /** Information maintained for an expr while walking an expr tree. */
  private static class ExprInfo {
    /**
     * true if expr rooted at this node doesn't contain more than one table.
     * alias
     */
    public boolean isCandidate = false;
    /** alias that this expression refers to. */
    public String alias = null;
    /** new expr for this expression. */
    public ExprNodeDesc convertedExpr = null;

    public ExprInfo() {
    }

    public ExprInfo(boolean isCandidate, String alias, ExprNodeDesc replacedNode) {
      this.isCandidate = isCandidate;
      this.alias = alias;
      convertedExpr = replacedNode;
    }
  }

  protected static final Log LOG = LogFactory.getLog(OpProcFactory.class
      .getName());;
  private Operator op = null;

  /**
   * Values the expression sub-trees (predicates) that can be pushed down for
   * root expression tree. Since there can be more than one alias in an
   * expression tree, this is a map from the alias to predicates.
   */
  private final Map> pushdownPreds;

  /**
   * Values the expression sub-trees (predicates) that can not be pushed down for
   * root expression tree. Since there can be more than one alias in an
   * expression tree, this is a map from the alias to predicates.
   */
  private final Map> nonFinalPreds;

  /**
   * this map contains a expr infos. Each key is a node in the expression tree
   * and the information for each node is the value which is used while walking
   * the tree by its parent.
   */
  private final Map exprInfoMap;

  /**
   * This is a map from a new pushdown expressions generated by the ExprWalker
   * to the old pushdown expression that it originated from. For example, if
   * an output column of the current operator is _col0, which comes from an
   * input column _col1, this would map the filter "Column[_col1]=2" to
   * "Column[_col0]=2" ("Column[_col1]=2" is new because we move from children
   * operators to parents in PPD)
   */
  private final Map newToOldExprMap;

  private boolean isDeterministic = true;

  public ExprWalkerInfo() {
    pushdownPreds = new HashMap>();
    nonFinalPreds = new HashMap>();
    exprInfoMap = new HashMap();
    newToOldExprMap = new HashMap();
  }

  public ExprWalkerInfo(Operator op) {
    this.op = op;

    pushdownPreds = new HashMap>();
    exprInfoMap = new HashMap();
    nonFinalPreds = new HashMap>();
    newToOldExprMap = new HashMap();
  }

  /**
   * @return the op of this expression.
   */
  public Operator getOp() {
    return op;
  }

  /**
   * @return the new expression to old expression map
   */
  public Map getNewToOldExprMap() {
    return newToOldExprMap;
  }

  /**
   * @return converted expression for give node. If there is none then returns
   *         null.
   */
  public ExprNodeDesc getConvertedNode(ExprNodeDesc nd) {
    ExprInfo ei = exprInfoMap.get(nd);
    if (ei == null) {
      return null;
    }
    return ei.convertedExpr;
  }

  /**
   * adds a replacement node for this expression.
   *
   * @param oldNode
   *          original node
   * @param newNode
   *          new node
   */
  public void addConvertedNode(ExprNodeDesc oldNode, ExprNodeDesc newNode) {
    ExprInfo ei = exprInfoMap.get(oldNode);
    if (ei == null) {
      ei = new ExprInfo();
      exprInfoMap.put(oldNode, ei);
    }
    ei.convertedExpr = newNode;
    exprInfoMap.put(newNode, new ExprInfo(ei.isCandidate, ei.alias, null));
  }

  /**
   * Returns true if the specified expression is pushdown candidate else false.
   *
   * @param expr
   * @return true or false
   */
  public boolean isCandidate(ExprNodeDesc expr) {
    ExprInfo ei = exprInfoMap.get(expr);
    if (ei == null) {
      return false;
    }
    return ei.isCandidate;
  }

  /**
   * Marks the specified expr to the specified value.
   *
   * @param expr
   * @param b
   *          can
   */
  public void setIsCandidate(ExprNodeDesc expr, boolean b) {
    ExprInfo ei = exprInfoMap.get(expr);
    if (ei == null) {
      ei = new ExprInfo();
      exprInfoMap.put(expr, ei);
    }
    ei.isCandidate = b;
  }

  /**
   * Returns the alias of the specified expr.
   *
   * @param expr
   * @return The alias of the expression
   */
  public String getAlias(ExprNodeDesc expr) {
    ExprInfo ei = exprInfoMap.get(expr);
    if (ei == null) {
      return null;
    }
    return ei.alias;
  }

  /**
   * Adds the specified alias to the specified expr.
   *
   * @param expr
   * @param alias
   */
  public void addAlias(ExprNodeDesc expr, String alias) {
    if (alias == null) {
      return;
    }
    ExprInfo ei = exprInfoMap.get(expr);
    if (ei == null) {
      ei = new ExprInfo();
      exprInfoMap.put(expr, ei);
    }
    ei.alias = alias;
  }

  /**
   * Adds the specified expr as the top-most pushdown expr (ie all its children
   * can be pushed).
   *
   * @param expr
   */
  public void addFinalCandidate(ExprNodeDesc expr) {
    addFinalCandidate(getAlias(expr), expr);
  }

  public void addFinalCandidate(String alias, ExprNodeDesc expr) {
    getPushdownPreds(alias).add(expr);
  }

  /**
   * Adds the passed list of pushDowns for the alias.
   *
   * @param alias
   * @param pushDowns
   */
  public void addPushDowns(String alias, List pushDowns) {
    getPushdownPreds(alias).addAll(pushDowns);
  }

  /**
   * Returns the list of pushdown expressions for each alias that appear in the
   * current operator's RowResolver. The exprs in each list can be combined
   * using conjunction (AND).
   *
   * @return the map of alias to a list of pushdown predicates
   */
  public Map> getFinalCandidates() {
    return pushdownPreds;
  }

  private List getPushdownPreds(String alias) {
    List predicates = pushdownPreds.get(alias);
    if (predicates == null) {
      pushdownPreds.put(alias, predicates = new ArrayList());
    }
    return predicates;
  }

  public boolean hasAnyCandidates() {
    if (pushdownPreds == null || pushdownPreds.isEmpty()) {
      return false;
    }
    for (List exprs : pushdownPreds.values()) {
      if (!exprs.isEmpty()) {
        return true;
      }
    }
    return false;
  }

  /**
   * Adds the specified expr as a non-final candidate
   *
   * @param expr
   */
  public void addNonFinalCandidate(ExprNodeDesc expr) {
    String alias = getAlias(expr);
    if (nonFinalPreds.get(alias) == null) {
      nonFinalPreds.put(alias, new ArrayList());
    }
    nonFinalPreds.get(alias).add(expr);
  }

  /**
   * Returns list of non-final candidate predicate for each map.
   *
   * @return list of non-final candidate predicates
   */
  public Map> getNonFinalCandidates() {
    return nonFinalPreds;
  }

  public Map> getResidualPredicates(boolean clear) {
    Map> oldExprs = new HashMap>();
    for (Map.Entry> entry : nonFinalPreds.entrySet()) {
      List converted = new ArrayList();
      for (ExprNodeDesc newExpr : entry.getValue()) {
        converted.add(newToOldExprMap.get(newExpr));
      }
      oldExprs.put(entry.getKey(), converted);
    }
    if (clear) {
      nonFinalPreds.clear();
    }
    return oldExprs;
  }

  /**
   * Merges the specified pushdown predicates with the current class.
   *
   * @param ewi
   *          ExpressionWalkerInfo
   */
  public void merge(ExprWalkerInfo ewi) {
    if (ewi == null) {
      return;
    }
    for (Entry> e : ewi.getFinalCandidates()
        .entrySet()) {
      List predList = pushdownPreds.get(e.getKey());
      if (predList != null) {
        predList.addAll(e.getValue());
      } else {
        pushdownPreds.put(e.getKey(), e.getValue());
      }
    }
    for (Entry> e : ewi.getNonFinalCandidates()
        .entrySet()) {
      List predList = nonFinalPreds.get(e.getKey());
      if (predList != null) {
        predList.addAll(e.getValue());
      } else {
        nonFinalPreds.put(e.getKey(), e.getValue());
      }
    }
    newToOldExprMap.putAll(ewi.getNewToOldExprMap());
  }

  /**
   * sets the deterministic flag for this expression.
   *
   * @param b
   *          deterministic or not
   */
  public void setDeterministic(boolean b) {
    isDeterministic = b;
  }

  /**
   * @return whether this expression is deterministic or not.
   */
  public boolean isDeterministic() {
    return isDeterministic;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy