@Override
  @SuppressWarnings("unchecked")
  public int run(final Configuration configuration, final PropertyManagement propertyManagement)
      throws Exception {

    propertyManagement.store(CentroidParameters.Centroid.ZOOM_LEVEL, currentZoomLevel);

    propertyManagement.storeIfEmpty(GlobalParameters.Global.BATCH_ID, UUID.randomUUID().toString());

    propertyManagement.storeIfEmpty(
        CentroidParameters.Centroid.WRAPPER_FACTORY_CLASS, SimpleFeatureItemWrapperFactory.class);
    propertyManagement.storeIfEmpty(
        CommonParameters.Common.DISTANCE_FUNCTION_CLASS, FeatureCentroidDistanceFn.class);
    propertyManagement.storeIfEmpty(
        CentroidParameters.Centroid.EXTRACTOR_CLASS, SimpleFeatureCentroidExtractor.class);
    propertyManagement.storeIfEmpty(
        CommonParameters.Common.DIMENSION_EXTRACT_CLASS, SimpleFeatureGeometryExtractor.class);

    propertyManagement.copy(
        CentroidParameters.Centroid.DATA_TYPE_ID, SampleParameters.Sample.DATA_TYPE_ID);

    propertyManagement.copy(CentroidParameters.Centroid.INDEX_ID, SampleParameters.Sample.INDEX_ID);

    ClusteringUtils.createAdapter(propertyManagement);
    ClusteringUtils.createIndex(propertyManagement);

    final String currentBatchId =
        propertyManagement.getPropertyAsString(
            GlobalParameters.Global.BATCH_ID, UUID.randomUUID().toString());

    try {

      final NumericRange rangeOfIterations =
          propertyManagement.getPropertyAsRange(
              JumpParameters.Jump.RANGE_OF_CENTROIDS, new NumericRange(2, 200));
      propertyManagement.store(GlobalParameters.Global.PARENT_BATCH_ID, currentBatchId);

      final GenericStoreCommandLineOptions<DataStore> dataStoreOptions =
          ((PersistableDataStore) propertyManagement.getProperty(StoreParam.DATA_STORE))
              .getCliOptions();
      final GenericStoreCommandLineOptions<IndexStore> indexStoreOptions =
          ((PersistableIndexStore) propertyManagement.getProperty(StoreParam.INDEX_STORE))
              .getCliOptions();
      final GenericStoreCommandLineOptions<AdapterStore> adapterStoreOptions =
          ((PersistableAdapterStore) propertyManagement.getProperty(StoreParam.ADAPTER_STORE))
              .getCliOptions();

      final DistortionGroupManagement distortionGroupManagement =
          new DistortionGroupManagement(
              dataStoreOptions.createStore(),
              indexStoreOptions.createStore(),
              adapterStoreOptions.createStore());

      for (int k = (int) Math.max(2, Math.round(rangeOfIterations.getMin()));
          k < Math.round(rangeOfIterations.getMax());
          k++) {

        // regardless of the algorithm, the sample set is fixed in size
        propertyManagement.store(SampleParameters.Sample.MIN_SAMPLE_SIZE, k);
        propertyManagement.store(SampleParameters.Sample.MAX_SAMPLE_SIZE, k);
        propertyManagement.store(SampleParameters.Sample.SAMPLE_SIZE, k);

        jumpRunner.setCentroidsCount(k);
        jumpRunner.setDataStoreOptions(dataStoreOptions);
        final String iterationBatchId = currentBatchId + "_" + k;
        propertyManagement.store(GlobalParameters.Global.BATCH_ID, iterationBatchId);
        jumpRunner.setReducerCount(k);
        LOGGER.info("KMeans for k: " + k + " and batch " + currentBatchId);
        final int status = super.run(configuration, propertyManagement);
        if (status != 0) {
          return status;
        }
      }
      propertyManagement.store(GlobalParameters.Global.BATCH_ID, currentBatchId);

      @SuppressWarnings("rawtypes")
      final Class<AnalyticItemWrapperFactory> analyticItemWrapperFC =
          propertyManagement.getPropertyAsClass(
              CentroidParameters.Centroid.WRAPPER_FACTORY_CLASS, AnalyticItemWrapperFactory.class);

      /**
       * Associate the batch id with the best set of groups so the caller can find the clusters for
       * the given batch
       */
      final int result =
          distortionGroupManagement.retainBestGroups(
              (AnalyticItemWrapperFactory<SimpleFeature>) analyticItemWrapperFC.newInstance(),
              propertyManagement.getPropertyAsString(CentroidParameters.Centroid.DATA_TYPE_ID),
              propertyManagement.getPropertyAsString(CentroidParameters.Centroid.INDEX_ID),
              currentBatchId,
              currentZoomLevel);

      // distortionGroupManagement.cleanUp();

      return result;
    } catch (final Exception ex) {
      LOGGER.error("Cannot create distortions", ex);
      return 1;
    }
  }