private static TableScanOperator.ProbeDecodeContext selectLowestRatioProbeDecodeMapJoin(TableScanOperator tsOp,
      List<MapJoinOperator> mjOps) throws SemanticException {
    MapJoinOperator selectedMJOp = null;
    double selectedMJOpRatio = 0;
    for (MapJoinOperator currMJOp : mjOps) {
      if (!isValidProbeDecodeMapJoin(currMJOp)) {
        continue;
      }
      // At this point we know it is a single Key MapJoin
      if (selectedMJOp == null) {
        // Set the first valid MJ
        selectedMJOp = currMJOp;
        selectedMJOpRatio = getProbeDecodeNDVRatio(tsOp, currMJOp);
        LOG.debug("ProbeDecode MJ {} with Ratio {}", selectedMJOp, selectedMJOpRatio);
      } else {
        double currMJRatio = getProbeDecodeNDVRatio(tsOp, currMJOp);
        if (currMJRatio < selectedMJOpRatio){
          LOG.debug("ProbeDecode MJ {} Ratio {} is lower than existing MJ {} with Ratio {}",
              currMJOp, currMJRatio, selectedMJOp, selectedMJOpRatio);
          selectedMJOp = currMJOp;
          selectedMJOpRatio = currMJRatio;
        }
      }
    }

    TableScanOperator.ProbeDecodeContext tsProbeDecodeCtx = null;
    // If there a valid MJ to be used for TS probeDecode make sure the MJ cache key is generated and
    // then propagate the new ProbeDecodeContext (to be used by LLap IO when executing the TSop)
    if (selectedMJOp != null) {
      String mjCacheKey = selectedMJOp.getConf().getCacheKey();
      if (mjCacheKey == null) {
        // Generate cache key if it has not been yet generated
        mjCacheKey = MapJoinDesc.generateCacheKey(selectedMJOp.getOperatorId());
        // Set in the conf of the map join operator
        selectedMJOp.getConf().setCacheKey(mjCacheKey);
      }

      byte posBigTable = (byte) selectedMJOp.getConf().getPosBigTable();
      Byte[] order = selectedMJOp.getConf().getTagOrder();
      Byte mjSmallTablePos = (order[0] == posBigTable ? order[1] : order[0]);

      List<ExprNodeDesc> keyDesc = selectedMJOp.getConf().getKeys().get(posBigTable);
      ExprNodeColumnDesc keyCol = (ExprNodeColumnDesc) keyDesc.get(0);
      ExprNodeColumnDesc originTSColExpr = OperatorUtils.findTableOriginColExpr(keyCol, selectedMJOp, tsOp);
      if (originTSColExpr == null) {
        LOG.warn("ProbeDecode could not find origTSCol for mjCol: {} with MJ Schema: {}",
            keyCol, selectedMJOp.getSchema());
      } else if (!TypeInfoUtils.doPrimitiveCategoriesMatch(keyCol.getTypeInfo(), originTSColExpr.getTypeInfo())) {
        // src Col -> HT key Col needs explicit or implicit (Casting) conversion
        // as a result we cannot perform direct lookups on the HT
        LOG.warn("ProbeDecode origTSCol {} type missmatch mjCol {}", originTSColExpr, keyCol);
      } else {
        tsProbeDecodeCtx = new TableScanOperator.ProbeDecodeContext(mjCacheKey, mjSmallTablePos,
            originTSColExpr.getColumn(), selectedMJOpRatio);
      }
    }
    return tsProbeDecodeCtx;
  }
TezCompiler translates the operator plan into TezTasks.
ql/src/java/org/apache/hadoop/hive/ql/parse/TezCompiler.java