private static OpAttr genMapSideRS(OpAttr inputOpAf, GBInfo gbInfo) throws SemanticException {
    Map<String, ExprNodeDesc> colExprMap = new HashMap<String, ExprNodeDesc>();
    List<String> outputKeyColumnNames = new ArrayList<String>();
    List<String> outputValueColumnNames = new ArrayList<String>();
    ArrayList<ColumnInfo> colInfoLst = new ArrayList<ColumnInfo>();
    String outputColName;

    // 1. Add GB Keys to reduce keys
    ArrayList<ExprNodeDesc> reduceKeys= new ArrayList<ExprNodeDesc>();
    for (int i = 0; i < gbInfo.gbKeys.size(); i++) {
      //gbInfo already has ExprNode for gbkeys
      reduceKeys.add(gbInfo.gbKeys.get(i));
      String colOutputName = SemanticAnalyzer.getColumnInternalName(i);
      outputKeyColumnNames.add(colOutputName);
      colInfoLst.add(new ColumnInfo(Utilities.ReduceField.KEY.toString() + "." + colOutputName, gbInfo.gbKeyTypes.get(i), "", false));
      colExprMap.put(colOutputName, gbInfo.gbKeys.get(i));
    }

    // Note: GROUPING SETS are not allowed with map side aggregation set to false so we don't have to worry about it

    int keyLength = reduceKeys.size();

    // 2. Add Dist UDAF args to reduce keys
    if (gbInfo.containsDistinctAggr) {
      // TODO: Why is this needed (doesn't represent any cols)
      String udafName = SemanticAnalyzer.getColumnInternalName(reduceKeys.size());
      outputKeyColumnNames.add(udafName);
      for (int i = 0; i < gbInfo.distExprNodes.size(); i++) {
        reduceKeys.add(gbInfo.distExprNodes.get(i));
        //this part of reduceKeys is later used to create column names strictly for non-distinct aggregates
        // with parameters same as distinct keys which expects _col0 at the end. So we always append
        // _col0 at the end instead of _col<i>
        outputColName = SemanticAnalyzer.getColumnInternalName(0);
        String field = Utilities.ReduceField.KEY.toString() + "." + udafName + ":" + i + "."
            + outputColName;
        ColumnInfo colInfo = new ColumnInfo(field, gbInfo.distExprNodes.get(i).getTypeInfo(), null,
            false);
        colInfoLst.add(colInfo);
        colExprMap.put(field, gbInfo.distExprNodes.get(i));
      }
    }

    // 3. Add UDAF args deduped to reduce values
    ArrayList<ExprNodeDesc> reduceValues = new ArrayList<ExprNodeDesc>();
    for (int i = 0; i < gbInfo.deDupedNonDistIrefs.size(); i++) {
      reduceValues.add(gbInfo.deDupedNonDistIrefs.get(i));
      outputColName = SemanticAnalyzer.getColumnInternalName(reduceValues.size() - 1);
      outputValueColumnNames.add(outputColName);
      String field = Utilities.ReduceField.VALUE.toString() + "." + outputColName;
      colInfoLst.add(new ColumnInfo(field, reduceValues.get(reduceValues.size() - 1).getTypeInfo(),
          null, false));
      colExprMap.put(field, reduceValues.get(reduceValues.size() - 1));
    }

    // 4. Gen RS
    ReduceSinkOperator rsOp = (ReduceSinkOperator) OperatorFactory.getAndMakeChild(PlanUtils
        .getReduceSinkDesc(reduceKeys, keyLength, reduceValues,
            gbInfo.distColIndices, outputKeyColumnNames,
            outputValueColumnNames, true, -1, getNumPartFieldsForMapSideRS(gbInfo),
            getParallelismForMapSideRS(gbInfo), AcidUtils.Operation.NOT_ACID, gbInfo.defaultNullOrder), new RowSchema(
        colInfoLst), inputOpAf.inputs.get(0));

    rsOp.setColumnExprMap(colExprMap);

    return new OpAttr("", new HashSet<Integer>(), rsOp);
  }
RS-GB1-RS-GB2

@param inputOpAf
@param aggRel
@param gbInfo
@return
@throws SemanticException
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/opconventer/HiveGBOpConvUtil.java