package mil.nga.giat.geowave.examples.query; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.minicluster.impl.MiniAccumuloClusterImpl; import org.apache.accumulo.minicluster.impl.MiniAccumuloConfigImpl; import org.apache.commons.io.FileUtils; import org.geotools.feature.AttributeTypeBuilder; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.referencing.operation.TransformException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.io.Files; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import mil.nga.giat.geowave.adapter.vector.FeatureDataAdapter; import mil.nga.giat.geowave.adapter.vector.plugin.GeoWaveGTDataStore; import mil.nga.giat.geowave.adapter.vector.utils.DateUtilities; import mil.nga.giat.geowave.core.geotime.GeometryUtils; import mil.nga.giat.geowave.core.geotime.ingest.SpatialTemporalDimensionalityTypeProvider; import mil.nga.giat.geowave.core.geotime.store.filter.SpatialQueryFilter.CompareOperation; import mil.nga.giat.geowave.core.geotime.store.query.SpatialTemporalQuery; import mil.nga.giat.geowave.core.geotime.store.query.TemporalConstraints; import mil.nga.giat.geowave.core.geotime.store.query.TemporalRange; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.IndexWriter; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.query.QueryOptions; import mil.nga.giat.geowave.core.store.util.DataStoreUtils; import mil.nga.giat.geowave.datastore.accumulo.AccumuloDataStore; import mil.nga.giat.geowave.datastore.accumulo.BasicAccumuloOperations; import mil.nga.giat.geowave.datastore.accumulo.minicluster.MiniAccumuloClusterFactory; /** * This class is intended to provide a self-contained, easy-to-follow example of * a few GeoTools queries against GeoWave using Spatial Temporal Data. * * For simplicity, a MiniAccumuloCluster is spun up and a few points from the DC * area are ingested (Washington Monument, White House, FedEx Field). Two * queries are executed against this data set. */ public class GeoTemporalQueryExample { private static final Logger LOGGER = LoggerFactory.getLogger(GeoTemporalQueryExample.class); private static File tempAccumuloDir; private static MiniAccumuloClusterImpl accumulo; private static AccumuloDataStore dataStore; private static final PrimaryIndex index = new SpatialTemporalDimensionalityTypeProvider().createPrimaryIndex(); private static final FeatureDataAdapter adapter = new FeatureDataAdapter( getPointSimpleFeatureType()); // Points (to be ingested into GeoWave Data Store) private static final Coordinate washingtonMonument = new Coordinate( -77.0352, 38.8895); private static final Coordinate whiteHouse = new Coordinate( -77.0366, 38.8977); private static final Coordinate fedexField = new Coordinate( -76.8644, 38.9078); public GeoTemporalQueryExample() {} public static void main( final String[] args ) throws AccumuloException, AccumuloSecurityException, InterruptedException, IOException, ParseException, TransformException { // spin up a MiniAccumuloCluster and initialize the DataStore setup(); new GeoTemporalQueryExample().run(); // stop MiniAccumuloCluster and delete temporary files cleanup(); } public void run() throws AccumuloException, AccumuloSecurityException, InterruptedException, IOException, ParseException, TransformException { // ingest 3 points represented as SimpleFeatures: Washington Monument, // White House, FedEx Field ingestCannedData(); // execute a query for a large polygon executePolygonAndTimeRangeQuery(); } private static void setup() throws AccumuloException, AccumuloSecurityException, IOException, InterruptedException { final String ACCUMULO_USER = "root"; final String ACCUMULO_PASSWORD = "Ge0wave"; final String TABLE_NAMESPACE = ""; tempAccumuloDir = Files.createTempDir(); accumulo = MiniAccumuloClusterFactory.newAccumuloCluster( new MiniAccumuloConfigImpl( tempAccumuloDir, ACCUMULO_PASSWORD), GeoTemporalQueryExample.class); accumulo.start(); dataStore = new AccumuloDataStore( new BasicAccumuloOperations( accumulo.getZooKeepers(), accumulo.getInstanceName(), ACCUMULO_USER, ACCUMULO_PASSWORD, TABLE_NAMESPACE)); } private void ingestCannedData() throws IOException { final List<SimpleFeature> points = new ArrayList<>(); System.out.println("Building SimpleFeatures from canned data set..."); try { points.add(buildSimpleFeature( "Washington Monument 1", washingtonMonument, DateUtilities.parseISO("2005-05-15T20:32:56Z"), DateUtilities.parseISO("2005-05-15T21:32:56Z"))); points.add(buildSimpleFeature( "Washington Monument 2", washingtonMonument, DateUtilities.parseISO("2005-05-17T20:32:56Z"), DateUtilities.parseISO("2005-05-17T21:32:56Z"))); points.add(buildSimpleFeature( "White House 1", whiteHouse, DateUtilities.parseISO("2005-05-17T20:32:56Z"), DateUtilities.parseISO("2005-05-17T21:32:56Z"))); points.add(buildSimpleFeature( "White House 2", whiteHouse, DateUtilities.parseISO("2005-05-17T19:32:56Z"), DateUtilities.parseISO("2005-05-17T20:45:56Z"))); points.add(buildSimpleFeature( "Fedex 1", fedexField, DateUtilities.parseISO("2005-05-17T20:32:56Z"), DateUtilities.parseISO("2005-05-17T21:32:56Z"))); points.add(buildSimpleFeature( "Fedex 2", fedexField, DateUtilities.parseISO("2005-05-18T19:32:56Z"), DateUtilities.parseISO("2005-05-18T20:45:56Z"))); points.add(buildSimpleFeature( "White House 3", whiteHouse, DateUtilities.parseISO("2005-05-19T19:32:56Z"), DateUtilities.parseISO("2005-05-19T20:45:56Z"))); } catch (final Exception ex) { LOGGER.warn( "Could not add points", ex); } System.out.println("Ingesting canned data..."); try (IndexWriter indexWriter = dataStore.createWriter( adapter, index)) { for (final SimpleFeature sf : points) { // indexWriter.write(sf); } } System.out.println("Ingest complete."); } private void executePolygonAndTimeRangeQuery() throws IOException, ParseException, TransformException { // Query equivalent to ECQL: // DWITHIN(geometry, POINT(-77.03521 38.8895), 13.7, kilometers) and // startTime after 2005-05-17T19:32:56Z and endTime before // 2005-05-17T22:32:56Z // // Notice the use of CompareOperations.CONTAINS. // By default, SpatialTemporalQuery and SpatialTemporalQuery use // CompareOperations.OVERLAPS // // To compose the polygon, this query creates a characteristic 'circle' // around center given a distance. // The method Geometry.buffer() works in degrees; a helper // method is available that uses metric units. The helper method // looses accuracy as the distance from the centroid grows and // the centroid moves closer the poles. final SpatialTemporalQuery query = new SpatialTemporalQuery( DateUtilities.parseISO("2005-05-17T19:32:56Z"), DateUtilities.parseISO("2005-05-17T22:32:56Z"), mil.nga.giat.geowave.adapter.vector.utils.GeometryUtils.buffer( GeoWaveGTDataStore.DEFAULT_CRS, GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate( -77.03521, 38.8895)), "meter", 13700).getKey(), CompareOperation.CONTAINS); System.out.println("Executing query, expecting to match three points..."); final CloseableIterator<SimpleFeature> iterator = dataStore.query( new QueryOptions(), query); while (iterator.hasNext()) { System.out.println("Query match: " + iterator.next().getID()); } iterator.close(); final TemporalConstraints tempotalIndexConstraints = new TemporalConstraints( Arrays.asList( new TemporalRange( DateUtilities.parseISO("2005-05-17T19:32:56Z"), DateUtilities.parseISO("2005-05-17T22:32:56Z")), new TemporalRange( DateUtilities.parseISO("2005-05-19T19:32:56Z"), DateUtilities.parseISO("2005-05-19T22:32:56Z"))), "ignored"); // the name is not used in this case final SpatialTemporalQuery query2 = new SpatialTemporalQuery( tempotalIndexConstraints, mil.nga.giat.geowave.adapter.vector.utils.GeometryUtils.buffer( GeoWaveGTDataStore.DEFAULT_CRS, GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate( -77.03521, 38.8895)), "meter", 13700).getKey(), CompareOperation.CONTAINS); System.out.println("Executing query # 2 with multiple time ranges, expecting to match four points..."); final CloseableIterator<SimpleFeature> iterator2 = dataStore.query( new QueryOptions( adapter, index), query2); while (iterator2.hasNext()) { System.out.println("Query match: " + iterator2.next().getID()); } iterator2.close(); } private static void cleanup() throws IOException, InterruptedException { try { accumulo.stop(); } finally { FileUtils.deleteDirectory(tempAccumuloDir); } } private static SimpleFeatureType getPointSimpleFeatureType() { final String NAME = "PointSimpleFeatureType"; final SimpleFeatureTypeBuilder sftBuilder = new SimpleFeatureTypeBuilder(); final AttributeTypeBuilder atBuilder = new AttributeTypeBuilder(); sftBuilder.setName(NAME); sftBuilder.add(atBuilder.binding( String.class).nillable( false).buildDescriptor( "locationName")); sftBuilder.add(atBuilder.binding( Geometry.class).nillable( false).buildDescriptor( "geometry")); sftBuilder.add(atBuilder.binding( Date.class).nillable( false).buildDescriptor( "startTime")); sftBuilder.add(atBuilder.binding( Date.class).nillable( false).buildDescriptor( "endTime")); return sftBuilder.buildFeatureType(); } private static SimpleFeature buildSimpleFeature( final String locationName, final Coordinate coordinate, final Date startTime, final Date endTime ) { final SimpleFeatureBuilder builder = new SimpleFeatureBuilder( getPointSimpleFeatureType()); builder.set( "locationName", locationName); builder.set( "geometry", GeometryUtils.GEOMETRY_FACTORY.createPoint(coordinate)); builder.set( "startTime", startTime); builder.set( "endTime", endTime); return builder.buildFeature(locationName); } }