private Operator genMapGroupByForSemijoin(List<ASTNode> fields, Operator<?> input)
      throws SemanticException {

    RowResolver groupByInputRowResolver = opParseCtx.get(input).getRowResolver();
    RowResolver groupByOutputRowResolver = new RowResolver();
    List<ExprNodeDesc> groupByKeys = new ArrayList<ExprNodeDesc>();
    List<String> outputColumnNames = new ArrayList<String>();
    List<AggregationDesc> aggregations = new ArrayList<AggregationDesc>();
    Map<String, ExprNodeDesc> colExprMap = new HashMap<String, ExprNodeDesc>();

    for (int i = 0; i < fields.size(); ++i) {
      // get the group by keys to ColumnInfo
      ASTNode colName = fields.get(i);
      String[] nm;
      String[] nm2;
      ExprNodeDesc grpByExprNode = genExprNodeDesc(colName, groupByInputRowResolver);
      if (grpByExprNode instanceof ExprNodeColumnDesc) {
        // In most of the cases, this is a column reference
        ExprNodeColumnDesc columnExpr = (ExprNodeColumnDesc) grpByExprNode;
        nm = groupByInputRowResolver.reverseLookup(columnExpr.getColumn());
        nm2 = groupByInputRowResolver.getAlternateMappings(columnExpr.getColumn());
      } else if (grpByExprNode instanceof ExprNodeConstantDesc) {
        // However, it can be a constant too. In that case, we need to track
        // the column that it originated from in the input operator so we can
        // propagate the aliases.
        ExprNodeConstantDesc constantExpr = (ExprNodeConstantDesc) grpByExprNode;
        String inputCol = constantExpr.getFoldedFromCol();
        nm = groupByInputRowResolver.reverseLookup(inputCol);
        nm2 = groupByInputRowResolver.getAlternateMappings(inputCol);
      } else {
        // We might generate other types that are not recognized, e.g., a field reference
        // if it is a nested field, but since this is just an additional optimization,
        // we bail out without introducing the Select + GroupBy below the right input
        // of the left semijoin
        return input;
      }
      groupByKeys.add(grpByExprNode);
      // generate output column names
      String field = getColumnInternalName(i);
      outputColumnNames.add(field);
      ColumnInfo colInfo2 = new ColumnInfo(field, grpByExprNode.getTypeInfo(),
          "", false);
      groupByOutputRowResolver.put(nm[0], nm[1], colInfo2);
      if (nm2 != null) {
        groupByOutputRowResolver.addMappingOnly(nm2[0], nm2[1], colInfo2);
      }
      groupByOutputRowResolver.putExpression(colName, colInfo2);
      // establish mapping from the output column to the input column
      colExprMap.put(field, grpByExprNode);
    }

    // Generate group-by operator
    float groupByMemoryUsage = HiveConf.getFloatVar(conf, HiveConf.ConfVars.HIVE_MAP_AGGR_HASH_MEMORY);
    float memoryThreshold = HiveConf
        .getFloatVar(conf, HiveConf.ConfVars.HIVE_MAP_AGGR_MEMORY_THRESHOLD);
    float minReductionHashAggr = HiveConf
        .getFloatVar(conf, HiveConf.ConfVars.HIVE_MAP_AGGR_HASH_MIN_REDUCTION);
    float minReductionHashAggrLowerBound = HiveConf
            .getFloatVar(conf, ConfVars.HIVE_MAP_AGGR_HASH_MIN_REDUCTION_LOWER_BOUND);
    float hashAggrFlushPercent = HiveConf
        .getFloatVar(conf, ConfVars.HIVE_MAP_AGGR_HASH_FLUSH_SIZE_PERCENT);
    Operator op = putOpInsertMap(OperatorFactory.getAndMakeChild(
        new GroupByDesc(GroupByDesc.Mode.HASH, outputColumnNames, groupByKeys, aggregations,
            false, groupByMemoryUsage, memoryThreshold, minReductionHashAggr, minReductionHashAggrLowerBound,
                hashAggrFlushPercent, null, false, -1, false),
        new RowSchema(groupByOutputRowResolver.getColumnInfos()),
        input), groupByOutputRowResolver);

    op.setColumnExprMap(colExprMap);
    return op;
  }
Construct a selection operator for semijoin that filter out all fields
other than the group by keys.

@param fields
         list of fields need to be output
@param input
         input operator
@return the selection operator.
@throws SemanticException
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java