private void initBufferedColumns() {
    /*
     * If we have more than one group key batch, we will buffer their contents.
     * We don't buffer the partitioning column since it's a constant for the whole partition.
     * We buffer:
     * 1. order columns
     * 2. the non-key input columns
     * 3. any streaming columns that will already have their output values
     * 4. scratch columns (as they're used by input expressions of evaluators)
     */
    int bufferedColumnCount = orderColumnMap.length + nonKeyInputColumnMap.length
        + streamingEvaluatorNums.length + scratchColumnPositions.length;
    this.bufferedColumnMap = new int[bufferedColumnCount];
    this.bufferedTypeInfos = new TypeInfo[bufferedColumnCount];

    int orderColumnCount = orderColumnMap.length;
    int nonKeyInputColumnCount = nonKeyInputColumnMap.length;
    int streamingEvaluatorCount = streamingEvaluatorNums.length;
    /*
     * In scenario 4. order column is not in keyInputColumnMap and is not referred in
     * reducerBatchTypeInfos, so we need to figure the TypeInfo out in an alternative way
     * (columnVectorTypeToTypeInfo). This is a workaround, maybe a compile-time solution would be
     * better.
     */
    for (int i = 0; i < orderColumnMap.length; i++) {
      final int columnNum = orderColumnMap[i];
      bufferedColumnMap[i] = columnNum;
      bufferedTypeInfos[i] = reducerBatchTypeInfos.length <= columnNum
        ? columnVectorTypeToTypeInfo(orderColumnVectorTypes[i]) : reducerBatchTypeInfos[columnNum];
    }

    for (int i = 0; i < nonKeyInputColumnMap.length; i++) {
      final int columnNum = nonKeyInputColumnMap[i];
      // ensure offsets in buffered map: [[order cols] [non-key input cols]]
      final int bufferedMapIndex = orderColumnCount + i;
      bufferedColumnMap[bufferedMapIndex] = columnNum;
      bufferedTypeInfos[bufferedMapIndex] = reducerBatchTypeInfos[columnNum];
    }

    for (int i = 0; i < streamingEvaluatorCount; i++) {
      final int streamingEvaluatorNum = streamingEvaluatorNums[i];
      // ensure offsets in buffered map: [[order cols] [non-key input cols] [streaming cols]]
      final int bufferedMapIndex = orderColumnCount + nonKeyInputColumnCount + i;
      bufferedColumnMap[bufferedMapIndex] = outputProjectionColumnMap[streamingEvaluatorNum];
      bufferedTypeInfos[bufferedMapIndex] = outputTypeInfos[streamingEvaluatorNum];
    }

    for (int i = 0; i < scratchColumnPositions.length; i++) {
      final int bufferedMapIndex = orderColumnCount + nonKeyInputColumnCount + streamingEvaluatorCount + i;
      bufferedColumnMap[bufferedMapIndex] = scratchColumnPositions[i];
      bufferedTypeInfos[bufferedMapIndex] = TypeInfoUtils.getTypeInfoFromTypeString(vOutContext.getScratchColumnTypeNames()[i]);
    }
  }
We are processing a batch from reduce processor that is only for one reducer key or PTF group.

For a simple OVER (PARTITION BY column) or OVER (ORDER BY column), the reduce processor's
group key is the partition or order by key.

For an OVER (PARTITION BY column1, ORDER BY column2), the reduce-shuffle group key is
the combination of the partition column1 and the order by column2.  In this case, this method
has to watch for changes in the partition and reset the group aggregations.

The reduce processor calls setNextVectorBatchGroupStatus beforehand to tell us whether the
batch supplied to our process method is the last batch for the group key, or not.  This helps
us intelligently process the batch.
ql/src/java/org/apache/hadoop/hive/ql/exec/vector/ptf/VectorPTFOperator.java