Search in sources :

Example 1 with ByteArrayRange

use of org.locationtech.geowave.core.index.ByteArrayRange in project datawave by NationalSecurityAgency.

the class GeoWaveUtils method splitLargeRanges.

/**
 * Splits ranges whose area overlaps more than maxRangeOverlap of the area of the queryGeometry envelope.
 *
 * @param byteArrayRanges
 *            the list of ranges to split
 * @param queryGeometry
 *            the original query geometry
 * @param maxRangeOverlap
 *            the maximum percentage overlap allowed for a range compared to the envelope of the original query geometry
 * @param longBuffer
 *            a reusable byte buffer of Long.BYTES length
 * @return a list of ranges, each of which overlaps less than maxRangeOverlap of the original query geometry
 */
public static List<ByteArrayRange> splitLargeRanges(List<ByteArrayRange> byteArrayRanges, Geometry queryGeometry, double maxRangeOverlap, ByteBuffer longBuffer) {
    longBuffer = initLongBuffer(longBuffer);
    List<ByteArrayRange> splitByteArrayRanges = new ArrayList<>();
    for (ByteArrayRange range : byteArrayRanges) {
        int tier = decodeTier(range.getStart());
        long min = decodePosition(range.getStart(), longBuffer);
        long max = decodePosition(range.getEnd(), longBuffer);
        Geometry rangeGeometry = rangeToGeometry(tier, min, max);
        if (rangeGeometry.getArea() > maxRangeOverlap * queryGeometry.getEnvelope().getArea()) {
            int numSubRanges = (int) (rangeGeometry.getArea() / (maxRangeOverlap * queryGeometry.getEnvelope().getArea())) + 1;
            long offset = (max - min) / numSubRanges;
            for (int i = 0; i < numSubRanges; i++) {
                long subMax = ((i + 1) == numSubRanges) ? max : min + (i + 1) * offset - 1;
                splitByteArrayRanges.add(createByteArrayRange(tier, min + i * offset, subMax, longBuffer));
            }
        } else {
            splitByteArrayRanges.add(range);
        }
    }
    return splitByteArrayRanges;
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) ArrayList(java.util.ArrayList) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange)

Example 2 with ByteArrayRange

use of org.locationtech.geowave.core.index.ByteArrayRange in project datawave by NationalSecurityAgency.

the class GeoWaveUtils method optimizeByteArrayRange.

/**
 * Optimizes the list of byte array ranges needed to query the desired area. Portions of each range which do not intersect the original query polygon will
 * be pruned out.
 *
 * @param queryGeometry
 *            the original query geometry used to create the list of byte array ranges
 * @param byteArrayRange
 *            a byte array range representing a portion of the query geometry
 * @param rangeSplitThreshold
 *            used to determine the minimum number of segments to break a range into - higher values will take longer to compute, but will yield tighter
 *            ranges
 * @param maxRangeOverlap
 *            the maximum amount of overlap a range is allowed to have compared to the envelope of the query geometry - expressed as a double between 0 and
 *            1.
 * @param longBuffer
 *            a reusable byte buffer of Long.BYTES length
 * @return a list of optimized byte array ranges
 */
