private boolean checkConvertJoinBucketMapJoin(JoinOperator joinOp,
      int bigTablePosition, TezBucketJoinProcCtx tezBucketJoinProcCtx) {
    // bail on mux-operator because mux operator masks the emit keys of the
    // constituent reduce sinks
    if (!(joinOp.getParentOperators().get(0) instanceof ReduceSinkOperator)) {
      LOG.info("Operator is " + joinOp.getParentOperators().get(0).getName() +
          ". Cannot convert to bucket map join");
      return false;
    }

    ReduceSinkOperator rs = (ReduceSinkOperator) joinOp.getParentOperators().get(bigTablePosition);
    List<List<String>> parentColNames = rs.getOpTraits().getBucketColNames();
    Operator<? extends OperatorDesc> parentOfParent = rs.getParentOperators().get(0);
    List<List<String>> grandParentColNames = parentOfParent.getOpTraits().getBucketColNames();
    Preconditions.checkState(rs.getOpTraits().getCustomBucketFunctions() == null
        || rs.getOpTraits().getCustomBucketFunctions().size() == 1);
    final boolean hasCustomBucketFunction = rs.getOpTraits().hasCustomBucketFunction();
    if (!checkColEquality(grandParentColNames, parentColNames, rs.getColumnExprMap(), !hasCustomBucketFunction)) {
      LOG.info("No info available to check for bucket map join. Cannot convert");
      return false;
    }

    boolean shouldCheckExternalTables = tezBucketJoinProcCtx.getConf()
        .getBoolVar(HiveConf.ConfVars.HIVE_DISABLE_UNSAFE_EXTERNALTABLE_OPERATIONS);
    if (shouldCheckExternalTables) {
      StringBuilder sb = new StringBuilder();
      for (Operator<?> parentOp : joinOp.getParentOperators()) {
        if (!canTableUseStats(parentOp, sb)) {
          LOG.debug("External table {} found in join and also could not provide statistics - " +
              "disabling bucket map join.", sb);
          return false;
        }
      }
    }

    /*
     * this is the case when the big table is a sub-query and is probably already bucketed by the
     * join column in say a group by operation
     */
    final CustomBucketFunction parentBucketFunction = rs.getOpTraits().getCustomBucketFunctions().get(0);
    int numBuckets = parentBucketFunction != null ? parentBucketFunction.getNumBuckets()
        : parentOfParent.getOpTraits().getNumBuckets();
    if (numBuckets < 0) {
      numBuckets = rs.getConf().getNumReducers();
    }
    tezBucketJoinProcCtx.setNumBuckets(numBuckets);
    return true;
  }
Preserves additional information about the operator.

When an operator is replaced by a new one; some of the information of the old have to be retained.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/ConvertJoinMapJoin.java