public static void setupBucketMapJoinInfo(MapWork plan,
        AbstractMapJoinOperator<? extends MapJoinDesc> currMapJoinOp) {
      if (currMapJoinOp != null) {
        Map<String, Map<String, List<String>>> aliasBucketFileNameMapping =
            currMapJoinOp.getConf().getAliasBucketFileNameMapping();
        if (aliasBucketFileNameMapping != null) {
          MapredLocalWork localPlan = plan.getMapRedLocalWork();
          if (localPlan == null) {
            if (currMapJoinOp instanceof SMBMapJoinOperator) {
              localPlan = ((SMBMapJoinOperator) currMapJoinOp).getConf().getLocalWork();
            }
          } else {
            // local plan is not null, we want to merge it into SMBMapJoinOperator's local work
            if (currMapJoinOp instanceof SMBMapJoinOperator) {
              MapredLocalWork smbLocalWork = ((SMBMapJoinOperator) currMapJoinOp).getConf()
                  .getLocalWork();
              if (smbLocalWork != null) {
                localPlan.getAliasToFetchWork().putAll(smbLocalWork.getAliasToFetchWork());
                localPlan.getAliasToWork().putAll(smbLocalWork.getAliasToWork());
              }
            }
          }

          if (localPlan == null) {
            return;
          }

          if (currMapJoinOp instanceof SMBMapJoinOperator) {
            plan.setMapRedLocalWork(null);
            ((SMBMapJoinOperator) currMapJoinOp).getConf().setLocalWork(localPlan);
          } else {
            plan.setMapRedLocalWork(localPlan);
          }
          BucketMapJoinContext bucketMJCxt = new BucketMapJoinContext();
          localPlan.setBucketMapjoinContext(bucketMJCxt);
          bucketMJCxt.setAliasBucketFileNameMapping(aliasBucketFileNameMapping);
          bucketMJCxt.setBucketFileNameMapping(
              currMapJoinOp.getConf().getBigTableBucketNumMapping());
          localPlan.setInputFileChangeSensitive(true);
          bucketMJCxt.setMapJoinBigTableAlias(currMapJoinOp.getConf().getBigTableAlias());
          bucketMJCxt
              .setBucketMatcherClass(org.apache.hadoop.hive.ql.exec.DefaultBucketMatcher.class);
          bucketMJCxt.setBigTablePartSpecToFileMapping(
              currMapJoinOp.getConf().getBigTablePartSpecToFileMapping());
          // BucketizedHiveInputFormat should be used for either sort merge join or bucket map join
          if ((currMapJoinOp instanceof SMBMapJoinOperator)
              || (currMapJoinOp.getConf().isBucketMapJoin())) {
            plan.setUseBucketizedHiveInputFormat(true);
          }
        }
      }
    }
MapJoin processor.
The user can specify a mapjoin hint to specify that the input should be processed as a
mapjoin instead of map-reduce join. If hive.auto.convert.join is set to true, the
user need not specify the hint explicitly, but hive will automatically process the joins
as a mapjoin whenever possible. However, a join can only be processed as a bucketized
map-side join or a sort merge join, if the user has provided the hint explicitly. This
will be fixed as part of HIVE-3433, and eventually, we should remove support for mapjoin
hint.
However, currently, the mapjoin hint is processed as follows:
A mapjoin will have 'n' parents for a n-way mapjoin, and therefore the mapjoin operator
will be encountered 'n' times (one for each parent). Since a reduceSink operator is not
allowed before a mapjoin, the task for the mapjoin will always be a root task. The task
corresponding to the mapjoin is converted to a root task when the operator is encountered
for the first time. When the operator is encountered subsequently, the current task is
merged with the root task for the mapjoin. Note that, it is possible that the map-join task
may be performed as a bucketized map-side join (or sort-merge join), the map join operator
is enhanced to contain the bucketing info. when it is encountered.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/MapJoinFactory.java