package mil.nga.giat.geowave.core.index.simple; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.ByteArrayRange; import mil.nga.giat.geowave.core.index.CompoundIndexStrategy; import mil.nga.giat.geowave.core.index.MultiDimensionalCoordinates; import mil.nga.giat.geowave.core.index.NumericIndexStrategy; import mil.nga.giat.geowave.core.index.PersistenceUtils; import mil.nga.giat.geowave.core.index.dimension.BasicDimensionDefinition; import mil.nga.giat.geowave.core.index.dimension.NumericDimensionDefinition; import mil.nga.giat.geowave.core.index.sfc.SFCFactory.SFCType; import mil.nga.giat.geowave.core.index.sfc.data.BasicNumericDataset; import mil.nga.giat.geowave.core.index.sfc.data.MultiDimensionalNumericData; import mil.nga.giat.geowave.core.index.sfc.data.NumericData; import mil.nga.giat.geowave.core.index.sfc.data.NumericRange; import mil.nga.giat.geowave.core.index.sfc.tiered.TieredSFCIndexFactory; import org.junit.Assert; import org.junit.Test; public class HashKeyIndexStrategyTest { private static final NumericDimensionDefinition[] SPATIAL_DIMENSIONS = new NumericDimensionDefinition[] { new BasicDimensionDefinition( -180, 180), new BasicDimensionDefinition( -90, 90) }; private static final NumericIndexStrategy sfcIndexStrategy = TieredSFCIndexFactory.createSingleTierStrategy( SPATIAL_DIMENSIONS, new int[] { 16, 16 }, SFCType.HILBERT); private static final HashKeyIndexStrategy hashIdexStrategy = new HashKeyIndexStrategy( 3); private static final CompoundIndexStrategy compoundIndexStrategy = new CompoundIndexStrategy( hashIdexStrategy, sfcIndexStrategy); private static final NumericRange dimension1Range = new NumericRange( 50.0, 50.025); private static final NumericRange dimension2Range = new NumericRange( -20.5, -20.455); private static final MultiDimensionalNumericData sfcIndexedRange = new BasicNumericDataset( new NumericData[] { dimension1Range, dimension2Range }); @Test public void testDistribution() { final Map<ByteArrayId, Long> counts = new HashMap<ByteArrayId, Long>(); int total = 0; for (double x = 90; x < 180; x += 0.05) { for (double y = 50; y < 90; y += 0.5) { final NumericRange dimension1Range = new NumericRange( x, x + 0.002); final NumericRange dimension2Range = new NumericRange( y - 0.002, y); final MultiDimensionalNumericData sfcIndexedRange = new BasicNumericDataset( new NumericData[] { dimension1Range, dimension2Range }); for (ByteArrayId id : hashIdexStrategy.getInsertionIds(sfcIndexedRange)) { Long count = counts.get(id); long nextcount = count == null ? 1 : count + 1; counts.put( id, nextcount); total++; } } } double mean = total / counts.size(); double diff = 0.0; for (Long count : counts.values()) { diff += Math.pow( mean - count, 2); } double sd = Math.sqrt(diff / counts.size()); assertTrue(sd < mean * 0.18); } @Test public void testBinaryEncoding() { final byte[] bytes = PersistenceUtils.toBinary(compoundIndexStrategy); final CompoundIndexStrategy deserializedStrategy = PersistenceUtils.fromBinary( bytes, CompoundIndexStrategy.class); final byte[] bytes2 = PersistenceUtils.toBinary(deserializedStrategy); Assert.assertArrayEquals( bytes, bytes2); } @Test public void testNumberOfDimensionsPerIndexStrategy() { final int[] numDimensionsPerStrategy = compoundIndexStrategy.getNumberOfDimensionsPerIndexStrategy(); Assert.assertEquals( 0, numDimensionsPerStrategy[0]); Assert.assertEquals( 2, numDimensionsPerStrategy[1]); } @Test public void testGetNumberOfDimensions() { final int numDimensions = compoundIndexStrategy.getNumberOfDimensions(); Assert.assertEquals( 2, numDimensions); } @Test public void testGetCoordinatesPerDimension() { final NumericRange dimension1Range = new NumericRange( 20.01, 20.02); final NumericRange dimension2Range = new NumericRange( 30.51, 30.59); final MultiDimensionalNumericData sfcIndexedRange = new BasicNumericDataset( new NumericData[] { dimension1Range, dimension2Range }); for (ByteArrayId id : compoundIndexStrategy.getInsertionIds(sfcIndexedRange)) { MultiDimensionalCoordinates coords = compoundIndexStrategy.getCoordinatesPerDimension(id); assertTrue(coords.getCoordinate( 0).getCoordinate() > 0); assertTrue(coords.getCoordinate( 1).getCoordinate() > 0); MultiDimensionalNumericData nd = compoundIndexStrategy.getRangeForId(id); assertEquals( 20.02, nd.getMaxValuesPerDimension()[0], 0.1); assertEquals( 30.59, nd.getMaxValuesPerDimension()[1], 0.2); assertEquals( 20.01, nd.getMinValuesPerDimension()[0], 0.1); assertEquals( 30.57, nd.getMinValuesPerDimension()[1], 0.2); } } @Test public void testGetQueryRangesWithMaximumNumberOfRanges() { final List<ByteArrayRange> sfcIndexRanges = sfcIndexStrategy.getQueryRanges(sfcIndexedRange); final List<ByteArrayRange> ranges = new ArrayList<>(); for (int i = 0; i < 3; i++) { for (final ByteArrayRange r2 : sfcIndexRanges) { final ByteArrayId start = compoundIndexStrategy.composeByteArrayId( new ByteArrayId( new byte[] { (byte) i }), r2.getStart()); final ByteArrayId end = compoundIndexStrategy.composeByteArrayId( new ByteArrayId( new byte[] { (byte) i }), r2.getEnd()); ranges.add(new ByteArrayRange( start, end)); } } final Set<ByteArrayRange> testRanges = new HashSet<>( ranges); final Set<ByteArrayRange> compoundIndexRanges = new HashSet<>( compoundIndexStrategy.getQueryRanges(sfcIndexedRange)); Assert.assertTrue(testRanges.containsAll(compoundIndexRanges)); Assert.assertTrue(compoundIndexRanges.containsAll(testRanges)); } }