public static List<ByteArrayRange> optimizeByteArrayRange(Geometry queryGeometry, ByteArrayRange byteArrayRange, int rangeSplitThreshold, double maxRangeOverlap, ByteBuffer longBuffer) {
    GeometryFactory gf = new GeometryFactory();
    List<ByteArrayRange> byteArrayRanges = new ArrayList<>();
    int tier = decodeTier(byteArrayRange.getStart());
    if (tier == 0) {
        byteArrayRanges.add(byteArrayRange);
    } else {
        longBuffer = initLongBuffer(longBuffer);
        long min = decodePosition(byteArrayRange.getStart(), longBuffer);
        long max = decodePosition(byteArrayRange.getEnd(), longBuffer);
        long range = max - min + 1;
        // as well).
        for (int curTier = 0; curTier <= tier; curTier++) {
            long scale = (long) Math.pow(2.0, 2.0 * (tier - curTier));
            if (range >= scale) {
                long scaledMin = (long) Math.ceil((double) min / scale);
                long scaledMax = max / scale;
                if ((scaledMax - scaledMin + 1) >= rangeSplitThreshold) {
                    boolean simplifiedRanges = false;
                    long subRangeMin = scaledMin * scale;
                    long subRangeMax = Long.MIN_VALUE;
                    for (long scaledPos = scaledMin; scaledPos <= scaledMax; scaledPos++) {
                        long nextSubRangeMax = (scaledPos * scale + scale - 1);
                        if (nextSubRangeMax <= max) {
                            simplifiedRanges = true;
                            subRangeMax = nextSubRangeMax;
                            // make sure that this condensed hash is within the bounds of the map
                            byte[] scaledId = createByteArray(curTier, scaledPos, longBuffer);
                            MultiDimensionalNumericData scaledBounds = GeometryNormalizer.indexStrategy.getRangeForId(null, scaledId);
                            // note: all cells for tiers 0 and 1 are within the bounds of the map
                            if (curTier <= 1 || inBounds(scaledBounds)) {
                                Geometry scaledGeom = boundsToGeometry(gf, scaledBounds);
                                // make sure that the scaled geometry intersects the original query geometry
                                if (scaledGeom.intersects(queryGeometry)) {
                                    byteArrayRanges.add(createByteArrayRange(tier, scaledPos * scale, scaledPos * scale + scale - 1, longBuffer));
                                }
                            }
                        } else {
                            break;
                        }
                    }
                    if (simplifiedRanges) {
                        if (min < subRangeMin && rangeToGeometry(tier, min, subRangeMin - 1).intersects(queryGeometry)) {
                            byteArrayRanges.add(createByteArrayRange(tier, min, subRangeMin - 1, longBuffer));
                        }
                        if (max > subRangeMax && rangeToGeometry(tier, subRangeMax + 1, max).intersects(queryGeometry)) {
                            byteArrayRanges.add(createByteArrayRange(tier, subRangeMax + 1, max, longBuffer));
                        }
                        break;
                    }
                }
            }
        }
        if (byteArrayRanges.isEmpty()) {
            if (rangeToGeometry(tier, min, max).intersects(queryGeometry))
                byteArrayRanges.add(byteArrayRange);
        } else {
            if (byteArrayRanges.size() > 1)
                byteArrayRanges = mergeContiguousRanges(byteArrayRanges, longBuffer);
            if (!byteArrayRanges.isEmpty())
                byteArrayRanges = splitLargeRanges(byteArrayRanges, queryGeometry, maxRangeOverlap, longBuffer);
        }
    }
    return byteArrayRanges;
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) ArrayList(java.util.ArrayList) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange)

Example 3 with ByteArrayRange

use of org.locationtech.geowave.core.index.ByteArrayRange in project datawave by NationalSecurityAgency.

the class GeoWaveUtilsTest method optimizeByteArrayRangesTest.

@Test
public void optimizeByteArrayRangesTest() throws Exception {
    String wktString = "POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10))";
    Geometry geom = new WKTReader().read(wktString);
    List<ByteArrayRange> byteArrayRanges = new ArrayList<>();
    for (MultiDimensionalNumericData range : GeometryUtils.basicConstraintsFromEnvelope(geom.getEnvelopeInternal()).getIndexConstraints(GeometryNormalizer.index)) {
        byteArrayRanges.addAll(GeometryNormalizer.index.getIndexStrategy().getQueryRanges(range, 8).getCompositeQueryRanges());
    }
    // count the number of cells included in the original ranges
    long numUnoptimizedIndices = byteArrayRanges.stream().map(range -> (GeoWaveUtils.decodePosition(range.getEnd()) - GeoWaveUtils.decodePosition(range.getStart()) + 1)).reduce(0L, Long::sum);
    List<ByteArrayRange> optimizedByteArrayRanges = GeoWaveUtils.optimizeByteArrayRanges(geom, byteArrayRanges, 16, 0.25);
    // count the number of cells included in the optimized ranges
    long numOptimizedIndices = optimizedByteArrayRanges.stream().map(range -> (GeoWaveUtils.decodePosition(range.getEnd()) - GeoWaveUtils.decodePosition(range.getStart()) + 1)).reduce(0L, Long::sum);
    Assert.assertTrue(numOptimizedIndices < numUnoptimizedIndices);
    // check each tier to ensure that it covers the original geometry
    Map<Integer, List<ByteArrayRange>> rangesByTier = optimizedByteArrayRanges.stream().collect(Collectors.groupingBy(x -> GeoWaveUtils.decodeTier(x.getStart())));
    for (Map.Entry<Integer, List<ByteArrayRange>> ranges : rangesByTier.entrySet()) {
        // union can introduce holes in the final geometry due to the level of precision used to
        // represent the geometries, so we need to ensure that we are only keeping the exterior ring
        Geometry tierGeom = new GeometryFactory().createPolygon(((Polygon) ranges.getValue().stream().map(GeoWaveUtils::rangeToGeometry).reduce(Geometry::union).get()).getExteriorRing().getCoordinates());
        Assert.assertTrue(tierGeom.covers(geom));
    }
}
Also used : ByteArray(org.locationtech.geowave.core.index.ByteArray) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) WKTReader(org.locationtech.jts.io.WKTReader) Test(org.junit.Test) GeometryUtils(org.locationtech.geowave.core.geotime.util.GeometryUtils) Collectors(java.util.stream.Collectors) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) ArrayList(java.util.ArrayList) GeometryNormalizer(datawave.data.normalizer.GeometryNormalizer) List(java.util.List) Map(java.util.Map) Polygon(org.locationtech.jts.geom.Polygon) Geometry(org.locationtech.jts.geom.Geometry) PointNormalizer(datawave.data.normalizer.PointNormalizer) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Assert(org.junit.Assert) Collections(java.util.Collections) MultiDimensionalNumericData(org.locationtech.geowave.core.index.sfc.data.MultiDimensionalNumericData) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) ArrayList(java.util.ArrayList) WKTReader(org.locationtech.jts.io.WKTReader) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Geometry(org.locationtech.jts.geom.Geometry) ArrayList(java.util.ArrayList) List(java.util.List) Polygon(org.locationtech.jts.geom.Polygon) Map(java.util.Map) Test(org.junit.Test)

