All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.locationtech.geowave.examples.aggregation.binning.SpatialBinningAggregationExample Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2013-2022 Contributors to the Eclipse Foundation
 *
 * 

See the NOTICE file distributed with this work for additional information regarding copyright * ownership. All rights reserved. This program and the accompanying materials are made available * under the terms of the Apache License, Version 2.0 which accompanies this distribution and is * available at http://www.apache.org/licenses/LICENSE-2.0.txt */ package org.locationtech.geowave.examples.aggregation.binning; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.commons.lang3.tuple.Pair; import org.geotools.feature.AttributeTypeBuilder; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.locationtech.geowave.adapter.vector.FeatureDataAdapter; import org.locationtech.geowave.core.geotime.binning.SpatialBinningType; import org.locationtech.geowave.core.geotime.index.SpatialDimensionalityTypeProvider; import org.locationtech.geowave.core.geotime.index.SpatialOptions; import org.locationtech.geowave.core.geotime.store.query.aggregate.SpatialSimpleFeatureBinningStrategy; import org.locationtech.geowave.core.geotime.util.GeometryUtils; import org.locationtech.geowave.core.index.ByteArray; import org.locationtech.geowave.core.store.api.AggregationQuery; import org.locationtech.geowave.core.store.api.AggregationQueryBuilder; import org.locationtech.geowave.core.store.api.DataStore; import org.locationtech.geowave.core.store.api.DataStoreFactory; import org.locationtech.geowave.core.store.api.Index; import org.locationtech.geowave.core.store.api.Writer; import org.locationtech.geowave.core.store.memory.MemoryRequiredOptions; import org.locationtech.geowave.core.store.query.aggregate.FieldNameParam; import org.locationtech.geowave.core.store.query.aggregate.FieldSumAggregation; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; /** * This class provides an example of how to create a binned aggregation for your data. You may want * to use a binned aggregation if you need to sort your data into buckets and process the buckets * individually.

