package mil.nga.giat.geowave.core.index.sfc.tiered;
import java.util.Arrays;
import mil.nga.giat.geowave.core.index.dimension.NumericDimensionDefinition;
import mil.nga.giat.geowave.core.index.sfc.SFCDimensionDefinition;
import mil.nga.giat.geowave.core.index.sfc.SFCFactory;
import mil.nga.giat.geowave.core.index.sfc.SpaceFillingCurve;
import mil.nga.giat.geowave.core.index.sfc.SFCFactory.SFCType;
import com.google.common.collect.ImmutableBiMap;
/**
* A factory for creating TieredSFCIndexStrategy using various approaches for
* breaking down the bits of precision per tier
*
*/
public class TieredSFCIndexFactory
{
private static int DEFAULT_NUM_TIERS = 11;
/**
* Used to create a Single Tier Index Strategy. For example, this would be
* used to generate a strategy that has Point type spatial data.
*
* @param dimensionDefs
* an array of SFC Dimension Definition objects
* @param sfc
* the type of space filling curve (e.g. Hilbert)
* @return an Index Strategy object with a single tier
*/
static public TieredSFCIndexStrategy createSingleTierStrategy(
final SFCDimensionDefinition[] dimensionDefs,
final SFCType sfc ) {
final SpaceFillingCurve[] orderedSfcs = new SpaceFillingCurve[] {
SFCFactory.createSpaceFillingCurve(
dimensionDefs,
sfc)
};
// unwrap SFC dimension definitions
final NumericDimensionDefinition[] baseDefinitions = new NumericDimensionDefinition[dimensionDefs.length];
int maxBitsOfPrecision = Integer.MIN_VALUE;
for (int d = 0; d < baseDefinitions.length; d++) {
baseDefinitions[d] = dimensionDefs[d].getDimensionDefinition();
maxBitsOfPrecision = Math.max(
dimensionDefs[d].getBitsOfPrecision(),
maxBitsOfPrecision);
}
return new TieredSFCIndexStrategy(
baseDefinitions,
orderedSfcs,
ImmutableBiMap.of(
0,
(byte) maxBitsOfPrecision));
}
/**
* Used to create a Single Tier Index Strategy. For example, this would be
* used to generate a strategy that has Point type spatial data.
*
* @param dimensionDefs
* an array of SFC Dimension Definition objects
* @param sfc
* the type of space filling curve (e.g. Hilbert)
* @return an Index Strategy object with a single tier
*/
static public TieredSFCIndexStrategy createSingleTierStrategy(
final NumericDimensionDefinition[] baseDefinitions,
final int[] maxBitsPerDimension,
final SFCType sfc ) {
final SFCDimensionDefinition[] sfcDimensions = new SFCDimensionDefinition[baseDefinitions.length];
int maxBitsOfPrecision = Integer.MIN_VALUE;
for (int d = 0; d < baseDefinitions.length; d++) {
sfcDimensions[d] = new SFCDimensionDefinition(
baseDefinitions[d],
maxBitsPerDimension[d]);
maxBitsOfPrecision = Math.max(
maxBitsPerDimension[d],
maxBitsOfPrecision);
}
final SpaceFillingCurve[] orderedSfcs = new SpaceFillingCurve[] {
SFCFactory.createSpaceFillingCurve(
sfcDimensions,
sfc)
};
return new TieredSFCIndexStrategy(
baseDefinitions,
orderedSfcs,
ImmutableBiMap.of(
0,
(byte) maxBitsOfPrecision));
}
static public TieredSFCIndexStrategy createFullIncrementalTieredStrategy(
final NumericDimensionDefinition[] baseDefinitions,
final int[] maxBitsPerDimension,
final SFCType sfcType ) {
return createFullIncrementalTieredStrategy(
baseDefinitions,
maxBitsPerDimension,
sfcType,
null);
}
/**
*
* @param baseDefinitions
* an array of Numeric Dimension Definitions
* @param maxBitsPerDimension
* the max cardinality for the Index Strategy
* @param sfcType
* the type of space filling curve (e.g. Hilbert)
* @param maxEstimatedDuplicatedIds
* the max number of duplicate SFC IDs
* @return an Index Strategy object with a tier for every incremental
* cardinality between the lowest max bits of precision and 0
*/
static public TieredSFCIndexStrategy createFullIncrementalTieredStrategy(
final NumericDimensionDefinition[] baseDefinitions,
final int[] maxBitsPerDimension,
final SFCType sfcType,
Long maxEstimatedDuplicatedIds ) {
if (maxBitsPerDimension.length == 0) {
final ImmutableBiMap<Integer, Byte> emptyMap = ImmutableBiMap.of();
return new TieredSFCIndexStrategy(
baseDefinitions,
new SpaceFillingCurve[] {},
emptyMap);
}
int numIndices = Integer.MAX_VALUE;
for (final int element : maxBitsPerDimension) {
numIndices = Math.min(
numIndices,
element + 1);
}
final SpaceFillingCurve[] spaceFillingCurves = new SpaceFillingCurve[numIndices];
final ImmutableBiMap.Builder<Integer, Byte> sfcIndexToTier = ImmutableBiMap.builder();
for (int sfcIndex = 0; sfcIndex < numIndices; sfcIndex++) {
final SFCDimensionDefinition[] sfcDimensions = new SFCDimensionDefinition[baseDefinitions.length];
int maxBitsOfPrecision = Integer.MIN_VALUE;
for (int d = 0; d < baseDefinitions.length; d++) {
final int bitsOfPrecision = maxBitsPerDimension[d] - (numIndices - sfcIndex - 1);
maxBitsOfPrecision = Math.max(
bitsOfPrecision,
maxBitsOfPrecision);
sfcDimensions[d] = new SFCDimensionDefinition(
baseDefinitions[d],
bitsOfPrecision);
}
sfcIndexToTier.put(
sfcIndex,
(byte) maxBitsOfPrecision);
spaceFillingCurves[sfcIndex] = SFCFactory.createSpaceFillingCurve(
sfcDimensions,
sfcType);
}
if (maxEstimatedDuplicatedIds != null && maxEstimatedDuplicatedIds > 0) {
return new TieredSFCIndexStrategy(
baseDefinitions,
spaceFillingCurves,
sfcIndexToTier.build(),
maxEstimatedDuplicatedIds);
}
return new TieredSFCIndexStrategy(
baseDefinitions,
spaceFillingCurves,
sfcIndexToTier.build());
}
/**
*
* @param baseDefinitions
* an array of Numeric Dimension Definitions
* @param maxBitsPerDimension
* the max cardinality for the Index Strategy
* @param sfcType
* the type of space filling curve (e.g. Hilbert)
* @return an Index Strategy object with a equal interval tiers
*/
static public TieredSFCIndexStrategy createEqualIntervalPrecisionTieredStrategy(
final NumericDimensionDefinition[] baseDefinitions,
final int[] maxBitsPerDimension,
final SFCType sfcType ) {
return createEqualIntervalPrecisionTieredStrategy(
baseDefinitions,
maxBitsPerDimension,
sfcType,
DEFAULT_NUM_TIERS);
}
/**
*
* @param baseDefinitions
* an array of Numeric Dimension Definitions
* @param maxBitsPerDimension
* the max cardinality for the Index Strategy
* @param sfcType
* the type of space filling curve (e.g. Hilbert)
* @param numTiers
* the number of tiers of the Index Strategy
* @return an Index Strategy object with a specified number of tiers
*/
static public TieredSFCIndexStrategy createEqualIntervalPrecisionTieredStrategy(
final NumericDimensionDefinition[] baseDefinitions,
final int[] maxBitsPerDimension,
final SFCType sfcType,
final int numIndices ) {
// Subtracting one from the number tiers prevents an extra tier. If
// we decide to create a catch-all, then we can ignore the subtraction.
final SpaceFillingCurve[] spaceFillingCurves = new SpaceFillingCurve[numIndices];
final ImmutableBiMap.Builder<Integer, Byte> sfcIndexToTier = ImmutableBiMap.builder();
for (int sfcIndex = 0; sfcIndex < numIndices; sfcIndex++) {
final SFCDimensionDefinition[] sfcDimensions = new SFCDimensionDefinition[baseDefinitions.length];
int maxBitsOfPrecision = Integer.MIN_VALUE;
for (int d = 0; d < baseDefinitions.length; d++) {
int bitsOfPrecision;
if (numIndices == 1) {
bitsOfPrecision = maxBitsPerDimension[d];
}
else {
final double bitPrecisionIncrement = ((double) maxBitsPerDimension[d] / (numIndices - 1));
bitsOfPrecision = (int) (bitPrecisionIncrement * sfcIndex);
}
maxBitsOfPrecision = Math.max(
bitsOfPrecision,
maxBitsOfPrecision);
sfcDimensions[d] = new SFCDimensionDefinition(
baseDefinitions[d],
bitsOfPrecision);
}
sfcIndexToTier.put(
sfcIndex,
(byte) maxBitsOfPrecision);
spaceFillingCurves[sfcIndex] = SFCFactory.createSpaceFillingCurve(
sfcDimensions,
sfcType);
}
return new TieredSFCIndexStrategy(
baseDefinitions,
spaceFillingCurves,
sfcIndexToTier.build());
}
/**
*
* @param orderedDimensionDefinitions
* an array of Numeric Dimension Definitions
* @param bitsPerDimensionPerLevel
* @param sfcType
* the type of space filling curve (e.g. Hilbert)
* @return an Index Strategy object with a specified number of tiers
*/
static public TieredSFCIndexStrategy createDefinedPrecisionTieredStrategy(
final NumericDimensionDefinition[] orderedDimensionDefinitions,
final int[][] bitsPerDimensionPerLevel,
final SFCType sfcType ) {
Integer numLevels = null;
for (final int[] element : bitsPerDimensionPerLevel) {
if (numLevels == null) {
numLevels = element.length;
}
else {
numLevels = Math.min(
numLevels,
element.length);
}
Arrays.sort(element);
}
if (numLevels == null) {
numLevels = 0;
}
final SpaceFillingCurve[] orderedSFCTiers = new SpaceFillingCurve[numLevels];
final int numDimensions = orderedDimensionDefinitions.length;
final ImmutableBiMap.Builder<Integer, Byte> sfcIndexToTier = ImmutableBiMap.builder();
for (int l = 0; l < numLevels; l++) {
final SFCDimensionDefinition[] sfcDimensions = new SFCDimensionDefinition[numDimensions];
int maxBitsOfPrecision = Integer.MIN_VALUE;
for (int d = 0; d < numDimensions; d++) {
sfcDimensions[d] = new SFCDimensionDefinition(
orderedDimensionDefinitions[d],
bitsPerDimensionPerLevel[d][l]);
maxBitsOfPrecision = Math.max(
bitsPerDimensionPerLevel[d][l],
maxBitsOfPrecision);
}
sfcIndexToTier.put(
l,
(byte) maxBitsOfPrecision);
orderedSFCTiers[l] = SFCFactory.createSpaceFillingCurve(
sfcDimensions,
sfcType);
}
return new TieredSFCIndexStrategy(
orderedDimensionDefinitions,
orderedSFCTiers,
sfcIndexToTier.build());
}
}