private static GroupByOperator createGroupBy(SelectOperator selectOp, Operator<?> parentOp, GroupByDesc.Mode gbMode,
      long bloomEntriesHint, HiveConf hiveConf) {

    final List<ExprNodeDesc> params;
    final GenericUDAFEvaluator.Mode udafMode = SemanticAnalyzer.groupByDescModeToUDAFMode(gbMode, false);
    switch (gbMode) {
    case FINAL:
      params = createGroupByAggregationParameters((ReduceSinkOperator) parentOp);
      break;
    case HASH:
      params = createGroupByAggregationParameters(selectOp);
      break;
    default:
      throw new AssertionError(gbMode.toString() + " is not supported");
    }

    List<AggregationDesc> gbAggs = new ArrayList<>();
    Deque<ExprNodeDesc> paramsCopy = new ArrayDeque<>(params);
    while (paramsCopy.size() > 1) {
      gbAggs.add(minAggregation(udafMode, paramsCopy.poll()));
      gbAggs.add(maxAggregation(udafMode, paramsCopy.poll()));
    }
    gbAggs.add(bloomFilterAggregation(udafMode, paramsCopy.poll(), selectOp, bloomEntriesHint, hiveConf));
    assert paramsCopy.size() == 0;

    List<String> gbOutputNames = new ArrayList<>(gbAggs.size());
    List<ColumnInfo> gbColInfos = new ArrayList<>(gbAggs.size());
    for (int i = 0; i < params.size(); i++) {
      String colName = HiveConf.getColumnInternalName(i);
      gbOutputNames.add(colName);
      final TypeInfo colType;
      if (i == params.size() - 1) {
        colType = TypeInfoFactory.binaryTypeInfo; // Bloom type
      } else {
        colType = params.get(i).getTypeInfo(); // Min/Max type
      }
      gbColInfos.add(new ColumnInfo(colName, colType, "", false));
    }

    float groupByMemoryUsage = HiveConf.getFloatVar(hiveConf, HiveConf.ConfVars.HIVE_MAP_AGGR_HASH_MEMORY);
    float memoryThreshold = HiveConf.getFloatVar(hiveConf, HiveConf.ConfVars.HIVE_MAP_AGGR_MEMORY_THRESHOLD);
    float minReductionHashAggr = HiveConf.getFloatVar(hiveConf, HiveConf.ConfVars.HIVE_MAP_AGGR_HASH_MIN_REDUCTION);
    float minReductionHashAggrLowerBound = HiveConf.getFloatVar(hiveConf, HiveConf.ConfVars.HIVE_MAP_AGGR_HASH_MIN_REDUCTION_LOWER_BOUND);
    float hashAggrFlushPercent = HiveConf.getFloatVar(hiveConf, HiveConf.ConfVars.HIVE_MAP_AGGR_HASH_FLUSH_SIZE_PERCENT);
    GroupByDesc groupBy =
        new GroupByDesc(gbMode, gbOutputNames, Collections.emptyList(), gbAggs, false, groupByMemoryUsage,
            memoryThreshold, minReductionHashAggr, minReductionHashAggrLowerBound, hashAggrFlushPercent, null, false, -1, false);
    groupBy.setColumnExprMap(Collections.emptyMap());
    return (GroupByOperator) OperatorFactory.getAndMakeChild(groupBy, new RowSchema(gbColInfos), parentOp);
  }
Creates a group by operator with min, max, and bloomFilter aggregations for every column of the parent.
<p>
The method generates two kind of group by operators for intermediate and final aggregations respectively.
Intermediate aggregations require the parent operator to be a select operator while final aggregations assume that
the parent is a reduce sink operator.
</p>
<p>
Intermediate group by example.
<pre>
Input: SEL[fname, lname, age, hash(fname,lname,age)]
Output: GBY[min(fname),max(fname),min(lname),max(lname),min(age),max(age),bloom(hash)]
</pre>
</p>
<p>
Final group by example.
<pre>
Input: RS[fname_min,fname_max,lname_min,lname_max,age_min,age_max, hash_bloom]
Output: GBY[min(fname_min),max(fname_max),min(lname_min),max(lname_max),min(age_min),max(age_max),bloom(hash_bloom)]
</pre>
</p>
ql/src/java/org/apache/hadoop/hive/ql/optimizer/SemiJoinReductionMerge.java