@Override
    public Object process(Node nd, Stack<Node> stack, NodeProcessorCtx ctx,
        Object... nodeOutputs) throws SemanticException {
      GroupByOperator gbOp = (GroupByOperator) nd;
      ColumnPrunerProcCtx cppCtx = (ColumnPrunerProcCtx) ctx;
      List<FieldNode> colLists = new ArrayList<>();
      GroupByDesc conf = gbOp.getConf();

      List<ExprNodeDesc> keys = conf.getKeys();
      for (ExprNodeDesc key : keys) {
        colLists = mergeFieldNodesWithDesc(colLists, key);
      }

      List<AggregationDesc> aggrs = conf.getAggregators();
      for (AggregationDesc aggr : aggrs) {
        List<ExprNodeDesc> params = aggr.getParameters();
        for (ExprNodeDesc param : params) {
          colLists = mergeFieldNodesWithDesc(colLists, param);
        }
      }

      int groupingSetPosition = conf.getGroupingSetPosition();
      if (groupingSetPosition >= 0) {
        List<FieldNode> neededCols = cppCtx.genColLists(gbOp);
        String groupingColumn = conf.getOutputColumnNames().get(groupingSetPosition);
        if (lookupColumn(neededCols, groupingColumn) == null) {
          conf.addComputedField(groupingColumn);
          conf.getOutputColumnNames().remove(groupingSetPosition);
          if (gbOp.getSchema() != null) {
            gbOp.getSchema().getSignature().remove(groupingSetPosition);
          }
        }
      }

      // If the child has a different schema, we create a Project operator between them both,
      // as we cannot prune the columns in the GroupBy operator
      for (Operator<?> child : gbOp.getChildOperators()) {
        if (child instanceof SelectOperator || child instanceof ReduceSinkOperator) {
          continue;
        }
        List<FieldNode> colList = cppCtx.genColLists(gbOp, child);
        Set<FieldNode> neededCols = new HashSet<>();
        if (colList != null) {
          neededCols.addAll(colList);
        } else {
          // colList will be null for FS operators.
          continue;
        }
        if (neededCols.size() < gbOp.getSchema().getSignature().size()) {
          ArrayList<ExprNodeDesc> exprs = new ArrayList<ExprNodeDesc>();
          ArrayList<String> outputColNames = new ArrayList<String>();
          Map<String, ExprNodeDesc> colExprMap = new HashMap<String, ExprNodeDesc>();
          ArrayList<ColumnInfo> outputRS = new ArrayList<ColumnInfo>();
          for (ColumnInfo colInfo : gbOp.getSchema().getSignature()) {
            if (lookupColumn(neededCols, colInfo.getInternalName()) == null) {
              continue;
            }
            ExprNodeDesc colDesc = new ExprNodeColumnDesc(colInfo.getType(),
                colInfo.getInternalName(), colInfo.getTabAlias(), colInfo.getIsVirtualCol());
            exprs.add(colDesc);
            outputColNames.add(colInfo.getInternalName());
            ColumnInfo newCol = new ColumnInfo(colInfo.getInternalName(), colInfo.getType(),
                    colInfo.getTabAlias(), colInfo.getIsVirtualCol(), colInfo.isHiddenVirtualCol());
            newCol.setAlias(colInfo.getAlias());
            outputRS.add(newCol);
            colExprMap.put(colInfo.getInternalName(), colDesc);
          }
          SelectDesc select = new SelectDesc(exprs, outputColNames, false);
          gbOp.removeChild(child);
          SelectOperator sel = (SelectOperator) OperatorFactory.getAndMakeChild(
              select, new RowSchema(outputRS), gbOp);
          OperatorFactory.makeChild(sel, child);
          sel.setColumnExprMap(colExprMap);
        }
      }

      cppCtx.getPrunedColLists().put(gbOp, colLists);
      return null;
    }
Node Processor for Column Pruning on Group By Operators.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/ColumnPrunerProcFactory.java