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;
}
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;
}
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));
}
}
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(" ", ""));
}
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());
}
Aggregations