private void pushOperatorsAboveUnion(UnionOperator union,
      Stack<Node> stack, int pos) throws SemanticException {
      // Clone all the operators between union and filescan, and push them above
      // the union. Remove the union (the tree below union gets delinked after that)
      try {
        List<Operator<? extends OperatorDesc>> parents =
          union.getParentOperators();
        int numParents = parents.size();
        for (Operator<? extends OperatorDesc> parent : parents) {
          parent.setChildOperators(null);
        }

        for (; pos < stack.size() - 1; pos++) {
          Operator<? extends OperatorDesc> originalOp =
            (Operator<? extends OperatorDesc>)stack.get(pos);

          for (int p = 0; p < numParents; p++) {
            OperatorDesc cloneDesc = (OperatorDesc)originalOp.getConf().clone();

            RowSchema origSchema = originalOp.getSchema();
            Map<String, ExprNodeDesc> origColExprMap = originalOp.getColumnExprMap();

            Operator<? extends OperatorDesc> cloneOp =
              OperatorFactory.getAndMakeChild(cloneDesc,
                origSchema == null ? null : new RowSchema(origSchema), 
                origColExprMap == null ? null : new HashMap(origColExprMap), 
                parents.get(p));
            parents.set(p, cloneOp);
          }
        }

        // FileSink cannot be simply cloned - it requires some special processing.
        // Sub-queries for the union will be processed as independent map-reduce jobs
        // possibly running in parallel. Those sub-queries cannot write to the same
        // directory. Clone the filesink, but create a sub-directory in the final path
        // for each sub-query. Also, these different filesinks need to be linked to each other
        FileSinkOperator fileSinkOp = (FileSinkOperator)stack.get(pos);
        // For file sink operator, change the directory name
        Path parentDirName = fileSinkOp.getConf().getDirName();

        // Clone the fileSinkDesc of the final fileSink and create similar fileSinks at
        // each parent
        List<FileSinkDesc> fileDescLists = new ArrayList<FileSinkDesc>();

        for (Operator<? extends OperatorDesc> parent : parents) {
          FileSinkDesc fileSinkDesc = (FileSinkDesc) fileSinkOp.getConf().clone();
          fileSinkDesc.setDirName(new Path(parentDirName, AbstractFileMergeOperator.UNION_SUDBIR_PREFIX + parent.getIdentifier()));
          fileSinkDesc.setLinkedFileSink(true);
          if (Utilities.FILE_OP_LOGGER.isTraceEnabled()) {
            Utilities.FILE_OP_LOGGER.trace("Created LinkedFileSink for union " + fileSinkDesc.getDirName()
                + "; parent " + parentDirName);
          }
          parent.setChildOperators(null);
          Operator<? extends OperatorDesc> tmpFileSinkOp =
            OperatorFactory.getAndMakeChild(fileSinkDesc, parent.getSchema(), parent);
          tmpFileSinkOp.setChildOperators(null);
          fileDescLists.add(fileSinkDesc);
        }

        for (FileSinkDesc fileDesc : fileDescLists) {
          fileDesc.setLinkedFileSinkDesc(fileDescLists);
        }

        // delink union
        union.setChildOperators(null);
        union.setParentOperators(null);
      } catch (Exception e) {
        throw new SemanticException(e.getMessage());
      }
    }
Union followed by no processing.
This is to optimize queries of the type:
select * from (subq1 union all subq2 ...)x;
where at least one of the queries involve a map-reduce job.
There is no need for a union in this scenario - it involves an extra
write and read for the final output without this optimization.
Queries of the form:
  select x.c1 from (subq1 union all subq2 ...)x where filter(x.c2);
can be transformed to:
  select * from (subq1 where filter union all subq2 where filter ...)x;
and then optimized.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/unionproc/UnionProcFactory.java