package mil.nga.giat.geowave.test.query; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableMap; import java.util.Set; import java.util.UUID; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Range; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.security.Authorizations; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.io.Text; import org.geotools.data.DataUtilities; import org.geotools.feature.SchemaException; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Point; import mil.nga.giat.geowave.adapter.vector.FeatureDataAdapter; import mil.nga.giat.geowave.adapter.vector.index.NumericSecondaryIndexConfiguration; import mil.nga.giat.geowave.adapter.vector.index.TemporalSecondaryIndexConfiguration; import mil.nga.giat.geowave.adapter.vector.index.TextSecondaryIndexConfiguration; import mil.nga.giat.geowave.adapter.vector.utils.SimpleFeatureUserDataConfiguration; import mil.nga.giat.geowave.adapter.vector.utils.SimpleFeatureUserDataConfigurationSet; import mil.nga.giat.geowave.core.geotime.GeometryUtils; import mil.nga.giat.geowave.core.geotime.store.dimension.GeometryAdapter; import mil.nga.giat.geowave.core.geotime.store.query.SpatialQuery; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.StringUtils; import mil.nga.giat.geowave.core.index.lexicoder.Lexicoders; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.DataStore; import mil.nga.giat.geowave.core.store.adapter.exceptions.MismatchedIndexToAdapterMapping; import mil.nga.giat.geowave.core.store.index.FilterableConstraints; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.index.SecondaryIndex; import mil.nga.giat.geowave.core.store.index.SecondaryIndexDataStore; import mil.nga.giat.geowave.core.store.index.SecondaryIndexType; import mil.nga.giat.geowave.core.store.index.SecondaryIndexUtils; import mil.nga.giat.geowave.core.store.index.numeric.NumericGreaterThanConstraint; import mil.nga.giat.geowave.core.store.index.temporal.TemporalQueryConstraint; import mil.nga.giat.geowave.core.store.index.text.TextQueryConstraint; import mil.nga.giat.geowave.core.store.IndexWriter; import mil.nga.giat.geowave.core.store.operations.remote.options.DataStorePluginOptions; import mil.nga.giat.geowave.core.store.query.DataIdQuery; import mil.nga.giat.geowave.core.store.query.DistributableQuery; import mil.nga.giat.geowave.core.store.query.Query; import mil.nga.giat.geowave.core.store.query.QueryOptions; import mil.nga.giat.geowave.datastore.accumulo.index.secondary.AccumuloSecondaryIndexDataStore; import mil.nga.giat.geowave.datastore.accumulo.operations.config.AccumuloRequiredOptions; import mil.nga.giat.geowave.datastore.accumulo.util.ConnectorPool; import mil.nga.giat.geowave.datastore.hbase.index.secondary.HBaseSecondaryIndexDataStore; import mil.nga.giat.geowave.datastore.hbase.operations.config.HBaseRequiredOptions; import mil.nga.giat.geowave.datastore.hbase.util.ConnectionPool; import mil.nga.giat.geowave.test.GeoWaveITRunner; import mil.nga.giat.geowave.test.TestUtils; import mil.nga.giat.geowave.test.annotation.GeoWaveTestStore; import mil.nga.giat.geowave.test.annotation.GeoWaveTestStore.GeoWaveStoreType; @RunWith(GeoWaveITRunner.class) public class SecondaryIndexIT { @GeoWaveTestStore({ GeoWaveStoreType.ACCUMULO, GeoWaveStoreType.HBASE }) protected DataStorePluginOptions dataStoreOptions; private FeatureDataAdapter dataAdapter; private PrimaryIndex index; private DataStore dataStore; private SecondaryIndexDataStore secondaryDataStore; private List<ByteArrayId> allPrimaryIndexIds = new ArrayList<>(); private List<String> allDataIds = new ArrayList<>(); private int numAttributes; private List<SecondaryIndex<SimpleFeature>> allSecondaryIndices; private DistributableQuery query; private Point expectedPoint; private String expectedDataId; @Test public void testSecondaryIndicesManually() throws AccumuloException, AccumuloSecurityException, TableNotFoundException, ParseException, IOException { Assert.assertTrue(allPrimaryIndexIds.size() == 3); if (dataStoreOptions.getType().equals( "accumulo")) { final AccumuloRequiredOptions options = (AccumuloRequiredOptions) dataStoreOptions.getFactoryOptions(); final Connector connector = ConnectorPool.getInstance().getConnector( options.getZookeeper(), options.getInstance(), options.getUser(), options.getPassword()); numericJoinAccumulo(connector); textJoinAccumulo(connector); temporalJoinAccumulo(connector); numericFullAccumulo(connector); textFullAccumulo(connector); temporalFullAccumulo(connector); numericPartialAccumulo(connector); textPartialAccumulo(connector); temporalPartialAccumulo(connector); } else if (dataStoreOptions.getType().equals( "hbase")) { final HBaseRequiredOptions options = (HBaseRequiredOptions) dataStoreOptions.getFactoryOptions(); final Connection connection = ConnectionPool.getInstance().getConnection( options.getZookeeper()); numericJoinHBase(connection); textJoinHBase(connection); temporalJoinHBase(connection); numericFullHBase(connection); textFullHBase(connection); temporalFullHBase(connection); numericPartialHBase(connection); textPartialHBase(connection); temporalPartialHBase(connection); } } @Test public void testSecondaryIndicesViaDirectQuery() throws IOException { Assert.assertTrue(secondaryDataStore != null); if (dataStoreOptions.getType().equals( "accumulo")) { Assert.assertTrue(secondaryDataStore instanceof AccumuloSecondaryIndexDataStore); } else if (dataStoreOptions.getType().equals( "hbase")) { Assert.assertTrue(secondaryDataStore instanceof HBaseSecondaryIndexDataStore); } Assert.assertTrue(allSecondaryIndices.size() == 9); for (final SecondaryIndex<SimpleFeature> secondaryIndex : allSecondaryIndices) { final List<SimpleFeature> queryResults = new ArrayList<>(); try (final CloseableIterator<SimpleFeature> results = secondaryDataStore.query( secondaryIndex, secondaryIndex.getFieldId(), dataAdapter, index, query, DEFAULT_AUTHORIZATIONS)) { while (results.hasNext()) { queryResults.add(results.next()); } } final int numResults = queryResults.size(); Assert.assertTrue( secondaryIndex.getId().getString() + " returned " + numResults + " results (should have been 1)", numResults == 1); final SimpleFeature result = queryResults.get(0); // verify dataId match Assert.assertTrue(result.getID().equals( expectedDataId)); // verify geometry match Assert.assertTrue(result.getAttribute( GEOMETRY_FIELD).equals( expectedPoint)); } // test delete final Query deleteQuery = new DataIdQuery( dataAdapter.getAdapterId(), new ByteArrayId( expectedDataId)); final QueryOptions queryOptions = new QueryOptions( dataAdapter, index); dataStore.delete( queryOptions, deleteQuery); for (final SecondaryIndex<SimpleFeature> secondaryIndex : allSecondaryIndices) { int numResults = 0; try (final CloseableIterator<SimpleFeature> results = secondaryDataStore.query( secondaryIndex, secondaryIndex.getFieldId(), dataAdapter, index, query, DEFAULT_AUTHORIZATIONS)) { while (results.hasNext()) { numResults++; } } Assert.assertTrue( secondaryIndex.getId().getString() + " returned " + numResults + " results (should have been 0)", numResults == 0); } } private static final String NUMERIC_JOIN_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_NUMERIC_JOIN"; private static final String TEXT_JOIN_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_TEXT_JOIN"; private static final String TEMPORAL_JOIN_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_TEMPORAL_JOIN"; private static final String NUMERIC_FULL_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_NUMERIC_FULL"; private static final String TEXT_FULL_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_TEXT_FULL"; private static final String TEMPORAL_FULL_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_TEMPORAL_FULL"; private static final String NUMERIC_PARTIAL_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_NUMERIC_PARTIAL"; private static final String TEXT_PARTIAL_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_TEXT_PARTIAL"; private static final String TEMPORAL_PARTIAL_TABLE = TestUtils.TEST_NAMESPACE + "_GEOWAVE_2ND_IDX_TEMPORAL_PARTIAL"; private static final String GEOMETRY_FIELD = "geometryField"; private static final String NUMERIC_JOIN_FIELD = "doubleField"; private static final ByteArrayId NUMERIC_JOIN_FIELD_ID = new ByteArrayId( NUMERIC_JOIN_FIELD); private static final String TEMPORAL_JOIN_FIELD = "dateField"; private static final ByteArrayId TEMPORAL_JOIN_FIELD_ID = new ByteArrayId( TEMPORAL_JOIN_FIELD); private static final String TEXT_JOIN_FIELD = "stringField"; private static final ByteArrayId TEXT_JOIN_FIELD_ID = new ByteArrayId( TEXT_JOIN_FIELD); private static final String NUMERIC_FULL_FIELD = "doubleField2"; private static final ByteArrayId NUMERIC_FULL_FIELD_ID = new ByteArrayId( NUMERIC_FULL_FIELD); private static final String TEMPORAL_FULL_FIELD = "dateField2"; private static final ByteArrayId TEMPORAL_FULL_FIELD_ID = new ByteArrayId( TEMPORAL_FULL_FIELD); private static final String TEXT_FULL_FIELD = "stringField2"; private static final ByteArrayId TEXT_FULL_FIELD_ID = new ByteArrayId( TEXT_FULL_FIELD); private static final String NUMERIC_PARTIAL_FIELD = "doubleField3"; private static final ByteArrayId NUMERIC_PARTIAL_FIELD_ID = new ByteArrayId( NUMERIC_PARTIAL_FIELD); private static final String TEMPORAL_PARTIAL_FIELD = "dateField3"; private static final ByteArrayId TEMPORAL_PARTIAL_FIELD_ID = new ByteArrayId( TEMPORAL_PARTIAL_FIELD); private static final String TEXT_PARTIAL_FIELD = "stringField3"; private static final ByteArrayId TEXT_PARTIAL_FIELD_ID = new ByteArrayId( TEXT_PARTIAL_FIELD); private static final DateFormat DATE_FORMAT = new SimpleDateFormat( "dd-MM-yyyy"); private static final ByteArrayId GEOMETRY_FIELD_ID = new ByteArrayId( GeometryAdapter.DEFAULT_GEOMETRY_FIELD_ID.getBytes()); private static final String[] DEFAULT_AUTHORIZATIONS = new String[] {}; private static final Authorizations DEFAULT_ACCUMULO_AUTHORIZATIONS = new Authorizations( DEFAULT_AUTHORIZATIONS); private static final List<String> PARTIAL_LIST = Arrays.asList(StringUtils.stringFromBinary(GEOMETRY_FIELD_ID .getBytes())); @Before public void initTest() throws SchemaException, MismatchedIndexToAdapterMapping, IOException, ParseException { // mark attributes for secondary indexing final List<SimpleFeatureUserDataConfiguration> configs = new ArrayList<>(); // JOIN configs.add(new NumericSecondaryIndexConfiguration( NUMERIC_JOIN_FIELD, SecondaryIndexType.JOIN)); configs.add(new TemporalSecondaryIndexConfiguration( TEMPORAL_JOIN_FIELD, SecondaryIndexType.JOIN)); configs.add(new TextSecondaryIndexConfiguration( TEXT_JOIN_FIELD, SecondaryIndexType.JOIN)); // FULL configs.add(new NumericSecondaryIndexConfiguration( NUMERIC_FULL_FIELD, SecondaryIndexType.FULL)); configs.add(new TemporalSecondaryIndexConfiguration( TEMPORAL_FULL_FIELD, SecondaryIndexType.FULL)); configs.add(new TextSecondaryIndexConfiguration( TEXT_FULL_FIELD, SecondaryIndexType.FULL)); // PARTIAL configs.add(new NumericSecondaryIndexConfiguration( NUMERIC_PARTIAL_FIELD, SecondaryIndexType.PARTIAL, PARTIAL_LIST)); configs.add(new TemporalSecondaryIndexConfiguration( TEMPORAL_PARTIAL_FIELD, SecondaryIndexType.PARTIAL, PARTIAL_LIST)); configs.add(new TextSecondaryIndexConfiguration( TEXT_PARTIAL_FIELD, SecondaryIndexType.PARTIAL, PARTIAL_LIST)); // update schema with configs final SimpleFeatureType schema = DataUtilities.createType( "record", GEOMETRY_FIELD + ":Geometry," + NUMERIC_JOIN_FIELD + ":Double," + NUMERIC_FULL_FIELD + ":Double," + NUMERIC_PARTIAL_FIELD + ":Double," + TEMPORAL_JOIN_FIELD + ":Date," + TEMPORAL_FULL_FIELD + ":Date," + TEMPORAL_PARTIAL_FIELD + ":Date," + TEXT_JOIN_FIELD + ":String," + TEXT_FULL_FIELD + ":String," + TEXT_PARTIAL_FIELD + ":String"); numAttributes = schema.getAttributeCount(); final SimpleFeatureUserDataConfigurationSet config = new SimpleFeatureUserDataConfigurationSet( schema, configs); config.updateType(schema); // build features final SimpleFeatureBuilder builder = new SimpleFeatureBuilder( schema); final List<SimpleFeature> features = new ArrayList<>(); features.add(buildSimpleFeature( builder, -180d, -90d, DATE_FORMAT.parse("11-11-2012"), 1d, "aaa")); features.add(buildSimpleFeature( builder, 0d, 0d, DATE_FORMAT.parse("11-30-2013"), 10d, "bbb")); // Create a feature and collect verification data from it final SimpleFeature feat = buildSimpleFeature( builder, 180d, 90d, DATE_FORMAT.parse("12-25-2015"), 100d, "ccc"); expectedPoint = (Point) feat.getAttribute(GEOMETRY_FIELD); expectedDataId = feat.getID(); features.add(feat); // ingest data dataStore = dataStoreOptions.createDataStore(); secondaryDataStore = dataStoreOptions.createSecondaryIndexStore(); secondaryDataStore.setDataStore(dataStore); dataAdapter = new FeatureDataAdapter( schema); index = TestUtils.DEFAULT_SPATIAL_INDEX; try (@SuppressWarnings("unchecked") final IndexWriter<SimpleFeature> writer = dataStore.createWriter( dataAdapter, index)) { for (final SimpleFeature aFeature : features) { allPrimaryIndexIds.addAll(writer.write(aFeature)); } } allSecondaryIndices = dataAdapter.getSupportedSecondaryIndices(); final Map<ByteArrayId, FilterableConstraints> additionalConstraints = new HashMap<>(); final Number number = 25d; additionalConstraints.put( NUMERIC_JOIN_FIELD_ID, new NumericGreaterThanConstraint( NUMERIC_JOIN_FIELD_ID, number)); additionalConstraints.put( NUMERIC_FULL_FIELD_ID, new NumericGreaterThanConstraint( NUMERIC_FULL_FIELD_ID, number)); additionalConstraints.put( NUMERIC_PARTIAL_FIELD_ID, new NumericGreaterThanConstraint( NUMERIC_PARTIAL_FIELD_ID, number)); final String matchValue = "ccc"; additionalConstraints.put( TEXT_JOIN_FIELD_ID, new TextQueryConstraint( TEXT_JOIN_FIELD_ID, matchValue, true)); additionalConstraints.put( TEXT_FULL_FIELD_ID, new TextQueryConstraint( TEXT_FULL_FIELD_ID, matchValue, true)); additionalConstraints.put( TEXT_PARTIAL_FIELD_ID, new TextQueryConstraint( TEXT_PARTIAL_FIELD_ID, matchValue, true)); final Date start = DATE_FORMAT.parse("12-24-2015"); final Date end = DATE_FORMAT.parse("12-26-2015"); additionalConstraints.put( TEMPORAL_JOIN_FIELD_ID, new TemporalQueryConstraint( TEMPORAL_JOIN_FIELD_ID, start, end)); additionalConstraints.put( TEMPORAL_FULL_FIELD_ID, new TemporalQueryConstraint( TEMPORAL_FULL_FIELD_ID, start, end)); additionalConstraints.put( TEMPORAL_PARTIAL_FIELD_ID, new TemporalQueryConstraint( TEMPORAL_PARTIAL_FIELD_ID, start, end)); query = new SpatialQuery( GeometryUtils.GEOMETRY_FACTORY.toGeometry(new Envelope( -180d, 180d, -90d, 90d)), additionalConstraints); } /** * * @throws IOException */ @After public void deleteTestData() throws IOException { TestUtils.deleteAll(dataStoreOptions); } /** * * @param connector * @throws TableNotFoundException */ private void numericJoinAccumulo( final Connector connector ) throws TableNotFoundException { final Scanner scanner = connector.createScanner( NUMERIC_JOIN_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( Lexicoders.DOUBLE.toByteArray(0d)), new Text( Lexicoders.DOUBLE.toByteArray(20d)))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), NUMERIC_JOIN_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final ByteArrayId primaryRowId = SecondaryIndexUtils.getPrimaryRowId(entry .getKey() .getColumnQualifierData() .getBackingArray()); if (numResults == 1) { Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(0))); } else if (numResults == 2) { Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(1))); } } scanner.close(); Assert.assertTrue(numResults == 2); } private void numericJoinHBase( final Connection connection ) throws IOException { final Table table = connection.getTable(TableName.valueOf((NUMERIC_JOIN_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), NUMERIC_JOIN_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(Lexicoders.DOUBLE.toByteArray(0d)); scan.setStopRow(Lexicoders.DOUBLE.toByteArray(20d)); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == 1); for (final Entry<byte[], byte[]> entry : entries) { final ByteArrayId primaryRowId = SecondaryIndexUtils.getPrimaryRowId(entry.getKey()); if (numResults == 1) { Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(0))); } else if (numResults == 2) { Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(1))); } } } table.close(); Assert.assertTrue(numResults == 2); } private void textJoinAccumulo( final Connector connector ) throws TableNotFoundException { final Scanner scanner = connector.createScanner( TEXT_JOIN_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( new ByteArrayId( "bbb").getBytes()))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEXT_JOIN_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final ByteArrayId primaryRowId = SecondaryIndexUtils.getPrimaryRowId(entry .getKey() .getColumnQualifierData() .getBackingArray()); Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(1))); } scanner.close(); Assert.assertTrue(numResults == 1); } private void textJoinHBase( final Connection connection ) throws IOException { final Table table = connection.getTable(TableName.valueOf((TEXT_JOIN_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEXT_JOIN_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(new ByteArrayId( "bbb").getBytes()); scan.setStopRow(new ByteArrayId( "bbb").getBytes()); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == 1); for (final Entry<byte[], byte[]> entry : entries) { final ByteArrayId primaryRowId = SecondaryIndexUtils.getPrimaryRowId(entry.getKey()); Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(1))); } } table.close(); Assert.assertTrue(numResults == 1); } private void temporalJoinAccumulo( final Connector connector ) throws TableNotFoundException, ParseException { final Scanner scanner = connector.createScanner( TEMPORAL_JOIN_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); Text startText = new Text( Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2012").getTime())); Text stopText = new Text( Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2014").getTime())); scanner.setRange(new Range( startText, stopText)); byte[] colFam = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEMPORAL_JOIN_FIELD_ID); scanner.fetchColumnFamily(new Text( colFam)); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final ByteArrayId primaryRowId = SecondaryIndexUtils.getPrimaryRowId(entry .getKey() .getColumnQualifierData() .getBackingArray()); Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(1))); } scanner.close(); Assert.assertTrue(numResults == 1); } private void temporalJoinHBase( final Connection connection ) throws IOException, ParseException { final Table table = connection.getTable(TableName.valueOf((TEMPORAL_JOIN_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEMPORAL_JOIN_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2012").getTime())); scan.setStopRow(Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2014").getTime())); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == 1); for (final Entry<byte[], byte[]> entry : entries) { final ByteArrayId primaryRowId = SecondaryIndexUtils.getPrimaryRowId(entry.getKey()); Assert.assertTrue(primaryRowId.equals(allPrimaryIndexIds.get(1))); } } table.close(); Assert.assertTrue(numResults == 1); } private void numericFullAccumulo( final Connector connector ) throws TableNotFoundException { final Scanner scanner = connector.createScanner( NUMERIC_FULL_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( Lexicoders.DOUBLE.toByteArray(0d)), new Text( Lexicoders.DOUBLE.toByteArray(20d)))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), NUMERIC_FULL_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { final String dataId = SecondaryIndexUtils.getDataId(entry .getKey() .getColumnQualifierData() .getBackingArray()); if ((numResults / numAttributes) == 0) { Assert.assertTrue(dataId.equals(allDataIds.get(0))); } else if ((numResults / numAttributes) == 1) { Assert.assertTrue(dataId.equals(allDataIds.get(1))); } numResults += 1; } scanner.close(); Assert.assertTrue(numResults == (2 * numAttributes)); } private void numericFullHBase( final Connection connection ) throws IOException { final Table table = connection.getTable(TableName.valueOf((NUMERIC_FULL_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), NUMERIC_FULL_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(Lexicoders.DOUBLE.toByteArray(0d)); scan.setStopRow(Lexicoders.DOUBLE.toByteArray(20d)); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == numAttributes); for (final Entry<byte[], byte[]> entry : entries) { final String dataId = SecondaryIndexUtils.getDataId(entry.getKey()); Assert.assertTrue((dataId.equals(allDataIds.get(0))) || (dataId.equals(allDataIds.get(1)))); } } table.close(); Assert.assertTrue(numResults == 2); } private void textFullAccumulo( final Connector connector ) throws TableNotFoundException { final Scanner scanner = connector.createScanner( TEXT_FULL_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( new ByteArrayId( "bbb").getBytes()))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEXT_FULL_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final String dataId = SecondaryIndexUtils.getDataId(entry .getKey() .getColumnQualifierData() .getBackingArray()); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } scanner.close(); Assert.assertTrue(numResults == numAttributes); } private void textFullHBase( final Connection connection ) throws IOException { final Table table = connection.getTable(TableName.valueOf((TEXT_FULL_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEXT_FULL_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(new ByteArrayId( "bbb").getBytes()); scan.setStopRow(new ByteArrayId( "bbb").getBytes()); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == numAttributes); for (final Entry<byte[], byte[]> entry : entries) { final String dataId = SecondaryIndexUtils.getDataId(entry.getKey()); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } } table.close(); Assert.assertTrue(numResults == 1); } private void temporalFullAccumulo( final Connector connector ) throws TableNotFoundException, ParseException { final Scanner scanner = connector.createScanner( TEMPORAL_FULL_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2012").getTime())), new Text( Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2014").getTime())))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEMPORAL_FULL_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final String dataId = SecondaryIndexUtils.getDataId(entry .getKey() .getColumnQualifierData() .getBackingArray()); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } scanner.close(); Assert.assertTrue(numResults == numAttributes); } private void temporalFullHBase( final Connection connection ) throws IOException, ParseException { final Table table = connection.getTable(TableName.valueOf((TEMPORAL_FULL_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEMPORAL_FULL_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2012").getTime())); scan.setStopRow(Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2014").getTime())); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == numAttributes); for (final Entry<byte[], byte[]> entry : entries) { final String dataId = SecondaryIndexUtils.getDataId(entry.getKey()); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } } table.close(); Assert.assertTrue(numResults == 1); } private void numericPartialAccumulo( final Connector connector ) throws TableNotFoundException { final Scanner scanner = connector.createScanner( NUMERIC_PARTIAL_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( Lexicoders.DOUBLE.toByteArray(0d)), new Text( Lexicoders.DOUBLE.toByteArray(20d)))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), NUMERIC_PARTIAL_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final byte[] cq = entry.getKey().getColumnQualifierData().getBackingArray(); final ByteArrayId fieldId = SecondaryIndexUtils.getFieldId(cq); Assert.assertTrue(fieldId.equals(GEOMETRY_FIELD_ID)); final String dataId = SecondaryIndexUtils.getDataId(entry .getKey() .getColumnQualifierData() .getBackingArray()); if (numResults == 1) { Assert.assertTrue(dataId.equals(allDataIds.get(0))); } else if (numResults == 2) { Assert.assertTrue(dataId.equals(allDataIds.get(1))); } } scanner.close(); Assert.assertTrue(numResults == 2); } private void numericPartialHBase( final Connection connection ) throws IOException { final Table table = connection.getTable(TableName.valueOf((NUMERIC_PARTIAL_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), NUMERIC_PARTIAL_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(Lexicoders.DOUBLE.toByteArray(0d)); scan.setStopRow(Lexicoders.DOUBLE.toByteArray(20d)); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == 1); for (final Entry<byte[], byte[]> entry : entries) { final byte[] cq = entry.getKey(); final ByteArrayId fieldId = SecondaryIndexUtils.getFieldId(cq); Assert.assertTrue(fieldId.equals(GEOMETRY_FIELD_ID)); final String dataId = SecondaryIndexUtils.getDataId(cq); Assert.assertTrue((dataId.equals(allDataIds.get(0))) || (dataId.equals(allDataIds.get(1)))); } } table.close(); Assert.assertTrue(numResults == 2); } private void textPartialAccumulo( final Connector connector ) throws TableNotFoundException { final Scanner scanner = connector.createScanner( TEXT_PARTIAL_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( new ByteArrayId( "bbb").getBytes()))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEXT_PARTIAL_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final byte[] cq = entry.getKey().getColumnQualifierData().getBackingArray(); final ByteArrayId fieldId = SecondaryIndexUtils.getFieldId(cq); Assert.assertTrue(fieldId.equals(GEOMETRY_FIELD_ID)); final String dataId = SecondaryIndexUtils.getDataId(cq); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } scanner.close(); Assert.assertTrue(numResults == 1); } private void textPartialHBase( final Connection connection ) throws IOException { final Table table = connection.getTable(TableName.valueOf((TEXT_PARTIAL_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEXT_PARTIAL_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(new ByteArrayId( "bbb").getBytes()); scan.setStopRow(new ByteArrayId( "bbb").getBytes()); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == 1); for (final Entry<byte[], byte[]> entry : entries) { final byte[] cq = entry.getKey(); final ByteArrayId fieldId = SecondaryIndexUtils.getFieldId(cq); Assert.assertTrue(fieldId.equals(GEOMETRY_FIELD_ID)); final String dataId = SecondaryIndexUtils.getDataId(cq); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } } table.close(); Assert.assertTrue(numResults == 1); } private void temporalPartialAccumulo( final Connector connector ) throws TableNotFoundException, ParseException { final Scanner scanner = connector.createScanner( TEMPORAL_PARTIAL_TABLE, DEFAULT_ACCUMULO_AUTHORIZATIONS); scanner.setRange(new Range( new Text( Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2012").getTime())), new Text( Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2014").getTime())))); scanner.fetchColumnFamily(new Text( SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEMPORAL_PARTIAL_FIELD_ID))); int numResults = 0; for (final Entry<Key, Value> entry : scanner) { numResults += 1; final byte[] cq = entry.getKey().getColumnQualifierData().getBackingArray(); final ByteArrayId fieldId = SecondaryIndexUtils.getFieldId(cq); Assert.assertTrue(fieldId.equals(GEOMETRY_FIELD_ID)); final String dataId = SecondaryIndexUtils.getDataId(cq); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } scanner.close(); Assert.assertTrue(numResults == 1); } private void temporalPartialHBase( final Connection connection ) throws IOException, ParseException { final Table table = connection.getTable(TableName.valueOf((TEMPORAL_PARTIAL_TABLE))); final Scan scan = new Scan(); final byte[] columnFamily = SecondaryIndexUtils.constructColumnFamily( dataAdapter.getAdapterId(), TEMPORAL_PARTIAL_FIELD_ID); scan.addFamily(columnFamily); scan.setStartRow(Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2012").getTime())); scan.setStopRow(Lexicoders.LONG.toByteArray(DATE_FORMAT.parse( "11-30-2014").getTime())); final ResultScanner results = table.getScanner(scan); int numResults = 0; for (final Result result : results) { numResults += 1; final NavigableMap<byte[], byte[]> qualifierToValueMap = result.getFamilyMap(columnFamily); final Set<Entry<byte[], byte[]>> entries = qualifierToValueMap.entrySet(); Assert.assertTrue(entries.size() == 1); for (final Entry<byte[], byte[]> entry : entries) { final byte[] cq = entry.getKey(); final ByteArrayId fieldId = SecondaryIndexUtils.getFieldId(cq); Assert.assertTrue(fieldId.equals(GEOMETRY_FIELD_ID)); final String dataId = SecondaryIndexUtils.getDataId(cq); Assert.assertTrue(dataId.equals(allDataIds.get(1))); } } table.close(); Assert.assertTrue(numResults == 1); } /** * * @param builder * SimpleFeature builder to be used * @param lng * - coordinate longitude * @param lat * - coordinate latitude * @param dateField * - * @param doubleField * @param stringField * @return */ private SimpleFeature buildSimpleFeature( final SimpleFeatureBuilder builder, final double lng, final double lat, final Date dateField, final double doubleField, final String stringField ) { builder.set( GEOMETRY_FIELD, GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate( lng, lat))); builder.set( TEMPORAL_JOIN_FIELD, dateField); builder.set( TEMPORAL_FULL_FIELD, dateField); builder.set( TEMPORAL_PARTIAL_FIELD, dateField); builder.set( NUMERIC_JOIN_FIELD, doubleField); builder.set( NUMERIC_FULL_FIELD, doubleField); builder.set( NUMERIC_PARTIAL_FIELD, doubleField); builder.set( TEXT_JOIN_FIELD, stringField); builder.set( TEXT_FULL_FIELD, stringField); builder.set( TEXT_PARTIAL_FIELD, stringField); final String dataId = UUID.randomUUID().toString(); allDataIds.add(dataId); return builder.buildFeature(dataId); } }