package mil.nga.giat.geowave.adapter.vector.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import mil.nga.giat.geowave.adapter.vector.stats.FeatureBoundingBoxStatistics;
import mil.nga.giat.geowave.adapter.vector.stats.FeatureTimeRangeStatistics;
import mil.nga.giat.geowave.adapter.vector.util.FeatureDataUtils;
import mil.nga.giat.geowave.adapter.vector.util.QueryIndexHelper;
import mil.nga.giat.geowave.adapter.vector.utils.TimeDescriptors.TimeDescriptorConfiguration;
import mil.nga.giat.geowave.core.geotime.ingest.SpatialDimensionalityTypeProvider;
import mil.nga.giat.geowave.core.geotime.ingest.SpatialTemporalDimensionalityTypeProvider;
import mil.nga.giat.geowave.core.geotime.store.query.TemporalConstraints;
import mil.nga.giat.geowave.core.geotime.store.query.TemporalConstraintsSet;
import mil.nga.giat.geowave.core.geotime.store.query.TemporalRange;
import mil.nga.giat.geowave.core.index.ByteArrayId;
import mil.nga.giat.geowave.core.index.NumericIndexStrategy;
import mil.nga.giat.geowave.core.index.sfc.data.MultiDimensionalNumericData;
import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatistics;
import mil.nga.giat.geowave.core.store.query.BasicQuery;
import mil.nga.giat.geowave.core.store.query.BasicQuery.Constraints;
import org.geotools.data.DataUtilities;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.referencing.CRS;
import org.junit.Before;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.MathTransform;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;
public class QueryIndexHelperTest
{
private static final NumericIndexStrategy SPATIAL_INDEX_STRATEGY = new SpatialDimensionalityTypeProvider()
.createPrimaryIndex()
.getIndexStrategy();
private static final NumericIndexStrategy SPATIAL_TEMPORAL_INDEX_STRATEGY = new SpatialTemporalDimensionalityTypeProvider()
.createPrimaryIndex()
.getIndexStrategy();
final ByteArrayId dataAdapterId = new ByteArrayId(
"123");
SimpleFeatureType rangeType;
SimpleFeatureType singleType;
SimpleFeatureType geoType;
SimpleFeatureType geoMercType;
final TimeDescriptors geoTimeDescriptors = new TimeDescriptors();
final TimeDescriptors rangeTimeDescriptors = new TimeDescriptors();
final TimeDescriptors singleTimeDescriptors = new TimeDescriptors();
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(
PrecisionModel.FIXED));
Date startTime, endTime;
Object[] singleDefaults, rangeDefaults, geoDefaults;
MathTransform transform;
@Before
public void setup()
throws SchemaException,
ParseException,
FactoryException {
startTime = DateUtilities.parseISO("2005-05-15T20:32:56Z");
endTime = DateUtilities.parseISO("2005-05-20T20:32:56Z");
geoType = DataUtilities.createType(
"geostuff",
"geometry:Geometry:srid=4326,pop:java.lang.Long,pid:String");
geoMercType = DataUtilities.createType(
"geostuff",
"geometry:Geometry:srid=3785,pop:java.lang.Long,pid:String");
rangeType = DataUtilities.createType(
"geostuff",
"geometry:Geometry:srid=4326,start:Date,end:Date,pop:java.lang.Long,pid:String");
singleType = DataUtilities.createType(
"geostuff",
"geometry:Geometry:srid=4326,when:Date,pop:java.lang.Long,pid:String");
transform = CRS.findMathTransform(
geoMercType.getCoordinateReferenceSystem(),
geoType.getCoordinateReferenceSystem(),
true);
final TimeDescriptorConfiguration rangeConfig = new TimeDescriptorConfiguration();
rangeConfig.configureFromType(rangeType);
rangeTimeDescriptors.update(
rangeType,
rangeConfig);
final TimeDescriptorConfiguration singleTimeConfig = new TimeDescriptorConfiguration();
singleTimeConfig.configureFromType(singleType);
singleTimeDescriptors.update(
singleType,
singleTimeConfig);
List<AttributeDescriptor> descriptors = rangeType.getAttributeDescriptors();
rangeDefaults = new Object[descriptors.size()];
int p = 0;
for (final AttributeDescriptor descriptor : descriptors) {
rangeDefaults[p++] = descriptor.getDefaultValue();
}
descriptors = singleType.getAttributeDescriptors();
singleDefaults = new Object[descriptors.size()];
p = 0;
for (final AttributeDescriptor descriptor : descriptors) {
singleDefaults[p++] = descriptor.getDefaultValue();
}
descriptors = geoType.getAttributeDescriptors();
geoDefaults = new Object[descriptors.size()];
p = 0;
for (final AttributeDescriptor descriptor : descriptors) {
geoDefaults[p++] = descriptor.getDefaultValue();
}
}
@Test
public void testGetTemporalConstraintsForSingleClippedRange()
throws ParseException {
final Date stime = DateUtilities.parseISO("2005-05-14T20:32:56Z");
final Date etime = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date stime1 = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date etime1 = DateUtilities.parseISO("2005-05-19T20:32:56Z");
final Map<ByteArrayId, DataStatistics<SimpleFeature>> statsMap = new HashMap<ByteArrayId, DataStatistics<SimpleFeature>>();
final FeatureTimeRangeStatistics whenStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"when");
statsMap.put(
FeatureTimeRangeStatistics.composeId("when"),
whenStats);
final TemporalConstraintsSet constraintsSet = new TemporalConstraintsSet();
constraintsSet.getConstraintsFor(
"when").add(
new TemporalRange(
stime,
etime));
final SimpleFeature notIntersectSingle1 = createSingleTimeFeature(startTime);
whenStats.entryIngested(
null,
notIntersectSingle1);
final SimpleFeature notIntersectSingle = createSingleTimeFeature(endTime);
whenStats.entryIngested(
null,
notIntersectSingle);
final TemporalConstraintsSet resultConstraintsSet = QueryIndexHelper.clipIndexedTemporalConstraints(
statsMap,
singleTimeDescriptors,
constraintsSet);
final TemporalConstraints constraints = resultConstraintsSet.getConstraintsFor("when");
assertEquals(
1,
constraints.getRanges().size());
assertEquals(
startTime,
constraints.getStartRange().getStartTime());
assertEquals(
etime,
constraints.getStartRange().getEndTime());
final TemporalConstraintsSet constraintsSet1 = new TemporalConstraintsSet();
constraintsSet1.getConstraintsFor(
"when").add(
new TemporalRange(
stime1,
etime1));
final TemporalConstraintsSet resultConstraintsSet1 = QueryIndexHelper.clipIndexedTemporalConstraints(
statsMap,
singleTimeDescriptors,
constraintsSet1);
final TemporalConstraints constraints1 = resultConstraintsSet1.getConstraintsFor("when");
assertEquals(
1,
constraints1.getRanges().size());
assertEquals(
stime1,
constraints1.getStartRange().getStartTime());
assertEquals(
etime1,
constraints1.getStartRange().getEndTime());
}
@Test
public void testGetTemporalConstraintsForRangeClippedFullRange()
throws ParseException {
final Map<ByteArrayId, DataStatistics<SimpleFeature>> statsMap = new HashMap<ByteArrayId, DataStatistics<SimpleFeature>>();
final FeatureTimeRangeStatistics startStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"start");
statsMap.put(
FeatureTimeRangeStatistics.composeId("start"),
startStats);
final FeatureTimeRangeStatistics endStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"end");
statsMap.put(
FeatureTimeRangeStatistics.composeId("end"),
endStats);
final Date statsStart1 = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date statsStart2 = DateUtilities.parseISO("2005-05-20T20:32:56Z");
final Date statsEnd1 = DateUtilities.parseISO("2005-05-21T20:32:56Z");
final Date statsEnd2 = DateUtilities.parseISO("2005-05-24T20:32:56Z");
final SimpleFeature firstRangFeature = createFeature(
statsStart1,
statsEnd1);
startStats.entryIngested(
null,
firstRangFeature);
endStats.entryIngested(
null,
firstRangFeature);
final SimpleFeature secondRangFeature = createFeature(
statsStart2,
statsEnd2);
startStats.entryIngested(
null,
secondRangFeature);
endStats.entryIngested(
null,
secondRangFeature);
final Date stime = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date etime = DateUtilities.parseISO("2005-05-19T20:32:56Z");
final TemporalConstraintsSet constraintsSet = new TemporalConstraintsSet();
constraintsSet.getConstraintsForRange(
"start",
"end").add(
new TemporalRange(
new Date(
0),
etime));
final TemporalConstraintsSet resultConstraintsSet = QueryIndexHelper.clipIndexedTemporalConstraints(
statsMap,
rangeTimeDescriptors,
constraintsSet);
final TemporalConstraints constraints = resultConstraintsSet.getConstraintsForRange(
"start",
"end");
assertEquals(
1,
constraints.getRanges().size());
assertEquals(
stime,
constraints.getStartRange().getStartTime());
assertEquals(
etime,
constraints.getStartRange().getEndTime());
}
@Test
public void testComposeQueryWithTimeRange()
throws ParseException {
final Map<ByteArrayId, DataStatistics<SimpleFeature>> statsMap = new HashMap<ByteArrayId, DataStatistics<SimpleFeature>>();
final FeatureTimeRangeStatistics startStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"start");
statsMap.put(
FeatureTimeRangeStatistics.composeId("start"),
startStats);
final FeatureTimeRangeStatistics endStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"end");
statsMap.put(
FeatureTimeRangeStatistics.composeId("end"),
endStats);
final Date statsStart1 = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date statsStart2 = DateUtilities.parseISO("2005-05-20T20:32:56Z");
final Date statsEnd1 = DateUtilities.parseISO("2005-05-21T20:32:56Z");
final Date statsEnd2 = DateUtilities.parseISO("2005-05-24T20:32:56Z");
final SimpleFeature firstRangFeature = createFeature(
statsStart1,
statsEnd1);
startStats.entryIngested(
null,
firstRangFeature);
endStats.entryIngested(
null,
firstRangFeature);
final SimpleFeature secondRangFeature = createFeature(
statsStart2,
statsEnd2);
startStats.entryIngested(
null,
secondRangFeature);
endStats.entryIngested(
null,
secondRangFeature);
final Date stime = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date etime = DateUtilities.parseISO("2005-05-19T20:32:56Z");
final TemporalConstraintsSet constraintsSet = new TemporalConstraintsSet();
constraintsSet.getConstraintsForRange(
"start",
"end").add(
new TemporalRange(
stime,
etime));
final BasicQuery query = new BasicQuery(
QueryIndexHelper.composeConstraints(
rangeType,
rangeTimeDescriptors,
statsMap,
factory.toGeometry(factory.createPoint(
new Coordinate(
27.25,
41.25)).getEnvelopeInternal()),
constraintsSet));
final List<MultiDimensionalNumericData> nd = query.getIndexConstraints(SPATIAL_TEMPORAL_INDEX_STRATEGY);
assertEquals(
stime.getTime(),
(long) nd.get(
0).getDataPerDimension()[2].getMin());
assertEquals(
etime.getTime(),
(long) nd.get(
0).getDataPerDimension()[2].getMax());
final BasicQuery query1 = new BasicQuery(
QueryIndexHelper.composeConstraints(
rangeType,
rangeTimeDescriptors,
statsMap,
factory.toGeometry(factory.createPoint(
new Coordinate(
27.25,
41.25)).getEnvelopeInternal()),
null));
final List<MultiDimensionalNumericData> nd1 = query1.getIndexConstraints(SPATIAL_TEMPORAL_INDEX_STRATEGY);
assertEquals(
statsStart1.getTime(),
(long) nd1.get(
0).getDataPerDimension()[2].getMin());
assertEquals(
statsEnd2.getTime(),
(long) nd1.get(
0).getDataPerDimension()[2].getMax());
}
@Test
public void testComposeQueryWithOutTimeRange() {
final Map<ByteArrayId, DataStatistics<SimpleFeature>> statsMap = new HashMap<ByteArrayId, DataStatistics<SimpleFeature>>();
final FeatureBoundingBoxStatistics geoStats = new FeatureBoundingBoxStatistics(
dataAdapterId,
"geometry");
statsMap.put(
FeatureBoundingBoxStatistics.composeId("geometry"),
geoStats);
final SimpleFeature firstFeature = createGeoFeature(factory.createPoint(new Coordinate(
22.25,
42.25)));
geoStats.entryIngested(
null,
firstFeature);
final SimpleFeature secondFeature = createGeoFeature(factory.createPoint(new Coordinate(
27.25,
41.25)));
geoStats.entryIngested(
null,
secondFeature);
final Envelope bounds = new Envelope(
21.23,
26.23,
41.75,
43.1);
final BasicQuery query = new BasicQuery(
QueryIndexHelper.composeConstraints(
geoType,
geoTimeDescriptors,
statsMap,
new GeometryFactory().toGeometry(bounds),
null));
final List<MultiDimensionalNumericData> nd = query.getIndexConstraints(SPATIAL_INDEX_STRATEGY);
assertEquals(
21.23,
nd.get(
0).getDataPerDimension()[0].getMin(),
0.0001);
assertEquals(
26.23,
nd.get(
0).getDataPerDimension()[0].getMax(),
0.0001);
assertEquals(
41.75,
nd.get(
0).getDataPerDimension()[1].getMin(),
0.0001);
assertEquals(
43.1,
nd.get(
0).getDataPerDimension()[1].getMax(),
0.0001);
}
@Test
public void testGetBBOX() {
final Map<ByteArrayId, DataStatistics<SimpleFeature>> statsMap = new HashMap<ByteArrayId, DataStatistics<SimpleFeature>>();
final FeatureBoundingBoxStatistics geoStats = new FeatureBoundingBoxStatistics(
dataAdapterId,
"geometry");
statsMap.put(
FeatureBoundingBoxStatistics.composeId("geometry"),
geoStats);
final SimpleFeature firstFeature = createGeoFeature(factory.createPoint(new Coordinate(
22.25,
42.25)));
geoStats.entryIngested(
null,
firstFeature);
final SimpleFeature secondFeature = createGeoFeature(factory.createPoint(new Coordinate(
27.25,
41.25)));
geoStats.entryIngested(
null,
secondFeature);
final Envelope bounds = new Envelope(
21.23,
26.23,
41.75,
43.1);
final Geometry bbox = QueryIndexHelper.clipIndexedBBOXConstraints(
geoType,
new GeometryFactory().toGeometry(bounds),
statsMap);
final Envelope env = bbox.getEnvelopeInternal();
assertEquals(
22.25,
env.getMinX(),
0.0001);
assertEquals(
26.23,
env.getMaxX(),
0.0001);
assertEquals(
41.75,
env.getMinY(),
0.0001);
assertEquals(
42.25,
env.getMaxY(),
0.0001);
}
@Test
public void testBBOXStatReprojection() {
// create a EPSG:3785 feature (units in meters)
final SimpleFeature mercFeat = createGeoMercFeature(factory.createPoint(new Coordinate(
19971868.8804,
20037508.3428)));
// convert from EPSG:3785 to EPSG:4326 (convert to degrees lon/lat)
// approximately 180.0, 85.0
final SimpleFeature defaultCRSFeat = FeatureDataUtils.defaultCRSTransform(
mercFeat,
geoMercType,
geoType,
transform);
final FeatureBoundingBoxStatistics geoStats = new FeatureBoundingBoxStatistics(
dataAdapterId,
"geometry",
geoMercType,
geoType,
transform);
geoStats.entryIngested(
null,
mercFeat);
final Coordinate coord = ((Point) defaultCRSFeat.getDefaultGeometry()).getCoordinate();
// coordinate should match reprojected feature
assertEquals(
coord.x,
geoStats.getMinX(),
0.0001);
assertEquals(
coord.x,
geoStats.getMaxX(),
0.0001);
assertEquals(
coord.y,
geoStats.getMinY(),
0.0001);
assertEquals(
coord.y,
geoStats.getMaxY(),
0.0001);
}
private SimpleFeature createGeoFeature(
final Geometry geo ) {
final SimpleFeature instance = SimpleFeatureBuilder.build(
geoType,
geoDefaults,
UUID.randomUUID().toString());
instance.setAttribute(
"pop",
Long.valueOf(100));
instance.setAttribute(
"pid",
UUID.randomUUID().toString());
instance.setAttribute(
"geometry",
geo);
return instance;
}
private SimpleFeature createGeoMercFeature(
final Geometry geo ) {
final SimpleFeature instance = SimpleFeatureBuilder.build(
geoMercType,
geoDefaults,
UUID.randomUUID().toString());
instance.setAttribute(
"pop",
Long.valueOf(100));
instance.setAttribute(
"pid",
UUID.randomUUID().toString());
instance.setAttribute(
"geometry",
geo);
return instance;
}
private SimpleFeature createSingleTimeFeature(
final Date time ) {
final SimpleFeature instance = SimpleFeatureBuilder.build(
singleType,
singleDefaults,
UUID.randomUUID().toString());
instance.setAttribute(
"pop",
Long.valueOf(100));
instance.setAttribute(
"pid",
UUID.randomUUID().toString());
instance.setAttribute(
"when",
time);
instance.setAttribute(
"geometry",
factory.createPoint(new Coordinate(
27.25,
41.25)));
return instance;
}
@Test
public void testComposeSubsetConstraints()
throws ParseException {
final Map<ByteArrayId, DataStatistics<SimpleFeature>> statsMap = new HashMap<ByteArrayId, DataStatistics<SimpleFeature>>();
final FeatureTimeRangeStatistics startStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"start");
statsMap.put(
FeatureTimeRangeStatistics.composeId("start"),
startStats);
final FeatureTimeRangeStatistics endStats = new FeatureTimeRangeStatistics(
dataAdapterId,
"end");
statsMap.put(
FeatureTimeRangeStatistics.composeId("end"),
endStats);
final Date statsStart1 = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date statsStart2 = DateUtilities.parseISO("2005-05-20T20:32:56Z");
final Date statsEnd1 = DateUtilities.parseISO("2005-05-21T20:32:56Z");
final Date statsEnd2 = DateUtilities.parseISO("2005-05-24T20:32:56Z");
final SimpleFeature firstRangFeature = createFeature(
statsStart1,
statsEnd1);
startStats.entryIngested(
null,
firstRangFeature);
endStats.entryIngested(
null,
firstRangFeature);
final SimpleFeature secondRangFeature = createFeature(
statsStart2,
statsEnd2);
startStats.entryIngested(
null,
secondRangFeature);
endStats.entryIngested(
null,
secondRangFeature);
final Date stime = DateUtilities.parseISO("2005-05-18T20:32:56Z");
final Date etime = DateUtilities.parseISO("2005-05-19T20:32:56Z");
final TemporalConstraintsSet constraintsSet = new TemporalConstraintsSet();
constraintsSet.getConstraintsForRange(
"start",
"end").add(
new TemporalRange(
stime,
etime));
final Constraints constraints = QueryIndexHelper.composeTimeBoundedConstraints(
rangeType,
rangeTimeDescriptors,
statsMap,
constraintsSet);
final List<MultiDimensionalNumericData> nd = constraints.getIndexConstraints(SPATIAL_TEMPORAL_INDEX_STRATEGY);
assertTrue(nd.isEmpty());
final FeatureBoundingBoxStatistics geoStats = new FeatureBoundingBoxStatistics(
dataAdapterId,
"geometry");
statsMap.put(
FeatureBoundingBoxStatistics.composeId("geometry"),
geoStats);
final SimpleFeature firstFeature = createGeoFeature(factory.createPoint(new Coordinate(
22.25,
42.25)));
geoStats.entryIngested(
null,
firstFeature);
final SimpleFeature secondFeature = createGeoFeature(factory.createPoint(new Coordinate(
27.25,
41.25)));
geoStats.entryIngested(
null,
secondFeature);
final Constraints constraints1 = QueryIndexHelper.composeConstraints(
rangeType,
rangeTimeDescriptors,
statsMap,
null,
constraintsSet);
final List<MultiDimensionalNumericData> nd1 = constraints1.getIndexConstraints(SPATIAL_TEMPORAL_INDEX_STRATEGY);
assertTrue(nd1.isEmpty());
/*
* assertEquals( stime.getTime(), (long) nd1.get(
* 0).getDataPerDimension()[2].getMin()); assertEquals( etime.getTime(),
* (long) nd1.get( 0).getDataPerDimension()[2].getMax());
*/
final TemporalConstraintsSet constraintsSet2 = new TemporalConstraintsSet();
constraintsSet2.getConstraintsForRange(
"start",
"end").add(
new TemporalRange(
statsStart1,
statsEnd2));
final Constraints constraints2 = QueryIndexHelper.composeTimeBoundedConstraints(
rangeType,
rangeTimeDescriptors,
statsMap,
constraintsSet2);
final List<MultiDimensionalNumericData> nd2 = constraints2.getIndexConstraints(SPATIAL_TEMPORAL_INDEX_STRATEGY);
assertTrue(nd2.isEmpty());
}
private SimpleFeature createFeature(
final Date sTime,
final Date eTime ) {
final SimpleFeature instance = SimpleFeatureBuilder.build(
rangeType,
rangeDefaults,
UUID.randomUUID().toString());
instance.setAttribute(
"pop",
Long.valueOf(100));
instance.setAttribute(
"pid",
UUID.randomUUID().toString());
instance.setAttribute(
"start",
sTime);
instance.setAttribute(
"end",
eTime);
instance.setAttribute(
"geometry",
factory.createPoint(new Coordinate(
27.25,
41.25)));
return instance;
}
}