private double computeScore(
      RelNode factRel,
      RelNode dimRel,
      LogicalJoin semiJoin) {
    // Estimate savings as a result of applying semijoin filter on fact
    // table.  As a heuristic, the selectivity of the semijoin needs to
    // be less than half.  There may be instances where an even smaller
    // selectivity value is required because of the overhead of
    // index lookups on a very large fact table.  Half was chosen as
    // a middle ground based on testing that was done with a large
    // data set.
    final ImmutableBitSet dimCols = ImmutableBitSet.of(semiJoin.analyzeCondition().rightKeys);
    final double selectivity =
        RelMdUtil.computeSemiJoinSelectivity(mq, factRel, dimRel, semiJoin);
    if (selectivity > .5) {
      return 0;
    }

    final RelOptCost factCost = mq.getCumulativeCost(factRel);

    // if not enough information, return a low score
    if (factCost == null) {
      return 0;
    }
    double savings =
        (1.0 - Math.sqrt(selectivity))
            * Math.max(1.0, factCost.getRows());

    // Additional savings if the dimension columns are unique.  We can
    // ignore nulls since they will be filtered out by the semijoin.
    boolean uniq =
        RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq,
            dimRel, dimCols);
    if (uniq) {
      savings *= 2.0;
    }

    // compute the cost of doing an extra scan on the dimension table,
    // including the distinct sort on top of the scan; if the dimension
    // columns are already unique, no need to add on the dup removal cost
    final Double dimSortCost = mq.getRowCount(dimRel);
    final Double dupRemCost = uniq ? 0 : dimSortCost;
    final RelOptCost dimCost = mq.getCumulativeCost(dimRel);
    if ((dimSortCost == null)
        || (dupRemCost == null)
        || (dimCost == null)) {
      return 0;
    }

    double dimRows = dimCost.getRows();
    if (dimRows < 1.0) {
      dimRows = 1.0;
    }
    return savings / dimRows;
  }
Computes a score relevant to applying a set of semijoins on a fact table.
The higher the score, the better.

@param factRel fact table being filtered
@param dimRel dimension table that participates in semijoin
@param semiJoin semijoin between fact and dimension tables

@return computed score of applying the dimension table filters on the
fact table
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveLoptSemiJoinOptimizer.java