@SuppressWarnings("nls")
  private Operator genGroupByPlan2MR(String dest, QB qb, Operator input)
      throws SemanticException {

    QBParseInfo parseInfo = qb.getParseInfo();

    Pair<List<ASTNode>, List<Long>> grpByExprsGroupingSets = getGroupByGroupingSetsForClause(parseInfo, dest);

    List<ASTNode> grpByExprs = grpByExprsGroupingSets.getLeft();
    List<Long> groupingSets = grpByExprsGroupingSets.getRight();

    // Grouping sets are not allowed
    // This restriction can be lifted in future.
    // HIVE-3508 has been filed for this
    if (!groupingSets.isEmpty()) {
      throw new SemanticException(ErrorMsg.HIVE_GROUPING_SETS_AGGR_NOMAPAGGR.getMsg());
    }

    // ////// 1. Generate ReduceSinkOperator
    // There is a special case when we want the rows to be randomly distributed
    // to
    // reducers for load balancing problem. That happens when there is no
    // DISTINCT
    // operator. We set the numPartitionColumns to -1 for this purpose. This is
    // captured by WritableComparableHiveObject.hashCode() function.
    ReduceSinkOperator reduceSinkOperatorInfo =
        genGroupByPlanReduceSinkOperator(qb,
            dest,
            input,
            grpByExprs,
            (parseInfo.getDistinctFuncExprsForClause(dest).isEmpty() ? -1 : Integer.MAX_VALUE),
            false,
            -1,
            false,
            false);

    // ////// 2. Generate GroupbyOperator
    Map<String, GenericUDAFEvaluator> genericUDAFEvaluators =
        new LinkedHashMap<String, GenericUDAFEvaluator>();
    GroupByOperator groupByOperatorInfo = (GroupByOperator) genGroupByPlanGroupByOperator(
        parseInfo, dest, reduceSinkOperatorInfo, reduceSinkOperatorInfo, GroupByDesc.Mode.PARTIAL1,
        genericUDAFEvaluators);

    int numReducers = -1;
    if (grpByExprs.isEmpty()) {
      numReducers = 1;
    }

    // ////// 3. Generate ReduceSinkOperator2
    Operator reduceSinkOperatorInfo2 = genGroupByPlanReduceSinkOperator2MR(
        parseInfo, dest, groupByOperatorInfo, grpByExprs.size(), numReducers, false);

    // ////// 4. Generate GroupbyOperator2
    Operator groupByOperatorInfo2 = genGroupByPlanGroupByOperator2MR(parseInfo,
        dest, reduceSinkOperatorInfo2,
        genericUDAFEvaluators, false);

    return groupByOperatorInfo2;
  }
Generate a Group-By plan using a 2 map-reduce jobs (5 operators will be
inserted):

ReduceSink ( keys = (K1_EXP, K2_EXP, DISTINCT_EXP), values = (A1_EXP,
A2_EXP) ) NOTE: If DISTINCT_EXP is null, partition by rand() SortGroupBy
(keys = (KEY.0,KEY.1), aggregations = (count_distinct(KEY.2), sum(VALUE.0),
count(VALUE.1))) ReduceSink ( keys = (0,1), values=(2,3,4)) SortGroupBy
(keys = (KEY.0,KEY.1), aggregations = (sum(VALUE.0), sum(VALUE.1),
sum(VALUE.2))) Select (final selects).

@param dest
@param qb
@param input
@return
@throws SemanticException

          Generate a Group-By plan using a 2 map-reduce jobs. Spray by the
          grouping key and distinct key (or a random number, if no distinct
          is present) in hope of getting a uniform distribution, and
          compute partial aggregates grouped by the reduction key (grouping
          key + distinct key). Evaluate partial aggregates first, and spray
          by the grouping key to compute actual aggregates in the second
          phase. The aggregation evaluation functions are as follows:
          Partitioning Key: random() if no DISTINCT grouping + distinct key
          if DISTINCT

          Sorting Key: grouping key if no DISTINCT grouping + distinct key
          if DISTINCT

          Reducer: iterate/terminatePartial (mode = PARTIAL1)

          STAGE 2

          Partitioning Key: grouping key

          Sorting Key: grouping key if no DISTINCT grouping + distinct key
          if DISTINCT

          Reducer: merge/terminate (mode = FINAL)
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java