@Override
    public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx procCtx,
        Object... nodeOutputs) throws SemanticException {
      super.process(nd, stack, procCtx, nodeOutputs);
      OpWalkerInfo owi = (OpWalkerInfo) procCtx;
      GroupByDesc groupByDesc = ((GroupByOperator)nd).getConf();
      ExprWalkerInfo prunedPred = owi.getPrunedPreds((Operator<? extends OperatorDesc>) nd);
      if (prunedPred == null || !prunedPred.hasAnyCandidates() ||
          !groupByDesc.isGroupingSetsPresent()) {
        return null;
      }

      List<Long> groupingSets = groupByDesc.getListGroupingSets();
      Map<String, List<ExprNodeDesc>> candidates = prunedPred.getFinalCandidates();
      FastBitSet[] fastBitSets = new FastBitSet[groupingSets.size()];
      int groupingSetPosition = groupByDesc.getGroupingSetPosition();
      for (int pos = 0; pos < fastBitSets.length; pos ++) {
        fastBitSets[pos] = GroupByOperator.groupingSet2BitSet(groupingSets.get(pos),
            groupingSetPosition);
      }
      List<ExprNodeDesc> groupByKeys = ((GroupByOperator)nd).getConf().getKeys();
      Map<ExprNodeDesc, ExprNodeDesc> newToOldExprMap = prunedPred.getNewToOldExprMap();
      Map<String, List<ExprNodeDesc>> nonFinalCandidates = new HashMap<String, List<ExprNodeDesc>>();
      Iterator<Map.Entry<String, List<ExprNodeDesc>>> iter = candidates.entrySet().iterator();
      while (iter.hasNext()) {
        Map.Entry<String, List<ExprNodeDesc>> entry = iter.next();
        List<ExprNodeDesc> residualExprs = new ArrayList<ExprNodeDesc>();
        List<ExprNodeDesc> finalCandidates = new ArrayList<ExprNodeDesc>();
        List<ExprNodeDesc> exprs = entry.getValue();
        for (ExprNodeDesc expr : exprs) {
          if (canPredPushdown(expr, groupByKeys, fastBitSets, groupingSetPosition)) {
            finalCandidates.add(expr);
          } else {
            residualExprs.add(newToOldExprMap.get(expr));
          }
        }
        if (!residualExprs.isEmpty()) {
          nonFinalCandidates.put(entry.getKey(), residualExprs);
        }

        if (finalCandidates.isEmpty()) {
          iter.remove();
        } else {
          exprs.clear();
          exprs.addAll(finalCandidates);
        }
      }

      logExpr(nd, prunedPred);
      if (!nonFinalCandidates.isEmpty()) {
        createFilter((Operator) nd, nonFinalCandidates, owi);
      }
      return null;
    }
Replaces exprNodeDescs in the specified exprNodeDesc using replaceMap by traversing the expression tree.
@param exprNodeDesc expression where exprNodeDescs should be replaced.
@param replaceMap Map containing replacements: key exprNodeDesc should be replaced to value exprNodeDesc.
@return The new expression with replaced exprNodeDescs.
ql/src/java/org/apache/hadoop/hive/ql/ppd/OpProcFactory.java