private void removeSemijoinsParallelToMapJoin(OptimizeTezProcContext procCtx)
          throws SemanticException {
    if (!procCtx.conf.getBoolVar(ConfVars.HIVE_CONVERT_JOIN)) {
      // Not needed without mapjoin conversion
      return;
    }

    // Get all the TS ops.
    List<Operator<?>> topOps = new ArrayList<>();
    topOps.addAll(procCtx.parseContext.getTopOps().values());

    Map<ReduceSinkOperator, TableScanOperator> semijoins = new HashMap<>();
    Map<TableScanOperator, List<MapJoinOperator>> probeDecodeMJoins = new HashMap<>();
    for (Operator<?> parent : topOps) {
      // A TS can have multiple branches due to DPP Or Semijoin Opt.
      // USe DFS to traverse all the branches until RS is hit.
      Deque<Operator<?>> deque = new LinkedList<>();
      deque.add(parent);
      while (!deque.isEmpty()) {
        Operator<?> op = deque.pollLast();
        if (op instanceof ReduceSinkOperator) {
          // Done with this branch
          continue;
        }

        if (op instanceof MapJoinOperator) {
          // A candidate.
          if (!findParallelSemiJoinBranch(op, (TableScanOperator) parent,
                  procCtx.parseContext, semijoins, probeDecodeMJoins)) {
            // No parallel edge was found for the given mapjoin op,
            // no need to go down further, skip this TS operator pipeline.
            break;
          }
        }
        deque.addAll(op.getChildOperators());
      }
    }
    //  No need to remove SJ branches when we have semi-join reduction or when semijoins are enabled for parallel mapjoins.
    if (!procCtx.conf.getBoolVar(ConfVars.TEZ_DYNAMIC_SEMIJOIN_REDUCTION_FOR_MAPJOIN)) {
      if (semijoins.size() > 0) {
        for (Entry<ReduceSinkOperator, TableScanOperator> semiEntry : semijoins.entrySet()) {
          if (LOG.isDebugEnabled()) {
            LOG.debug("Semijoin optimization with parallel edge to map join. Removing semijoin " +
                OperatorUtils.getOpNamePretty(semiEntry.getKey()) + " - " + OperatorUtils.getOpNamePretty(semiEntry.getValue()));
          }
          GenTezUtils.removeBranch(semiEntry.getKey());
          GenTezUtils.removeSemiJoinOperator(procCtx.parseContext, semiEntry.getKey(), semiEntry.getValue());
        }
      }
    }
    if (LlapHiveUtils.isLlapMode(procCtx.conf) && procCtx.conf.getBoolVar(ConfVars.HIVE_OPTIMIZE_SCAN_PROBEDECODE)) {
      if (probeDecodeMJoins.size() > 0) {
        // When multiple MJ, select one based on a policy
        for (Map.Entry<TableScanOperator, List<MapJoinOperator>> probeTsMap : probeDecodeMJoins.entrySet()){
          TableScanOperator.ProbeDecodeContext tsCntx = null;
          // Currently supporting: LowestRatio policy
          // TODO: Add more policies and make the selection a conf property
          tsCntx = selectLowestRatioProbeDecodeMapJoin(probeTsMap.getKey(), probeTsMap.getValue());
          if (tsCntx != null) {
            LOG.debug("ProbeDecode MJ for TS {}  with CacheKey {} MJ Pos {} ColName {} with Ratio {}",
                    probeTsMap.getKey().getName(), tsCntx.getMjSmallTableCacheKey(), tsCntx.getMjSmallTablePos(),
                    tsCntx.getMjBigTableKeyColName(), tsCntx.getKeyRatio());
            probeTsMap.getKey().setProbeDecodeContext(tsCntx);
            probeTsMap.getKey().getConf().setProbeDecodeContext(tsCntx);
          }
        }
      }
    }
  }
TezCompiler translates the operator plan into TezTasks.
ql/src/java/org/apache/hadoop/hive/ql/parse/TezCompiler.java