@Override
 public float getProgress() throws IOException {
   if ((numKeysRead > 0) && (currentAccumuloKey == null)) {
     return 1.0f;
   }
   if (currentGeoWaveRangeIndexPair == null) {
     return 0.0f;
   }
   final ProgressPerRange progress = progressPerRange.get(currentGeoWaveRangeIndexPair);
   if (progress == null) {
     return getProgressForRange(currentGeoWaveRangeIndexPair.getRange(), currentAccumuloKey);
   }
   return getOverallProgress(
       currentGeoWaveRangeIndexPair.getRange(), currentAccumuloKey, progress);
 }
  /** Initialize a scanner over the given input split using this task attempt configuration. */
  @Override
  public void initialize(final InputSplit inSplit, final TaskAttemptContext attempt)
      throws IOException {
    split = (GeoWaveAccumuloInputSplit) inSplit;

    numKeysRead = 0;

    final Map<RangeLocationPair, CloseableIterator<?>> iteratorsPerRange =
        new LinkedHashMap<RangeLocationPair, CloseableIterator<?>>();

    final Set<PrimaryIndex> indices = split.getIndices();
    BigDecimal sum = BigDecimal.ZERO;

    final Map<RangeLocationPair, BigDecimal> incrementalRangeSums =
        new LinkedHashMap<RangeLocationPair, BigDecimal>();

    for (final PrimaryIndex i : indices) {
      final List<RangeLocationPair> ranges = split.getRanges(i);
      List<QueryFilter> queryFilters = null;
      if (query != null) {
        queryFilters = query.createFilters(i.getIndexModel());
      }
      for (final RangeLocationPair r : ranges) {
        final QueryOptions rangeQueryOptions = new QueryOptions(queryOptions);
        rangeQueryOptions.setIndex(i);
        iteratorsPerRange.put(
            r,
            new InputFormatAccumuloRangeQuery(
                    adapterStore,
                    i,
                    r.getRange(),
                    queryFilters,
                    isOutputWritable,
                    rangeQueryOptions)
                .query(
                    accumuloOperations,
                    adapterStore,
                    rangeQueryOptions.getMaxResolutionSubsamplingPerDimension(),
                    rangeQueryOptions.getLimit()));
        incrementalRangeSums.put(r, sum);
        sum = sum.add(BigDecimal.valueOf(r.getCardinality()));
      }
    }

    // finally we can compute percent progress
    progressPerRange = new LinkedHashMap<RangeLocationPair, ProgressPerRange>();
    RangeLocationPair prevRangeIndex = null;
    float prevProgress = 0f;
    for (final Entry<RangeLocationPair, BigDecimal> entry : incrementalRangeSums.entrySet()) {
      final BigDecimal value = entry.getValue();
      final float progress = value.divide(sum, RoundingMode.HALF_UP).floatValue();
      if (prevRangeIndex != null) {
        progressPerRange.put(prevRangeIndex, new ProgressPerRange(prevProgress, progress));
      }
      prevRangeIndex = entry.getKey();
      prevProgress = progress;
    }
    progressPerRange.put(prevRangeIndex, new ProgressPerRange(prevProgress, 1f));
    // concatenate iterators
    iterator =
        new CloseableIteratorWrapper<Object>(
            new Closeable() {
              @Override
              public void close() throws IOException {
                for (final CloseableIterator<?> it : iteratorsPerRange.values()) {
                  it.close();
                }
              }
            },
            concatenateWithCallback(
                iteratorsPerRange.entrySet().iterator(),
                new NextRangeCallback() {

                  @Override
                  public void setRange(final RangeLocationPair indexPair) {
                    currentGeoWaveRangeIndexPair = indexPair;
                  }
                }));
  }