package mil.nga.giat.geowave.core.store.query; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.tuple.Pair; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.ByteArrayRange; import mil.nga.giat.geowave.core.index.IndexMetaData; import mil.nga.giat.geowave.core.index.MultiDimensionalCoordinateRangesArray; import mil.nga.giat.geowave.core.index.NumericIndexStrategy; import mil.nga.giat.geowave.core.index.sfc.data.MultiDimensionalNumericData; import mil.nga.giat.geowave.core.store.adapter.DataAdapter; import mil.nga.giat.geowave.core.store.adapter.statistics.DuplicateEntryCount; import mil.nga.giat.geowave.core.store.filter.DedupeFilter; import mil.nga.giat.geowave.core.store.filter.DistributableQueryFilter; import mil.nga.giat.geowave.core.store.filter.QueryFilter; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.query.aggregate.Aggregation; import mil.nga.giat.geowave.core.store.util.DataStoreUtils; public class ConstraintsQuery { public static final int MAX_RANGE_DECOMPOSITION = 2000; public static final int AGGREGATION_RANGE_DECOMPOSITION = 10; public final Pair<DataAdapter<?>, Aggregation<?, ?, ?>> aggregation; public final List<MultiDimensionalNumericData> constraints; public final List<DistributableQueryFilter> distributableFilters; private final IndexMetaData[] indexMetaData; private final PrimaryIndex index; public ConstraintsQuery( final List<MultiDimensionalNumericData> constraints, final Pair<DataAdapter<?>, Aggregation<?, ?, ?>> aggregation, final IndexMetaData[] indexMetaData, final PrimaryIndex index, final List<QueryFilter> queryFilters, DedupeFilter clientDedupeFilter, final DuplicateEntryCount duplicateCounts, final FilteredIndexQuery parentQuery ) { this.constraints = constraints; this.aggregation = aggregation; this.indexMetaData = indexMetaData != null ? indexMetaData : new IndexMetaData[] {}; this.index = index; final SplitFilterLists lists = splitList(queryFilters); final List<QueryFilter> clientFilters = lists.clientFilters; if ((duplicateCounts != null) && !duplicateCounts.isAnyEntryHaveDuplicates()) { clientDedupeFilter = null; } // add dedupe filters to the front of both lists so that the // de-duplication is performed before any more complex filtering // operations, use the supplied client dedupe filter if possible if (clientDedupeFilter != null) { clientFilters.add( 0, clientDedupeFilter); } parentQuery.setClientFilters(clientFilters); distributableFilters = lists.distributableFilters; if (!distributableFilters.isEmpty() && clientDedupeFilter != null) { distributableFilters.add( 0, clientDedupeFilter); } } public boolean isAggregation() { return ((aggregation != null) && (aggregation.getRight() != null)); } public List<MultiDimensionalCoordinateRangesArray> getCoordinateRanges() { if ((constraints == null) || constraints.isEmpty()) { return new ArrayList<MultiDimensionalCoordinateRangesArray>(); } else { final NumericIndexStrategy indexStrategy = index.getIndexStrategy(); final List<MultiDimensionalCoordinateRangesArray> ranges = new ArrayList<MultiDimensionalCoordinateRangesArray>(); for (final MultiDimensionalNumericData nd : constraints) { ranges.add(new MultiDimensionalCoordinateRangesArray( indexStrategy.getCoordinateRangesPerDimension( nd, indexMetaData))); } return ranges; } } public List<ByteArrayRange> getRanges() { if (isAggregation()) { final List<ByteArrayRange> ranges = DataStoreUtils.constraintsToByteArrayRanges( constraints, index.getIndexStrategy(), AGGREGATION_RANGE_DECOMPOSITION, indexMetaData); if ((ranges == null) || (ranges.size() < 2)) { return ranges; } final List<ByteArrayRange> retVal = new ArrayList<ByteArrayRange>(); retVal.add(getSingleRange(ranges)); return retVal; } else { return getAllRanges(); } } private ByteArrayRange getSingleRange( List<ByteArrayRange> ranges ) { ByteArrayId start = null; ByteArrayId end = null; for (final ByteArrayRange range : ranges) { if ((start == null) || (range.getStart().compareTo( start) < 0)) { start = range.getStart(); } if ((end == null) || (range.getEnd().compareTo( end) > 0)) { end = range.getEnd(); } } return new ByteArrayRange( start, end); } public List<ByteArrayRange> getAllRanges() { return DataStoreUtils.constraintsToByteArrayRanges( constraints, index.getIndexStrategy(), MAX_RANGE_DECOMPOSITION, indexMetaData); } private SplitFilterLists splitList( final List<QueryFilter> allFilters ) { final List<DistributableQueryFilter> distributableFilters = new ArrayList<DistributableQueryFilter>(); final List<QueryFilter> clientFilters = new ArrayList<QueryFilter>(); if ((allFilters == null) || allFilters.isEmpty()) { return new SplitFilterLists( distributableFilters, clientFilters); } for (final QueryFilter filter : allFilters) { if (filter instanceof DistributableQueryFilter) { distributableFilters.add((DistributableQueryFilter) filter); } else { clientFilters.add(filter); } } return new SplitFilterLists( distributableFilters, clientFilters); } private static class SplitFilterLists { private final List<DistributableQueryFilter> distributableFilters; private final List<QueryFilter> clientFilters; public SplitFilterLists( final List<DistributableQueryFilter> distributableFilters, final List<QueryFilter> clientFilters ) { this.distributableFilters = distributableFilters; this.clientFilters = clientFilters; } } }