This example counts the population after grouping the data by geohash, by S3, * and by S2. */ public class SpatialBinningAggregationExample { public static void main(final String[] args) { // this example shows binning using geohashes but it can easily use Google's S2 or Uber's H3 as // well for spatial binning final SimpleFeatureType featureType = getSimpleFeatureType(); // Points (to be ingested into GeoWave Data Store) final List cannedFeatures = ImmutableList.of( buildSimpleFeature(featureType, "Loc1", new Coordinate(-77.0352, 38.8895), 12), buildSimpleFeature(featureType, "Loc2", new Coordinate(-77.0366, 38.8977), 13), buildSimpleFeature(featureType, "Loc3", new Coordinate(-76.8644, 38.9078), 8), buildSimpleFeature(featureType, "Loc4", new Coordinate(-76.350677, 38.9641511), 15), buildSimpleFeature(featureType, "Loc5", new Coordinate(-77.3384112, 38.416091), 7), buildSimpleFeature(featureType, "Loc6", new Coordinate(-67.0352, 28.8895), 3), buildSimpleFeature(featureType, "Loc7", new Coordinate(-67.0366, 28.8977), 99), buildSimpleFeature(featureType, "Loc8", new Coordinate(-66.8644, 28.9078), 0), buildSimpleFeature(featureType, "Loc9", new Coordinate(-66.350677, 28.9641511), 1), buildSimpleFeature(featureType, "Loc10", new Coordinate(-67.3384112, 28.416091), 23)); final Index index = SpatialDimensionalityTypeProvider.createIndexFromOptions(new SpatialOptions()); final DataStore dataStore = DataStoreFactory.createDataStore(new MemoryRequiredOptions()); final FeatureDataAdapter adapter = new FeatureDataAdapter(featureType); // Ingest cannedFeatures into the DataStore. dataStore.addType(adapter, index); try (Writer indexWriter = dataStore.createWriter(adapter.getTypeName())) { for (final SimpleFeature sf : cannedFeatures) { indexWriter.write(sf); } } // calculate the population count for each precision from 1 to 6. // a geohash like g5c is a hash that is contained by the geohash g5, // which is contained by the geohash g. final Map allResults = Maps.newHashMapWithExpectedSize(100); for (int i = 6; i > 0; i--) { // execute a binned Aggregation, return the results // -1 maxBins means no max. allResults.putAll( executeBinningAggregation(i, index.getName(), adapter.getTypeName(), dataStore, -1)); } System.out.printf( "Results for precision 1-6: %s%n", Arrays.toString( allResults.entrySet().stream().map( e -> Pair.of( SpatialBinningType.GEOHASH.binToString(e.getKey().getBytes()), e.getValue())).map(p -> p.getKey() + "=" + p.getValue()).toArray( String[]::new))); System.out.printf( "Results just for precision 6: %s%n", Arrays.toString( allResults.entrySet().stream().filter((e) -> e.getKey().getBytes().length == 6).map( e -> Pair.of( SpatialBinningType.GEOHASH.binToString(e.getKey().getBytes()), e.getValue())).map(p -> p.getKey() + "=" + p.getValue()).toArray( String[]::new))); // when maxBins is used, it will simply drop any new data that comes in. final Map maxed = executeBinningAggregation(8, index.getName(), adapter.getTypeName(), dataStore, 5); System.out.printf( "Results limited to the first 5 bins: %s%n", Arrays.toString( maxed.entrySet().stream().map( e -> Pair.of( SpatialBinningType.GEOHASH.binToString(e.getKey().getBytes()), e.getValue())).map(p -> p.getKey() + "=" + p.getValue()).toArray( String[]::new))); } /** * This method creates a binning aggregation that groups the data in the dataStore by the given * precision, and sums all of the entries in the group. * * @param precision The geohash precision to use during binning. * @param indexName The index to query * @param typeName The name of the registered type adapter to use for serialization purposes. * @param dataStore where we have stored the data that we will aggregate. * @return Aggregated and computed data. Each entry has a key that is the geohash, and a value * that is the population in that geohash. */ private static Map executeBinningAggregation( final int precision, final String indexName, final String typeName, final DataStore dataStore, final int maxBins) { final AggregationQueryBuilder queryBuilder = AggregationQueryBuilder.newBuilder(); queryBuilder.indexName(indexName); // Use `.count` instead of `aggregate` if you simply want to count the amount of rows // queryBuilder.count("geometry"); // aggregate uses a provided aggregation to form data. queryBuilder.aggregate(typeName, new FieldSumAggregation(new FieldNameParam("population"))); // `.bin` uses the current aggregation (the VectorSumAggregation in this case), // but adds a binning strategy on top of it. // each bin uses a fresh aggregation, so there is no contamination between aggregations. // P here is BinningAggregationOptions But Java lets us elide it. // NOTE: here's where SpatialBinningType could instead be Google's S2 or Uber's H3 if desired final AggregationQuery, SimpleFeature> agg = queryBuilder.buildWithBinningStrategy( new SpatialSimpleFeatureBinningStrategy(SpatialBinningType.GEOHASH, precision, true), maxBins); // Aggregate the data in the dataStore with the AggregationQuery. return dataStore.aggregate(agg); } /** * A helper that constructs the SimpleFeatureType used in this example. */ private static SimpleFeatureType getSimpleFeatureType() { final String name = "ExampleSimpleFeatureType"; final SimpleFeatureTypeBuilder sftBuilder = new SimpleFeatureTypeBuilder(); final AttributeTypeBuilder atBuilder = new AttributeTypeBuilder(); sftBuilder.setName(name); // the location name isn't used in this example, its just here for show! sftBuilder.add(atBuilder.binding(String.class).nillable(false).buildDescriptor("locationName")); // this is used for the grouping (the `.bin` call). sftBuilder.add(atBuilder.binding(Geometry.class).nillable(false).buildDescriptor("geometry")); // this is the field that is summed in each group, as defined by the `.aggregate` call. sftBuilder.add(atBuilder.binding(Integer.class).nillable(false).buildDescriptor("population")); return sftBuilder.buildFeatureType(); } /** * Just a helper method to create a SimpleFeature to the specifications used in this example. */ private static SimpleFeature buildSimpleFeature( final SimpleFeatureType featureType, final String locationName, final Coordinate coordinate, final int population) { final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType); builder.set("locationName", locationName); builder.set("geometry", GeometryUtils.GEOMETRY_FACTORY.createPoint(coordinate)); builder.set("population", population); return builder.buildFeature(locationName); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy