package mil.nga.giat.geowave.core.geotime.ingest;
import com.beust.jcommander.Parameter;
import mil.nga.giat.geowave.core.geotime.index.dimension.LatitudeDefinition;
import mil.nga.giat.geowave.core.geotime.index.dimension.LongitudeDefinition;
import mil.nga.giat.geowave.core.geotime.index.dimension.TemporalBinningStrategy.Unit;
import mil.nga.giat.geowave.core.geotime.store.dimension.GeometryWrapper;
import mil.nga.giat.geowave.core.geotime.store.dimension.LatitudeField;
import mil.nga.giat.geowave.core.geotime.store.dimension.LongitudeField;
import mil.nga.giat.geowave.core.geotime.store.dimension.TimeField;
import mil.nga.giat.geowave.core.index.ByteArrayId;
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.xz.XZHierarchicalIndexFactory;
import mil.nga.giat.geowave.core.store.dimension.NumericDimensionField;
import mil.nga.giat.geowave.core.store.index.BasicIndexModel;
import mil.nga.giat.geowave.core.store.index.CommonIndexValue;
import mil.nga.giat.geowave.core.store.index.CustomIdIndex;
import mil.nga.giat.geowave.core.store.index.PrimaryIndex;
import mil.nga.giat.geowave.core.store.operations.remote.options.IndexPluginOptions.BaseIndexBuilder;
import mil.nga.giat.geowave.core.store.spi.DimensionalityTypeOptions;
import mil.nga.giat.geowave.core.store.spi.DimensionalityTypeProviderSpi;
public class SpatialDimensionalityTypeProvider implements
DimensionalityTypeProviderSpi
{
private final SpatialOptions options = new SpatialOptions();
private static final String DEFAULT_SPATIAL_ID = "SPATIAL_IDX";
private static final int LONGITUDE_BITS = 31;
private static final int LATITUDE_BITS = 31;
protected static final NumericDimensionDefinition[] SPATIAL_DIMENSIONS = new NumericDimensionDefinition[] {
new LongitudeDefinition(),
new LatitudeDefinition(
true)
// just use the same range for latitude to make square sfc values in
// decimal degrees (EPSG:4326)
};
protected static final NumericDimensionField[] SPATIAL_FIELDS = new NumericDimensionField[] {
new LongitudeField(),
new LatitudeField(
true)
// just use the same range for latitude to make square sfc values in
// decimal degrees (EPSG:4326)
};
protected static final NumericDimensionField[] SPATIAL_TEMPORAL_FIELDS = new NumericDimensionField[] {
new LongitudeField(),
new LatitudeField(
true),
new TimeField(
Unit.YEAR)
};
public SpatialDimensionalityTypeProvider() {}
@Override
public String getDimensionalityTypeName() {
return "spatial";
}
@Override
public String getDimensionalityTypeDescription() {
return "This dimensionality type matches all indices that only require Geometry.";
}
@Override
public int getPriority() {
// arbitrary - just higher than spatial temporal so that the default
// will be spatial over spatial-temporal
return 10;
}
@Override
public DimensionalityTypeOptions getOptions() {
return options;
}
@Override
public PrimaryIndex createPrimaryIndex() {
return internalCreatePrimaryIndex(options);
}
private static PrimaryIndex internalCreatePrimaryIndex(
final SpatialOptions options ) {
return new CustomIdIndex(
XZHierarchicalIndexFactory.createFullIncrementalTieredStrategy(
SPATIAL_DIMENSIONS,
new int[] {
LONGITUDE_BITS,
LATITUDE_BITS
},
SFCType.HILBERT),
new BasicIndexModel(
options.storeTime ? SPATIAL_TEMPORAL_FIELDS : SPATIAL_FIELDS),
new ByteArrayId(
options.storeTime ? DEFAULT_SPATIAL_ID + "_TIME" : DEFAULT_SPATIAL_ID));
}
private static class SpatialOptions implements
DimensionalityTypeOptions
{
@Parameter(names = {
"--storeTime"
}, required = false, description = "The index will store temporal values. This allows it to slightly more efficiently run spatial-temporal queries although if spatial-temporal queries are a common use case, a separate spatial-temporal index is recommended.")
protected boolean storeTime = false;
}
@Override
public Class<? extends CommonIndexValue>[] getRequiredIndexTypes() {
return new Class[] {
GeometryWrapper.class
};
}
public static class SpatialIndexBuilder extends
BaseIndexBuilder<SpatialIndexBuilder>
{
private final SpatialOptions options;
public SpatialIndexBuilder() {
super();
options = new SpatialOptions();
}
public SpatialIndexBuilder setIncludeTimeInCommonIndexModel(
final boolean storeTime ) {
options.storeTime = storeTime;
return this;
}
@Override
public PrimaryIndex createIndex() {
return createIndex(internalCreatePrimaryIndex(options));
}
}
public static boolean isSpatial(
final PrimaryIndex index ) {
if ((index == null) || (index.getIndexStrategy() == null)
|| (index.getIndexStrategy().getOrderedDimensionDefinitions() == null)) {
return false;
}
final NumericDimensionDefinition[] dimensions = index.getIndexStrategy().getOrderedDimensionDefinitions();
if (dimensions.length != 2) {
return false;
}
boolean hasLat = false, hasLon = false;
for (final NumericDimensionDefinition definition : dimensions) {
if (definition instanceof LatitudeDefinition) {
hasLat = true;
}
else if (definition instanceof LongitudeDefinition) {
hasLon = true;
}
}
return hasLat && hasLon;
}
}