package mil.nga.giat.geowave.datastore.accumulo.query;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.iterators.IteratorEnvironment;
import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
import org.apache.hadoop.io.Text;
import mil.nga.giat.geowave.core.index.ByteArrayId;
import mil.nga.giat.geowave.core.index.ByteArrayUtils;
import mil.nga.giat.geowave.core.index.MultiDimensionalCoordinateRangesArray.ArrayOfArrays;
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.store.entities.GeowaveRowId;
import mil.nga.giat.geowave.core.store.query.CoordinateRangeUtils.RangeCache;
import mil.nga.giat.geowave.core.store.query.CoordinateRangeUtils.RangeLookupFactory;
public class NumericIndexStrategyFilterIterator implements
SortedKeyValueIterator<Key, Value>
{
// this is after the versioning iterator at 20 but before the more expensive
// distributable filter iterator at 25
protected static final int IDX_FILTER_ITERATOR_PRIORITY = 22;
protected static final String IDX_FILTER_ITERATOR_NAME = "GEOWAVE_IDX_FILTER";
protected static String COORDINATE_RANGE_KEY = "COORD_RANGE";
protected static String INDEX_STRATEGY_KEY = "IDX_STRATEGY";
private SortedKeyValueIterator<Key, Value> source = null;
private Key topKey = null;
private Value topValue = null;
private final Text row = new Text();
private NumericIndexStrategy indexStrategy;
private RangeCache rangeCache;
@Override
public void init(
final SortedKeyValueIterator<Key, Value> source,
final Map<String, String> options,
final IteratorEnvironment env )
throws IOException {
this.source = source;
if (options == null) {
throw new IllegalArgumentException(
"Arguments must be set for " + NumericIndexStrategyFilterIterator.class.getName());
}
try {
if (options.containsKey(INDEX_STRATEGY_KEY)) {
final String idxStrategyStr = options.get(INDEX_STRATEGY_KEY);
final byte[] idxStrategyBytes = ByteArrayUtils.byteArrayFromString(idxStrategyStr);
indexStrategy = PersistenceUtils.fromBinary(
idxStrategyBytes,
NumericIndexStrategy.class);
}
else {
throw new IllegalArgumentException(
"'" + INDEX_STRATEGY_KEY + "' must be set for "
+ NumericIndexStrategyFilterIterator.class.getName());
}
if (options.containsKey(COORDINATE_RANGE_KEY)) {
final String coordRangeStr = options.get(COORDINATE_RANGE_KEY);
final byte[] coordRangeBytes = ByteArrayUtils.byteArrayFromString(coordRangeStr);
final ArrayOfArrays arrays = new ArrayOfArrays();
arrays.fromBinary(coordRangeBytes);
rangeCache = RangeLookupFactory.createMultiRangeLookup(arrays.getCoordinateArrays());
}
else {
throw new IllegalArgumentException(
"'" + COORDINATE_RANGE_KEY + "' must be set for "
+ NumericIndexStrategyFilterIterator.class.getName());
}
}
catch (final Exception e) {
throw new IllegalArgumentException(
e);
}
}
@Override
public boolean hasTop() {
return topKey != null;
}
@Override
public void next()
throws IOException {
source.next();
findTop();
}
@Override
public void seek(
final Range range,
final Collection<ByteSequence> columnFamilies,
final boolean inclusive )
throws IOException {
source.seek(
range,
columnFamilies,
inclusive);
findTop();
}
@Override
public Key getTopKey() {
return topKey;
}
@Override
public Value getTopValue() {
return topValue;
}
@Override
public SortedKeyValueIterator<Key, Value> deepCopy(
final IteratorEnvironment env ) {
final NumericIndexStrategyFilterIterator iterator = new NumericIndexStrategyFilterIterator();
iterator.indexStrategy = indexStrategy;
iterator.rangeCache = rangeCache;
iterator.source = source.deepCopy(env);
return iterator;
}
private void findTop() {
topKey = null;
topValue = null;
while (source.hasTop()) {
if (inBounds(source.getTopKey())) {
topKey = source.getTopKey();
topValue = source.getTopValue();
return;
}
else {
try {
source.next();
}
catch (final IOException e) {
throw new RuntimeException(
e);
}
}
}
}
private boolean inBounds(
final Key k ) {
k.getRow(row);
final MultiDimensionalCoordinates coordinates = indexStrategy.getCoordinatesPerDimension(new ByteArrayId(
new GeowaveRowId(
row.getBytes(),
row.getLength()).getInsertionId()));
return rangeCache.inBounds(coordinates);
}
}