All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.locationtech.geowave.examples.index.CustomIndexExample Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2013-2022 Contributors to the Eclipse Foundation
 *
 * 

See the NOTICE file distributed with this work for additional information regarding copyright * ownership. All rights reserved. This program and the accompanying materials are made available * under the terms of the Apache License, Version 2.0 which accompanies this distribution and is * available at http://www.apache.org/licenses/LICENSE-2.0.txt */ package org.locationtech.geowave.examples.index; import java.io.IOException; import java.util.UUID; import org.geotools.feature.AttributeTypeBuilder; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.filter.text.cql2.CQLException; import org.locationtech.geowave.adapter.vector.FeatureDataAdapter; import org.locationtech.geowave.core.geotime.index.api.SpatialIndexBuilder; import org.locationtech.geowave.core.geotime.store.query.api.VectorQueryBuilder; import org.locationtech.geowave.core.geotime.util.GeometryUtils; import org.locationtech.geowave.core.index.ByteArrayRange; import org.locationtech.geowave.core.index.CustomIndexStrategy; import org.locationtech.geowave.core.index.InsertionIds; import org.locationtech.geowave.core.index.QueryRanges; import org.locationtech.geowave.core.index.StringUtils; import org.locationtech.geowave.core.index.persist.Persistable; import org.locationtech.geowave.core.store.CloseableIterator; import org.locationtech.geowave.core.store.api.DataStore; import org.locationtech.geowave.core.store.api.DataStoreFactory; import org.locationtech.geowave.core.store.api.Index; import org.locationtech.geowave.core.store.api.Writer; import org.locationtech.geowave.core.store.index.CustomIndex; import org.locationtech.geowave.core.store.memory.MemoryRequiredOptions; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import com.google.common.collect.Lists; /** * This class is intended to provide a self-contained, easy-to-follow example of how a custom index * can be created. In this example, we will create a UUID index that can be used alongside a spatial * index in order to efficiently query features by a String UUID field that each feature has. */ public class CustomIndexExample { private DataStore dataStore; private SimpleFeatureType simpleFeatureType; private FeatureDataAdapter adapter; private Index spatialIndex; private Index customIndex; private final String uuid1 = UUID.randomUUID().toString(); private final String uuid2 = UUID.randomUUID().toString(); private final String uuid3 = UUID.randomUUID().toString(); private final String uuid4 = UUID.randomUUID().toString(); public static void main(final String[] args) throws IOException, CQLException { final CustomIndexExample example = new CustomIndexExample(); example.run(); } public void run() { // Create an in-memory data store to use with this example dataStore = DataStoreFactory.createDataStore(new MemoryRequiredOptions()); // Create the simple feature type for our data simpleFeatureType = getSimpleFeatureType(); // Create an adapter for our features adapter = new FeatureDataAdapter(simpleFeatureType); // Create the spatial index spatialIndex = new SpatialIndexBuilder().createIndex(); // Create our custom index using the UUID index strategy customIndex = new CustomIndex<>(new UUIDIndexStrategy("uuid"), "customIdx"); // Add the type to the data store with the spatial and custom indices dataStore.addType(adapter, spatialIndex, customIndex); // Ingest the data into a spatial index and our custom index ingestData(); // Perform a spatial query on the data querySpatial(); // Perform a UUID query on the data queryUUID(); } public void ingestData() { try (Writer writer = dataStore.createWriter(adapter.getTypeName())) { writer.write(buildSimpleFeature("feature1", new Coordinate(0, 0), uuid1)); writer.write(buildSimpleFeature("feature2", new Coordinate(1, 1), uuid2)); writer.write(buildSimpleFeature("feature3", new Coordinate(2, 2), uuid3)); writer.write(buildSimpleFeature("feature4", new Coordinate(3, 3), uuid4)); // Entries with the same UUID will be placed next to each other in the index writer.write(buildSimpleFeature("feature5", new Coordinate(4, 4), uuid2)); } } public void querySpatial() { System.out.println("Executing query, expecting to match feature2, feature3, and feature4..."); final VectorQueryBuilder bldr = VectorQueryBuilder.newBuilder(); try (final CloseableIterator iterator = dataStore.query( bldr.indexName(spatialIndex.getName()).addTypeName(adapter.getTypeName()).constraints( bldr.constraintsFactory().cqlConstraints( "BBOX(geometry,0.5,0.5,3.5,3.5)")).build())) { while (iterator.hasNext()) { System.out.println("Query match: " + iterator.next().getID()); } } } public void queryUUID() { System.out.println("Executing query, expecting to match feature1 with UUID [" + uuid1 + "]..."); VectorQueryBuilder bldr = VectorQueryBuilder.newBuilder(); // When querying our custom index, we can provide our custom constraints by using the // customConstraints function on the constraints factory. try (final CloseableIterator iterator = dataStore.query( bldr.indexName(customIndex.getName()).addTypeName(adapter.getTypeName()).constraints( bldr.constraintsFactory().customConstraints(new UUIDConstraints(uuid1))).build())) { while (iterator.hasNext()) { System.out.println("Query match: " + iterator.next().getID()); } } System.out.println( "Executing query, expecting to match feature2 and feature5 with UUID [" + uuid2 + "]..."); bldr = VectorQueryBuilder.newBuilder(); try (final CloseableIterator iterator = dataStore.query( bldr.indexName(customIndex.getName()).addTypeName(adapter.getTypeName()).constraints( bldr.constraintsFactory().customConstraints(new UUIDConstraints(uuid2))).build())) { while (iterator.hasNext()) { System.out.println("Query match: " + iterator.next().getID()); } } } private SimpleFeatureType getSimpleFeatureType() { final String NAME = "ExampleType"; final SimpleFeatureTypeBuilder sftBuilder = new SimpleFeatureTypeBuilder(); final AttributeTypeBuilder atBuilder = new AttributeTypeBuilder(); sftBuilder.setName(NAME); sftBuilder.add(atBuilder.binding(Geometry.class).nillable(false).buildDescriptor("geometry")); sftBuilder.add(atBuilder.binding(String.class).nillable(false).buildDescriptor("uuid")); return sftBuilder.buildFeatureType(); } private SimpleFeature buildSimpleFeature( final String featureId, final Coordinate coordinate, final String uuid) { final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(simpleFeatureType); builder.set("geometry", GeometryUtils.GEOMETRY_FACTORY.createPoint(coordinate)); builder.set("uuid", uuid); return builder.buildFeature(featureId); } /** * This index strategy will index data by using an attribute of a simple feature as the sort key * in the index. This implementation allows the user to supply the field name for the UUID field * to offer some flexibility. */ public static class UUIDIndexStrategy implements CustomIndexStrategy { private String uuidField; public UUIDIndexStrategy() {} public UUIDIndexStrategy(final String uuidField) { this.uuidField = uuidField; } /** * Store any data needed to persist this index strategy. */ @Override public byte[] toBinary() { return StringUtils.stringToBinary(uuidField); } /** * Load the index strategy UUID field from binary. */ @Override public void fromBinary(final byte[] bytes) { uuidField = StringUtils.stringFromBinary(bytes); } /** * The method supplies all of the insertion IDs needed for a given entry. It is possible to * insert the same SimpleFeature multiple times in the index under different insertion IDs, but * for this case we only need to use the UUID as the lone insertion ID. * * @param entry the feature to generate sort keys for. * @return the insertion IDs for the given feature */ @Override public InsertionIds getInsertionIds(final SimpleFeature entry) { final String featureUUID = (String) entry.getAttribute(uuidField); return new InsertionIds(Lists.newArrayList(StringUtils.stringToBinary(featureUUID))); } /** * This method generates the query ranges to be used by the data store implementation to * retrieve features from the database. For this example, we are only interested in querying for * an exact UUID, so we can simply use the desired UUID as the query range. */ @Override public QueryRanges getQueryRanges(final UUIDConstraints constraints) { final byte[] sortKey = StringUtils.stringToBinary(constraints.uuid()); return new QueryRanges(new ByteArrayRange(sortKey, sortKey)); } @Override public Class getConstraintsClass() { return UUIDConstraints.class; } } /** * This class serves as constraints for our UUID index strategy. Since we only need to query for * exact UUIDs, the constraints class is fairly straightforward. We only need a single UUID String * to use as our constraint. */ public static class UUIDConstraints implements Persistable { private String uuid; public UUIDConstraints() {} public UUIDConstraints(final String uuid) { this.uuid = uuid; } public String uuid() { return uuid; } /** * Serialize any data needed to persist this constraint. */ @Override public byte[] toBinary() { return StringUtils.stringToBinary(uuid); } /** * Load the UUID constraint from binary. */ @Override public void fromBinary(final byte[] bytes) { uuid = StringUtils.stringFromBinary(bytes); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy