package mil.nga.giat.geowave.core.store.index; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.Persistable; import mil.nga.giat.geowave.core.index.PersistenceUtils; import mil.nga.giat.geowave.core.index.StringUtils; import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatistics; import mil.nga.giat.geowave.core.store.base.DataStoreEntryInfo.FieldInfo; /** * This class fully describes everything necessary to index data within GeoWave * using secondary indexing. <br> * The key components are the indexing strategy and the common index model. <br> * <br> * Attributes for SecondaryIndex include:<br> * indexStrategy = array of fieldIndexStrategy (numeric, temporal or text)<br> * fieldId<br> * associatedStatistics <br> * secondaryIndexType - (join, full, partial)<br> * secondaryIndexId - <br> * partialFieldIds - list of fields that are part of the ...<br> */ public class SecondaryIndex<T> implements Index<FilterableConstraints, List<FieldInfo<?>>> { private static final String TABLE_PREFIX = "GEOWAVE_2ND_IDX_"; private FieldIndexStrategy<?, ?> indexStrategy; private ByteArrayId fieldId; private List<DataStatistics<T>> associatedStatistics; private SecondaryIndexType secondaryIndexType; private ByteArrayId secondaryIndexId; private List<ByteArrayId> partialFieldIds; protected SecondaryIndex() {} public SecondaryIndex( final FieldIndexStrategy<?, ?> indexStrategy, final ByteArrayId fieldId, final List<DataStatistics<T>> associatedStatistics, final SecondaryIndexType secondaryIndexType ) { this( indexStrategy, fieldId, associatedStatistics, secondaryIndexType, Collections.<ByteArrayId> emptyList()); } public SecondaryIndex( final FieldIndexStrategy<?, ?> indexStrategy, final ByteArrayId fieldId, final List<DataStatistics<T>> associatedStatistics, final SecondaryIndexType secondaryIndexType, final List<ByteArrayId> partialFieldIds ) { super(); this.indexStrategy = indexStrategy; this.fieldId = fieldId; this.associatedStatistics = associatedStatistics; this.secondaryIndexType = secondaryIndexType; this.secondaryIndexId = new ByteArrayId( TABLE_PREFIX + indexStrategy.getId() + "_" + secondaryIndexType.getValue()); this.partialFieldIds = partialFieldIds; } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public FieldIndexStrategy getIndexStrategy() { return indexStrategy; } public ByteArrayId getFieldId() { return fieldId; } @Override public ByteArrayId getId() { return secondaryIndexId; } public List<DataStatistics<T>> getAssociatedStatistics() { return associatedStatistics; } public SecondaryIndexType getSecondaryIndexType() { return secondaryIndexType; } public List<ByteArrayId> getPartialFieldIds() { return partialFieldIds; } @Override public int hashCode() { return getId().hashCode(); } /** * Compare this object to the one passed as parameter to see if same object, * same class and that id is the same. */ @Override public boolean equals( final Object obj ) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SecondaryIndex<?> other = (SecondaryIndex<?>) obj; return getId().equals( other.getId()); } @Override public byte[] toBinary() { final byte[] indexStrategyBinary = PersistenceUtils.toBinary(indexStrategy); final byte[] fieldIdBinary = fieldId.getBytes(); final byte[] secondaryIndexTypeBinary = StringUtils.stringToBinary(secondaryIndexType.getValue()); final List<Persistable> persistables = new ArrayList<Persistable>(); for (DataStatistics<T> dataStatistics : associatedStatistics) { persistables.add(dataStatistics); } final byte[] persistablesBinary = PersistenceUtils.toBinary(persistables); final boolean handlePartials = (partialFieldIds != null && !partialFieldIds.isEmpty()); int partialsLength = 0; byte[] partialsBinary = null; if (handlePartials) { int totalLength = 0; for (final ByteArrayId partialFieldId : partialFieldIds) { totalLength += partialFieldId.getBytes().length; } final ByteBuffer allPartials = ByteBuffer.allocate(totalLength + (partialFieldIds.size() * 4)); for (final ByteArrayId partialFieldId : partialFieldIds) { allPartials.putInt(partialFieldId.getBytes().length); allPartials.put(partialFieldId.getBytes()); } partialsLength = allPartials.array().length; partialsBinary = allPartials.array(); } final ByteBuffer buf = ByteBuffer.allocate(indexStrategyBinary.length + fieldIdBinary.length + secondaryIndexTypeBinary.length + 20 + persistablesBinary.length + partialsLength + (partialsLength > 0 ? 4 : 0)); buf.putInt(indexStrategyBinary.length); buf.putInt(fieldIdBinary.length); buf.putInt(secondaryIndexTypeBinary.length); buf.putInt(persistablesBinary.length); buf.putInt(handlePartials ? partialFieldIds.size() : 0); buf.put(indexStrategyBinary); buf.put(fieldIdBinary); buf.put(secondaryIndexTypeBinary); buf.put(persistablesBinary); if (handlePartials) { buf.putInt(partialsLength); buf.put(partialsBinary); } return buf.array(); } @SuppressWarnings("unchecked") @Override public void fromBinary( final byte[] bytes ) { final ByteBuffer buf = ByteBuffer.wrap(bytes); final int indexStrategyLength = buf.getInt(); final int fieldIdLength = buf.getInt(); final int secondaryIndexTypeLength = buf.getInt(); final int persistablesBinaryLength = buf.getInt(); final int numPartials = buf.getInt(); final byte[] indexStrategyBinary = new byte[indexStrategyLength]; final byte[] fieldIdBinary = new byte[fieldIdLength]; final byte[] secondaryIndexTypeBinary = new byte[secondaryIndexTypeLength]; buf.get(indexStrategyBinary); buf.get(fieldIdBinary); buf.get(secondaryIndexTypeBinary); indexStrategy = PersistenceUtils.fromBinary( indexStrategyBinary, FieldIndexStrategy.class); fieldId = new ByteArrayId( fieldIdBinary); secondaryIndexType = SecondaryIndexType.valueOf(StringUtils.stringFromBinary(secondaryIndexTypeBinary)); final byte[] persistablesBinary = new byte[persistablesBinaryLength]; buf.get(persistablesBinary); final List<Persistable> persistables = PersistenceUtils.fromBinary(persistablesBinary); for (final Persistable persistable : persistables) { associatedStatistics.add((DataStatistics<T>) persistable); } secondaryIndexId = new ByteArrayId( StringUtils.stringToBinary(indexStrategy.getId() + "_" + secondaryIndexType.getValue())); if (numPartials > 0) { partialFieldIds = new ArrayList<>(); final int partialsLength = buf.getInt(); final byte[] partialsBinary = new byte[partialsLength]; final ByteBuffer partialsBB = ByteBuffer.wrap(partialsBinary); for (int i = 0; i < numPartials; i++) { final int currPartialLength = partialsBB.getInt(); final byte[] currPartialBinary = new byte[currPartialLength]; partialFieldIds.add(new ByteArrayId( currPartialBinary)); } } } }