@Override
  public ParseContext transform(ParseContext pactx) throws SemanticException {
    List<MapJoinOperator> listMapJoinOps = new ArrayList<MapJoinOperator>();

    // traverse all the joins and convert them if necessary
    if (pactx.getJoinOps() != null) {
      Set<JoinOperator> joinMap = new HashSet<JoinOperator>();
      Set<MapJoinOperator> mapJoinMap = pactx.getMapJoinOps();
      if (mapJoinMap == null) {
        mapJoinMap = new HashSet<MapJoinOperator>();
        pactx.setMapJoinOps(mapJoinMap);
      }

      Iterator<JoinOperator> joinCtxIter = pactx.getJoinOps().iterator();
      while (joinCtxIter.hasNext()) {
        JoinOperator joinOp = joinCtxIter.next();
        int mapJoinPos = mapSideJoin(joinOp);
        if (mapJoinPos >= 0) {
          MapJoinOperator mapJoinOp = generateMapJoinOperator(pactx, joinOp, mapJoinPos);
          listMapJoinOps.add(mapJoinOp);
          mapJoinOp.getConf().setQBJoinTreeProps(joinOp.getConf());
          mapJoinMap.add(mapJoinOp);
        } else {
          joinOp.getConf().setQBJoinTreeProps(joinOp.getConf());
          joinMap.add(joinOp);
        }
      }

      // store the new joinContext
      pactx.setJoinOps(joinMap);
    }

    // Go over the list and find if a reducer is not needed
    List<AbstractMapJoinOperator<? extends MapJoinDesc>> listMapJoinOpsNoRed = new ArrayList<AbstractMapJoinOperator<? extends MapJoinDesc>>();

    // create a walker which walks the tree in a DFS manner while maintaining
    // the operator stack.
    // The dispatcher generates the plan from the operator tree
    Map<SemanticRule, SemanticNodeProcessor> opRules = new LinkedHashMap<SemanticRule, SemanticNodeProcessor>();
    opRules.put(new RuleRegExp("R0",
      MapJoinOperator.getOperatorName() + "%"),
      getCurrentMapJoin());
    opRules.put(new RuleRegExp("R1",
      MapJoinOperator.getOperatorName() + "%.*" + FileSinkOperator.getOperatorName() + "%"),
      getMapJoinFS());
    opRules.put(new RuleRegExp("R2",
      MapJoinOperator.getOperatorName() + "%.*" + ReduceSinkOperator.getOperatorName() + "%"),
      getMapJoinDefault());
    opRules.put(new RuleRegExp("R4",
      MapJoinOperator.getOperatorName() + "%.*" + UnionOperator.getOperatorName() + "%"),
      getMapJoinDefault());

    // The dispatcher fires the processor corresponding to the closest matching
    // rule and passes the context along
    SemanticDispatcher disp = new DefaultRuleDispatcher(getDefault(), opRules, new MapJoinWalkerCtx(
        listMapJoinOpsNoRed, pactx));

    SemanticGraphWalker ogw = new GenMapRedWalker(disp);
    ArrayList<Node> topNodes = new ArrayList<Node>();
    topNodes.addAll(listMapJoinOps);
    ogw.startWalking(topNodes, null);

    pactx.setListMapJoinOpsNoReducer(listMapJoinOpsNoRed);
    return pactx;
  }
Transform the query tree. For each join, check if it is a map-side join (user specified). If
yes, convert it to a map-side join.

@param pactx
         current parse context
ql/src/java/org/apache/hadoop/hive/ql/optimizer/MapJoinProcessor.java