package mil.nga.giat.geowave.examples.query; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; 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 com.google.common.io.Files; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Polygon; import mil.nga.giat.geowave.adapter.vector.FeatureDataAdapter; import mil.nga.giat.geowave.core.geotime.GeometryUtils; import mil.nga.giat.geowave.core.geotime.ingest.SpatialDimensionalityTypeProvider; import mil.nga.giat.geowave.core.geotime.store.query.SpatialQuery; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.DataStore; 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. 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 GeotoolsQueryExample { private static File tempAccumuloDir; private static MiniAccumuloClusterImpl accumulo; private static DataStore dataStore; private static final PrimaryIndex index = new SpatialDimensionalityTypeProvider().createPrimaryIndex(); // 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); // cities used to construct Geometries for queries private static final Coordinate baltimore = new Coordinate( -76.6167, 39.2833); private static final Coordinate richmond = new Coordinate( -77.4667, 37.5333); private static final Coordinate harrisonburg = new Coordinate( -78.8689, 38.4496); private static final Map<String, Coordinate> cannedData = new HashMap<>(); static { cannedData.put( "Washington Monument", washingtonMonument); cannedData.put( "White House", whiteHouse); cannedData.put( "FedEx Field", fedexField); } final static FeatureDataAdapter ADAPTER = new FeatureDataAdapter( getPointSimpleFeatureType()); public static void main( final String[] args ) throws AccumuloException, AccumuloSecurityException, InterruptedException, IOException { // spin up a MiniAccumuloCluster and initialize the DataStore setup(); // ingest 3 points represented as SimpleFeatures: Washington Monument, // White House, FedEx Field ingestCannedData(); // execute a query for a bounding box executeBoundingBoxQuery(); // execute a query for a large polygon executePolygonQuery(); // stop MiniAccumuloCluster and delete temporary files cleanup(); } 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), GeotoolsQueryExample.class); accumulo.start(); dataStore = new AccumuloDataStore( new BasicAccumuloOperations( accumulo.getZooKeepers(), accumulo.getInstanceName(), ACCUMULO_USER, ACCUMULO_PASSWORD, TABLE_NAMESPACE)); } private static void ingestCannedData() throws IOException { final List<SimpleFeature> points = new ArrayList<>(); System.out.println("Building SimpleFeatures from canned data set..."); for (final Entry<String, Coordinate> entry : cannedData.entrySet()) { System.out.println("Added point: " + entry.getKey()); points.add(buildSimpleFeature( entry.getKey(), entry.getValue())); } 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 static void executeBoundingBoxQuery() throws IOException { System.out.println("Constructing bounding box for the area contained by [Baltimore, MD and Richmond, VA."); final Geometry boundingBox = GeometryUtils.GEOMETRY_FACTORY.toGeometry(new Envelope( baltimore, richmond)); System.out.println("Executing query, expecting to match ALL points..."); try (final CloseableIterator<SimpleFeature> iterator = dataStore.query( new QueryOptions( ADAPTER, index), new SpatialQuery( boundingBox))) { while (iterator.hasNext()) { System.out.println("Query match: " + iterator.next().getID()); } } } private static void executePolygonQuery() throws IOException { System.out .println("Constructing polygon for the area contained by [Baltimore, MD; Richmond, VA; Harrisonburg, VA]."); final Polygon polygon = GeometryUtils.GEOMETRY_FACTORY.createPolygon(new Coordinate[] { baltimore, richmond, harrisonburg, baltimore }); System.out.println("Executing query, expecting to match ALL points..."); /** * NOTICE: In this query, the adapter is added to the query options. If * an index has data from more than one adapter, the data associated * with a specific adapter can be selected. */ try (final CloseableIterator<SimpleFeature> closableIterator = dataStore.query( new QueryOptions( ADAPTER, index), new SpatialQuery( polygon))) { while (closableIterator.hasNext()) { System.out.println("Query match: " + closableIterator.next().getID()); } } } 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")); return sftBuilder.buildFeatureType(); } private static SimpleFeature buildSimpleFeature( final String locationName, final Coordinate coordinate ) { final SimpleFeatureBuilder builder = new SimpleFeatureBuilder( getPointSimpleFeatureType()); builder.set( "locationName", locationName); builder.set( "geometry", GeometryUtils.GEOMETRY_FACTORY.createPoint(coordinate)); return builder.buildFeature(locationName); } }