private void runEvaluator(VectorPTFEvaluatorBase evaluator, Range range)
      throws HiveException {
    int batchStartIndex = findInMemoryBatchIndex(range.getStart());
    int batchEndIndex = findInMemoryBatchIndex(range.getEnd());

    for (int i = Math.max(0, batchStartIndex); i < Math.min(batchEndIndex + 1,
        bufferedBatches.size()); i++) {
      BufferedVectorizedRowBatch bufferedBatch = bufferedBatches.get(i);
      /*
       * Let's say we have a range: 12-15 and buffered batches like: [0, 1, 2, 3, 4, 5, 6] [7, 8, 9,
       * 10, 11, 12, 13] [14, 15, 16, 17, 18, 19, 20] [21, 22, 23, 24, 25, 26, 27]. We need to
       * create a truncated version of the batches in order to make the evaluator iterate on values
       * [12, 13] and then [14] (range end is exclusive). This way, evaluators will have no idea
       * that they work on a specific range, so the evaluator.evaluateGroupBatch(batch) call works
       * without any changes. Here is a tradeoff, because we might take care of truncated batches at
       * the start/end of ranges (minor performance change), but evaluator instances will remain as
       * simple as they are.
       */
      int currentBatchStartRow = inMemoryStartRowIndex.get(i);
      int currentBatchEndRow = inMemoryStartRowIndex.get(i) + bufferedBatch.size - 1;

      // e.g. in case of the last batch: 14 < 21
      if (range.getEnd() - 1 < currentBatchStartRow) {
        // break the loop, we've already passed the important batches
        break;
      }
      // e.g. in case of the first batch: 12 > 6
      if (range.getStart() > currentBatchEndRow) {
        // loop forward, we haven't reached the batch containing the first row yet
        continue;
      }
      // first important batch: 12 > 7 || 14 < 13
      // second important batch: 12 > 14 || 14 < 20
      if (range.getStart() > currentBatchStartRow || range.getEnd() - 1 < currentBatchEndRow) {
        /*
         * Create truncated batches:
         *
         * 1.
         * [12, 13] -> indices in current batch: 5 --> 6 ([7, 8, 9, 10, 11, 12, 13])
         * max(range.getStart(), currentBatchStartRow) - currentBatchStartRow
         * --> min(range.getEnd() - 1, currentBatchEndRow) - currentBatchStartRow
         * == max(12, 7) - 7 --> min(14, 13) - 7 == 5 --> 6
         *
         * 2.
         * [14] -> indices in current batch: 0 --> 0
         * max(range.getStart(), currentBatchStartRow) - currentBatchStartRow
         * --> min(range.getEnd() - 1, currentBatchEndRow) - currentBatchStartRow
         * == max(12, 14) - 14 --> min(14, 20) - 14 == 0 --> 0
         *
         * The value of currentBatchStartRow should be subtracted from every index as both
         * currentBatchStartRow/currentBatchStartRow and range values are "global" across the
         * blocks, so across the whole partition. After -currentBatchStartRow, the result index is a
         * proper index within the batch.
         */
        evaluator.evaluateGroupBatch(createTruncatedBufferedBatch(bufferedBatch,
            Math.max(range.getStart(), currentBatchStartRow) - currentBatchStartRow,
            Math.min(range.getEnd() - 1, currentBatchEndRow) - currentBatchStartRow));
      } else {
        evaluator.evaluateGroupBatch(bufferedBatch);
      }
    }
  }
Runs the evaluator on a specific range. The provided Ref<Object> is needed because some
evaluators (RANK, DENSE_RANK) are supposed to provide the result before handling the last batch
in a group (doLastBatchWork). For this purposes, a simple return value would not be sufficient.

@param evaluator
@param range
@param result
@throws HiveException
ql/src/java/org/apache/hadoop/hive/ql/exec/vector/ptf/VectorPTFGroupBatches.java