Example 4 with ByteArrayRange

use of org.locationtech.geowave.core.index.ByteArrayRange in project datawave by NationalSecurityAgency.

the class GeoWaveUtilsTest method createByteArrayRangeTest.

@Test
public void createByteArrayRangeTest() {
    // String, String
    ByteArrayRange byteArrayRange = GeoWaveUtils.createByteArrayRange("0100", "0103");
    Assert.assertEquals("0100", new ByteArray(byteArrayRange.getStart()).getHexString().replace(" ", ""));
    Assert.assertEquals("0103", new ByteArray(byteArrayRange.getEnd()).getHexString().replace(" ", ""));
    // int, long, long
    byteArrayRange = GeoWaveUtils.createByteArrayRange(4, 0, 20);
    Assert.assertEquals("0400", new ByteArray(byteArrayRange.getStart()).getHexString().replace(" ", ""));
    Assert.assertEquals("0414", new ByteArray(byteArrayRange.getEnd()).getHexString().replace(" ", ""));
}
Also used : ByteArray(org.locationtech.geowave.core.index.ByteArray) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Test(org.junit.Test)

Example 5 with ByteArrayRange

use of org.locationtech.geowave.core.index.ByteArrayRange in project datawave by NationalSecurityAgency.

the class GeoWaveUtilsTest method splitLargeRangesTest.

@Test
public void splitLargeRangesTest() throws Exception {
    String wktString = "POLYGON((-180 -90, 180 -90, 180 90, -180 90, -180 -90))";
    Geometry geom = new WKTReader().read(wktString);
    List<ByteArrayRange> byteArrayRanges = new ArrayList<>();
    byteArrayRanges.add(GeoWaveUtils.createByteArrayRange("0100", "0103"));
    List<ByteArrayRange> splitByteArrayRanges = GeoWaveUtils.splitLargeRanges(byteArrayRanges, geom, .75);
    Assert.assertEquals(2, splitByteArrayRanges.size());
}
Also used : Geometry(org.locationtech.jts.geom.Geometry) ArrayList(java.util.ArrayList) WKTReader(org.locationtech.jts.io.WKTReader) ByteArrayRange(org.locationtech.geowave.core.index.ByteArrayRange) Test(org.junit.Test)

Aggregations

ByteArrayRange (org.locationtech.geowave.core.index.ByteArrayRange)58 ArrayList (java.util.ArrayList)33 SinglePartitionQueryRanges (org.locationtech.geowave.core.index.SinglePartitionQueryRanges)13 Test (org.junit.Test)11 QueryRanges (org.locationtech.geowave.core.index.QueryRanges)9 GeoWaveRowRange (org.locationtech.geowave.mapreduce.splits.GeoWaveRowRange)8 ByteArray (org.locationtech.geowave.core.index.ByteArray)7 List (java.util.List)6 Geometry (org.locationtech.jts.geom.Geometry)6 IOException (java.io.IOException)5 HashSet (java.util.HashSet)5 Map (java.util.Map)5 MultiDimensionalNumericData (org.locationtech.geowave.core.index.numeric.MultiDimensionalNumericData)5 RangeDecomposition (org.locationtech.geowave.core.index.sfc.RangeDecomposition)5 HRegionInfo (org.apache.hadoop.hbase.HRegionInfo)4 HRegionLocation (org.apache.hadoop.hbase.HRegionLocation)4 MultiRowRangeFilter (org.apache.hadoop.hbase.filter.MultiRowRangeFilter)4 ClientVisibilityFilter (org.locationtech.geowave.core.store.query.filter.ClientVisibilityFilter)4 HashMap (java.util.HashMap)3 Collectors (java.util.stream.Collectors)3