public void makePossibleSemiJoins(HiveLoptMultiJoin multiJoin) {
    possibleSemiJoins.clear();

    // semijoins can't be used with any type of outer join, including full
    if (multiJoin.getMultiJoinRel().isFullOuterJoin()) {
      return;
    }

    int nJoinFactors = multiJoin.getNumJoinFactors();
    for (int factIdx = 0; factIdx < nJoinFactors; factIdx++) {
      final Map<Integer, List<RexNode>> dimFilters = new HashMap<>();
      final Map<Integer, LogicalJoin> semiJoinMap = new HashMap<>();

      // loop over all filters and find equality filters that reference
      // this factor and one other factor
      for (RexNode joinFilter : multiJoin.getJoinFilters()) {
        int dimIdx = isSuitableFilter(multiJoin, joinFilter, factIdx);
        if (dimIdx == -1) {
          continue;
        }

        // if either the fact or dimension table is null generating,
        // we cannot use semijoins
        if (multiJoin.isNullGenerating(factIdx)
            || multiJoin.isNullGenerating(dimIdx)) {
          continue;
        }

        // if we've already matched against this dimension factor,
        // then add the filter to the list associated with
        // that dimension factor; otherwise, create a new entry
        List<RexNode> currDimFilters = dimFilters.get(dimIdx);
        if (currDimFilters == null) {
          currDimFilters = new ArrayList<>();
        }
        currDimFilters.add(joinFilter);
        dimFilters.put(dimIdx, currDimFilters);
      }

      // if there are potential dimension filters, determine if there
      // are appropriate indexes
      Set<Integer> dimIdxes = dimFilters.keySet();
      for (Integer dimIdx : dimIdxes) {
        List<RexNode> joinFilters = dimFilters.get(dimIdx);
        if (joinFilters != null) {
          LogicalJoin semiJoin =
              findSemiJoinIndexByCost(
                  multiJoin,
                  joinFilters,
                  factIdx,
                  dimIdx);

          // if an index is available, keep track of it as a
          // possible semijoin
          if (semiJoin != null) {
            semiJoinMap.put(dimIdx, semiJoin);
            possibleSemiJoins.put(factIdx, semiJoinMap);
          }
        }
      }
    }
  }
Determines all possible semijoins that can be used by dimension tables to
filter fact tables. Constructs SemiJoinRels corresponding to potential
dimension table filters and stores them in the member field
"possibleSemiJoins"

@param multiJoin join factors being optimized
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveLoptSemiJoinOptimizer.java