package mil.nga.giat.geowave.adapter.vector.index; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.IndexUtils; import mil.nga.giat.geowave.core.index.sfc.data.MultiDimensionalNumericData; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatistics; import mil.nga.giat.geowave.core.store.index.Index; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.query.BasicQuery; import org.opengis.feature.simple.SimpleFeature; /** * This Query Strategy purely chooses the index that most closely preserves * locality given a query. It will behave the best assuming a single prefix * query but because it doesn't always choose the index with the most dimensions * defined, it will not always have the most fine-grained contraints given a * larger set of indexable ranges. * * */ public class ChooseLocalityPreservingQueryStrategy implements IndexQueryStrategySPI { public static final String NAME = "Preserve Locality"; @Override public String toString() { return NAME; } @Override public CloseableIterator<Index<?, ?>> getIndices( final Map<ByteArrayId, DataStatistics<SimpleFeature>> stats, final BasicQuery query, final PrimaryIndex[] indices ) { return new CloseableIterator<Index<?, ?>>() { PrimaryIndex nextIdx = null; boolean done = false; int i = 0; @Override public boolean hasNext() { double indexMax = -1; PrimaryIndex bestIdx = null; while (!done && i < indices.length) { nextIdx = indices[i++]; if (nextIdx.getIndexStrategy().getOrderedDimensionDefinitions().length == 0) continue; final List<MultiDimensionalNumericData> queryRanges = query.getIndexConstraints(nextIdx .getIndexStrategy()); if (IndexUtils.isFullTableScan(queryRanges)) { // keep this is as a default in case all indices // result in a full table scan if (bestIdx == null) { bestIdx = nextIdx; } } else { double totalMax = 0; for (final MultiDimensionalNumericData qr : queryRanges) { final double[] dataRangePerDimension = new double[qr.getDimensionCount()]; for (int d = 0; d < dataRangePerDimension.length; d++) { dataRangePerDimension[d] = qr.getMaxValuesPerDimension()[d] - qr.getMinValuesPerDimension()[d]; } totalMax += IndexUtils.getDimensionalBitsUsed( nextIdx.getIndexStrategy(), dataRangePerDimension); } if (totalMax > indexMax) { indexMax = totalMax; bestIdx = nextIdx; } } } nextIdx = bestIdx; done = true; return nextIdx != null; } @Override public Index<?, ?> next() throws NoSuchElementException { if (nextIdx == null) { throw new NoSuchElementException(); } final Index<?, ?> returnVal = nextIdx; nextIdx = null; return returnVal; } @Override public void remove() {} @Override public void close() throws IOException {} }; } }