package mil.nga.giat.geowave.analytic.mapreduce.kde; import java.io.IOException; import java.util.HashMap; import java.util.Map; import mil.nga.giat.geowave.mapreduce.input.GeoWaveInputKey; import org.apache.hadoop.io.DoubleWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.mapreduce.Mapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.geotools.filter.text.cql2.CQL; import org.geotools.filter.text.cql2.CQLException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.Filter; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; public class GaussianCellMapper extends Mapper<GeoWaveInputKey, SimpleFeature, LongWritable, DoubleWritable> { private final static Logger LOGGER = LoggerFactory.getLogger(GaussianCellMapper.class); protected static final String CQL_FILTER_KEY = "CQL_FILTER"; protected int minLevel; protected int maxLevel; protected Filter filter; protected Map<Integer, LevelStore> levelStoreMap; @Override protected void setup( final Context context ) throws IOException, InterruptedException { super.setup(context); minLevel = context.getConfiguration().getInt( KDEJobRunner.MIN_LEVEL_KEY, 1); maxLevel = context.getConfiguration().getInt( KDEJobRunner.MAX_LEVEL_KEY, 25); final String cql = context.getConfiguration().get( CQL_FILTER_KEY); if ((cql != null) && !cql.isEmpty()) { try { filter = CQL.toFilter(cql); } catch (final CQLException e) { LOGGER.warn( "Unable to parse CQL filter", e); } } levelStoreMap = new HashMap<Integer, LevelStore>(); for (int level = maxLevel; level >= minLevel; level--) { final int numXPosts = (int) Math.pow( 2, level + 1) * KDEJobRunner.TILE_SIZE; final int numYPosts = (int) Math.pow( 2, level) * KDEJobRunner.TILE_SIZE; populateLevelStore( context, numXPosts, numYPosts, level); } } protected void populateLevelStore( final Context context, final int numXPosts, final int numYPosts, final int level ) { levelStoreMap.put( level, new LevelStore( numXPosts, numYPosts, new MapContextCellCounter( context, level, minLevel, maxLevel))); } @Override protected void map( final GeoWaveInputKey key, final SimpleFeature value, final Context context ) throws IOException, InterruptedException { Point pt = null; if (value != null) { if ((filter != null) && !filter.evaluate(value)) { return; } final Object geomObj = value.getDefaultGeometry(); if ((geomObj != null) && (geomObj instanceof Geometry)) { pt = ((Geometry) geomObj).getCentroid(); } } if ((pt == null) || pt.isEmpty()) { return; } for (int level = maxLevel; level >= minLevel; level--) { incrementLevelStore( level, pt, value); } } protected void incrementLevelStore( final int level, final Point pt, final SimpleFeature feature ) { final LevelStore levelStore = levelStoreMap.get(level); GaussianFilter.incrementPt( pt.getY(), pt.getX(), levelStore.counter, levelStore.numXPosts, levelStore.numYPosts); } public static class LevelStore { public final int numXPosts; public final int numYPosts; public final CellCounter counter; public LevelStore( final int numXPosts, final int numYPosts, final CellCounter counter ) { this.numXPosts = numXPosts; this.numYPosts = numYPosts; this.counter = counter; } } }