He estado probando algunas soluciones para convertir de forma eficiente GeoJSON en un archivo shapefile sin tener que almacenar todas las características en la memoria. Estoy utilizando GeoTools 9.2.
El problema no está tanto en cómo transmitir el JSON sino en cómo escribir eficientemente las características en el shapefile. Utilizo FeatureJSON#streamFeatureCollection para obtener un iterador. Después de googling, he encontrado 3 maneras diferentes de escribir un shapefile, a saber:
Opción 1 : Llamar repetidamente a FeatureStore#addFeatures con una colección que contiene digamos 1000 características, dentro de una transacción.
ListFeatureCollection coll = new ListFeatureCollection(type, features);
Transaction transaction = new DefaultTransaction("create");
featureStore.setTransaction(transaction);
try {
featureStore.addFeatures(coll);
transaction.commit();
} catch (IOException e) {
transaction.rollback();
throw new IllegalStateException(
"Could not write some features to shapefile. Aborting process", e);
} finally {
transaction.close();
}
Esta opción es extremadamente lenta. Haciendo un perfil de algunas ejecuciones, noté que alrededor del 50% del tiempo de CPU se gasta en el método ContentFeatureStore#getWriterAppend, presumiblemente con el fin de alcanzar el final del archivo antes de cada transacción.
Opción 2 : Obtener un escritor append directamente de ShapefileDataStore, y escribir 1000 características a la vez dentro de una transacción.
Esta opción adolece de los mismos problemas que la número uno.
Opción 3 : Obtener un escritor de características de ShapefileDataStore, y escribir una característica a la vez usando Transaction.AUTO_COMMIT.
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = shpDataStore
.getFeatureWriter(shpDataStore.getTypeNames()[0],
Transaction.AUTO_COMMIT);
while (jsonIt.hasNext()) {
SimpleFeature feature = jsonIt.next();
SimpleFeature toWrite = writer.next();
for (int i = 0; i < toWrite.getType().getAttributeCount(); i++) {
String name = toWrite.getType().getDescriptor(i).getLocalName();
toWrite.setAttribute(name, feature.getAttribute(name));
}
writer.write();
}
writer.close();
La opción 3 es la más rápida, pero creo que habría una manera de eficientemente añadir un mayor número de características a la vez al shapefile dentro de una transacción.
Por otra parte, un comentario anterior en la lista de correo de GeoTools señalaba:
Lo anterior funcionaría para transferencias de datos medianas, para masivas contra bases de datos es mejor adoptar algún tipo de batching para evitar tener una única transacción con un millón de inserciones, por ejemplo, insertar 1000, confirmar la transacción, insertar otros 1000, y así sucesivamente. Este funcionaría mejor contra bases de datos y contra servidores WFS, pero no contra archivos shape que en cambio funcionan mejor con el masivo inserción... cada uno a lo suyo.
¿Significa esto que la forma más eficiente de escribir en un shapefile es tener todas las características en la memoria, en lugar de ser capaz de añadir características?