@SuppressWarnings("nls")
  private Operator genGroupByPlanMapAggrNoSkew(String dest, QB qb,
                                               Operator inputOperatorInfo) 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();
    boolean groupingSetsPresent = !groupingSets.isEmpty();

    int newMRJobGroupingSetsThreshold =
        conf.getIntVar(HiveConf.ConfVars.HIVE_NEW_JOB_GROUPING_SET_CARDINALITY);

    // ////// Generate GroupbyOperator for a map-side partial aggregation
    Map<String, GenericUDAFEvaluator> genericUDAFEvaluators =
        new LinkedHashMap<String, GenericUDAFEvaluator>();

    // Is the grouping sets data consumed in the current in MR job, or
    // does it need an additional MR job
    boolean groupingSetsNeedAdditionalMRJob = groupingSetsPresent &&
        groupingSets.size() > newMRJobGroupingSetsThreshold;

    GroupByOperator groupByOperatorInfo =
        (GroupByOperator) genGroupByPlanMapGroupByOperator(
            qb,
            dest,
            grpByExprs,
            inputOperatorInfo,
            genericUDAFEvaluators,
            groupingSets,
            groupingSetsPresent && !groupingSetsNeedAdditionalMRJob);

    groupOpToInputTables.put(groupByOperatorInfo, opParseCtx.get(
        inputOperatorInfo).getRowResolver().getTableNames());
    int numReducers = -1;

    // Optimize the scenario when there are no grouping keys - only 1 reducer is
    // needed
    if (grpByExprs.isEmpty()) {
      numReducers = 1;
    }

    // ////// Generate ReduceSink Operator
    boolean isDistinct = !qb.getParseInfo().getDistinctFuncExprsForClause(dest).isEmpty();

    // Distincts are not allowed with an additional mr job
    if (groupingSetsNeedAdditionalMRJob && isDistinct) {
      String errorMsg = "The number of rows per input row due to grouping sets is "
          + groupingSets.size();
      throw new SemanticException(
          ErrorMsg.HIVE_GROUPING_SETS_THRESHOLD_NOT_ALLOWED_WITH_DISTINCTS.getMsg(errorMsg));
    }

    Operator reduceSinkOperatorInfo =
        genGroupByPlanReduceSinkOperator(qb,
            dest,
            groupByOperatorInfo,
            grpByExprs,
            grpByExprs.size(),
            true,
            numReducers,
            true,
            groupingSetsPresent && !groupingSetsNeedAdditionalMRJob);

    // Does it require a new MR job for grouping sets
    if (!groupingSetsPresent || !groupingSetsNeedAdditionalMRJob) {
      // This is a 1-stage map-reduce processing of the groupby. Tha map-side
      // aggregates was just used to
      // reduce output data. In case of distincts, partial results are not used,
      // and so iterate is again
      // invoked on the reducer. In case of non-distincts, partial results are
      // used, and merge is invoked
      // on the reducer.
      return genGroupByPlanGroupByOperator1(parseInfo, dest,
          reduceSinkOperatorInfo, GroupByDesc.Mode.MERGEPARTIAL,
          genericUDAFEvaluators,
          groupingSets, groupingSetsPresent, groupingSetsNeedAdditionalMRJob);
    }
    else
    {
      // Add 'n' rows corresponding to the grouping sets. For each row, create 'n' rows,
      // one for each grouping set key. Since map-side aggregation has already been performed,
      // the number of rows would have been reduced. Moreover, the rows corresponding to the
      // grouping keys come together, so there is a higher chance of finding the rows in the hash
      // table.
      Operator groupByOperatorInfo2 =
          genGroupByPlanGroupByOperator1(parseInfo, dest,
              reduceSinkOperatorInfo, GroupByDesc.Mode.PARTIALS,
              genericUDAFEvaluators,
              groupingSets, groupingSetsPresent, groupingSetsNeedAdditionalMRJob);

      // ////// Generate ReduceSinkOperator2
      Operator reduceSinkOperatorInfo2 = genGroupByPlanReduceSinkOperator2MR(
          parseInfo, dest, groupByOperatorInfo2, grpByExprs.size() + 1, numReducers,
          groupingSetsPresent);

      // ////// Generate GroupbyOperator3
      return genGroupByPlanGroupByOperator2MR(parseInfo, dest,
          reduceSinkOperatorInfo2,
          genericUDAFEvaluators, groupingSetsPresent);
    }
  }
Generate a Group-By plan using 1 map-reduce job. First perform a map-side
partial aggregation (to reduce the amount of data), at this point of time,
we may turn off map-side partial aggregation based on its performance. Then
spray by the group by key, and sort by the distinct key (if any), and
compute aggregates based on actual aggregates

The aggregation evaluation functions are as follows:

No grouping sets:
Group By Operator:
grouping keys: group by expressions if no DISTINCT
grouping keys: group by expressions + distinct keys if DISTINCT
Mapper: iterate/terminatePartial (mode = HASH)
Partitioning Key: grouping key
Sorting Key: grouping key if no DISTINCT
grouping + distinct key if DISTINCT
Reducer: iterate/terminate if DISTINCT
merge/terminate if NO DISTINCT (mode MERGEPARTIAL)

Grouping Sets:
Group By Operator:
grouping keys: group by expressions + grouping id. if no DISTINCT
grouping keys: group by expressions + grouping id. + distinct keys if DISTINCT
Mapper: iterate/terminatePartial (mode = HASH)
Partitioning Key: grouping key + grouping id.
Sorting Key: grouping key + grouping id. if no DISTINCT
grouping + grouping id. + distinct key if DISTINCT
Reducer: iterate/terminate if DISTINCT
merge/terminate if NO DISTINCT (mode MERGEPARTIAL)

Grouping Sets with an additional MR job introduced (distincts are not allowed):
Group By Operator:
grouping keys: group by expressions
Mapper: iterate/terminatePartial (mode = HASH)
Partitioning Key: grouping key
Sorting Key: grouping key
Reducer: merge/terminate (mode MERGEPARTIAL)
Group by Operator:
grouping keys: group by expressions + add a new grouping id. key

STAGE 2
Partitioning Key: grouping key + grouping id.
Sorting Key: grouping key + grouping id.
Reducer: merge/terminate (mode = FINAL)
Group by Operator:
grouping keys: group by expressions + grouping id.
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java