package mil.nga.giat.geowave.adapter.raster.adapter; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.ByteArrayRange; import mil.nga.giat.geowave.core.index.CompoundIndexStrategy; import mil.nga.giat.geowave.core.index.Coordinate; import mil.nga.giat.geowave.core.index.HierarchicalNumericIndexStrategy; import mil.nga.giat.geowave.core.index.IndexMetaData; import mil.nga.giat.geowave.core.index.MultiDimensionalCoordinateRanges; 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.index.dimension.NumericDimensionDefinition; import mil.nga.giat.geowave.core.index.sfc.data.MultiDimensionalNumericData; import mil.nga.giat.geowave.core.index.simple.RoundRobinKeyIndexStrategy; /** * This class wraps the first occurrence of a hierarchical index within a * compound index such that sub strategies within the hierarchy are replaced * maintaining the rest of the structure of the compound index * * */ public class CompoundHierarchicalIndexStrategyWrapper implements HierarchicalNumericIndexStrategy { private final static Logger LOGGER = LoggerFactory.getLogger(CompoundHierarchicalIndexStrategyWrapper.class); private List<CompoundIndexStrategy> parentStrategies; private HierarchicalNumericIndexStrategy firstHierarchicalStrategy; public CompoundHierarchicalIndexStrategyWrapper( final List<CompoundIndexStrategy> parentStrategies, final HierarchicalNumericIndexStrategy firstHierarchicalStrategy ) { this.parentStrategies = parentStrategies; this.firstHierarchicalStrategy = firstHierarchicalStrategy; } protected CompoundHierarchicalIndexStrategyWrapper() { super(); } @Override public SubStrategy[] getSubStrategies() { // for these substrategies we need to replace the last parent strategy's // hierarchical index strategy with the underlying substrategy index // strategy final SubStrategy[] subStrategies = firstHierarchicalStrategy.getSubStrategies(); final SubStrategy[] retVal = new SubStrategy[subStrategies.length]; for (int i = 0; i < subStrategies.length; i++) { NumericIndexStrategy currentStrategyToBeReplaced = firstHierarchicalStrategy; NumericIndexStrategy currentStrategyReplacement = subStrategies[i].getIndexStrategy(); for (int j = parentStrategies.size() - 1; j >= 0; j--) { // traverse parents in reverse order final CompoundIndexStrategy parent = parentStrategies.get(j); if (parent.getPrimarySubStrategy().equals( currentStrategyToBeReplaced)) { // replace primary currentStrategyReplacement = new CompoundIndexStrategy( currentStrategyReplacement, parent.getSecondarySubStrategy()); } else { // replace secondary currentStrategyReplacement = new CompoundIndexStrategy( parent.getPrimarySubStrategy(), currentStrategyReplacement); } currentStrategyToBeReplaced = parent; } retVal[i] = new SubStrategy( currentStrategyReplacement, subStrategies[i].getPrefix()); } return retVal; } @Override public byte[] toBinary() { return PersistenceUtils.toBinary(parentStrategies.get(0)); } @Override public List<ByteArrayRange> getQueryRanges( final MultiDimensionalNumericData indexedRange, final IndexMetaData... hints ) { return parentStrategies.get( 0).getQueryRanges( indexedRange, hints); } @Override public void fromBinary( final byte[] bytes ) { final CompoundIndexStrategy rootStrategy = PersistenceUtils.fromBinary( bytes, CompoundIndexStrategy.class); parentStrategies = new ArrayList<CompoundIndexStrategy>(); // discover hierarchy firstHierarchicalStrategy = findHierarchicalStrategy( rootStrategy, parentStrategies); } @Override public List<ByteArrayRange> getQueryRanges( final MultiDimensionalNumericData indexedRange, final int maxEstimatedRangeDecomposition, final IndexMetaData... hints ) { return parentStrategies.get( 0).getQueryRanges( indexedRange, maxEstimatedRangeDecomposition, hints); } @Override public NumericDimensionDefinition[] getOrderedDimensionDefinitions() { return parentStrategies.get( 0).getOrderedDimensionDefinitions(); } @Override public List<ByteArrayId> getInsertionIds( final MultiDimensionalNumericData indexedData ) { return parentStrategies.get( 0).getInsertionIds( indexedData); } @Override public double[] getHighestPrecisionIdRangePerDimension() { return parentStrategies.get( 0).getHighestPrecisionIdRangePerDimension(); } @Override public int getByteOffsetFromDimensionalIndex() { return parentStrategies.get( 0).getByteOffsetFromDimensionalIndex(); } @Override public List<ByteArrayId> getInsertionIds( final MultiDimensionalNumericData indexedData, final int maxEstimatedDuplicateIds ) { return parentStrategies.get( 0).getInsertionIds( indexedData, maxEstimatedDuplicateIds); } @Override public MultiDimensionalNumericData getRangeForId( final ByteArrayId insertionId ) { return parentStrategies.get( 0).getRangeForId( insertionId); } @Override public String getId() { return parentStrategies.get( 0).getId(); } @Override public Set<ByteArrayId> getNaturalSplits() { return parentStrategies.get( 0).getNaturalSplits(); } @Override public List<IndexMetaData> createMetaData() { return parentStrategies.get( 0).createMetaData(); } public static HierarchicalNumericIndexStrategy findHierarchicalStrategy( final NumericIndexStrategy indexStrategy ) { final List<CompoundIndexStrategy> parentStrategies = new ArrayList<CompoundIndexStrategy>(); final HierarchicalNumericIndexStrategy firstHierarchicalStrategy = findHierarchicalStrategy( indexStrategy, parentStrategies); if (firstHierarchicalStrategy == null) { return null; } else if (parentStrategies.isEmpty()) { return firstHierarchicalStrategy; } else { return new CompoundHierarchicalIndexStrategyWrapper( parentStrategies, firstHierarchicalStrategy); } } public static HierarchicalNumericIndexStrategy findHierarchicalStrategy( final NumericIndexStrategy indexStrategy, final List<CompoundIndexStrategy> parentStrategies ) { if (indexStrategy instanceof HierarchicalNumericIndexStrategy) { return (HierarchicalNumericIndexStrategy) indexStrategy; } if (indexStrategy instanceof CompoundIndexStrategy) { final NumericIndexStrategy primaryIndex = ((CompoundIndexStrategy) indexStrategy).getPrimarySubStrategy(); final NumericIndexStrategy secondaryIndex = ((CompoundIndexStrategy) indexStrategy) .getSecondarySubStrategy(); // warn if round robin is used if (primaryIndex instanceof RoundRobinKeyIndexStrategy) { LOGGER.warn("Round Robin partitioning won't work correctly with raster merge strategies"); } else if (secondaryIndex instanceof RoundRobinKeyIndexStrategy) { LOGGER.warn("Round Robin partitioning won't work correctly with raster merge strategies"); } final HierarchicalNumericIndexStrategy primary = findHierarchicalStrategy(primaryIndex); if (primary != null) { // add it to beginning because we are recursing back from the // leaf strategy up to the parent parentStrategies.add( 0, (CompoundIndexStrategy) indexStrategy); return primary; } final HierarchicalNumericIndexStrategy secondary = findHierarchicalStrategy(secondaryIndex); if (secondary != null) { // add it to beginning because we are recursing back from the // leaf strategy up to the parent parentStrategies.add( 0, (CompoundIndexStrategy) indexStrategy); return secondary; } } return null; } @Override public MultiDimensionalCoordinates getCoordinatesPerDimension( ByteArrayId insertionId ) { return parentStrategies.get( 0).getCoordinatesPerDimension( insertionId); } @Override public MultiDimensionalCoordinateRanges[] getCoordinateRangesPerDimension( MultiDimensionalNumericData dataRange, IndexMetaData... hints ) { return parentStrategies.get( 0).getCoordinateRangesPerDimension( dataRange, hints); } }