Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Index Configuration Feature to Neo4j Spatial #410

Merged
merged 1 commit into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,6 @@
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>${geotools.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geotools.xsd</groupId>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/neo4j/gis/spatial/ShapefileImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public List<Node> importFile(String dataset, String layerName, Charset charset)
EditableLayerImpl layer;
try (Transaction tx = database.beginTx()) {
layer = (EditableLayerImpl) spatialDatabase.getOrCreateLayer(tx, layerName, WKBGeometryEncoder.class,
layerClass);
layerClass, null);
tx.commit();
}
return importFile(dataset, layer, charset);
Expand Down
109 changes: 67 additions & 42 deletions src/main/java/org/neo4j/gis/spatial/SpatialDatabaseService.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
*/
public class SpatialDatabaseService implements Constants {

public static final String RTREE_INDEX_NAME = "rtree";
public static final String GEOHASH_INDEX_NAME = "geohash";

public final IndexManager indexManager;

public SpatialDatabaseService(IndexManager indexManager) {
Expand Down Expand Up @@ -178,30 +181,29 @@ public DynamicLayer asDynamicLayer(Transaction tx, Layer layer) {
return (DynamicLayer) LayerUtilities.makeLayerFromNode(tx, indexManager, node);
}

public DefaultLayer getOrCreateDefaultLayer(Transaction tx, String name) {
return (DefaultLayer) getOrCreateLayer(tx, name, WKBGeometryEncoder.class, EditableLayerImpl.class, "");
public DefaultLayer getOrCreateDefaultLayer(Transaction tx, String name, String indexConfig) {
return (DefaultLayer) getOrCreateLayer(tx, name, WKBGeometryEncoder.class, EditableLayerImpl.class, "",
indexConfig);
}

public EditableLayer getOrCreateEditableLayer(Transaction tx, String name, String format,
String propertyNameConfig) {
public EditableLayer getOrCreateEditableLayer(Transaction tx, String name, String format, String propertyNameConfig,
String indexConfig) {
Class<? extends GeometryEncoder> geClass = WKBGeometryEncoder.class;
if (format != null && format.toUpperCase().startsWith("WKT")) {
geClass = WKTGeometryEncoder.class;
}
return (EditableLayer) getOrCreateLayer(tx, name, geClass, EditableLayerImpl.class, propertyNameConfig);
return (EditableLayer) getOrCreateLayer(tx, name, geClass, EditableLayerImpl.class, propertyNameConfig,
indexConfig);
}

public EditableLayer getOrCreateEditableLayer(Transaction tx, String name) {
return getOrCreateEditableLayer(tx, name, "WKB", "");
public EditableLayer getOrCreateEditableLayer(Transaction tx, String name, String indexConfig) {
return getOrCreateEditableLayer(tx, name, "WKB", "", indexConfig);
}

public EditableLayer getOrCreateEditableLayer(Transaction tx, String name, String wktProperty) {
return getOrCreateEditableLayer(tx, name, "WKT", wktProperty);
public EditableLayer getOrCreateEditableLayer(Transaction tx, String name, String wktProperty, String indexConfig) {
return getOrCreateEditableLayer(tx, name, "WKT", wktProperty, indexConfig);
}

public static final String RTREE_INDEX_NAME = "rtree";
public static final String GEOHASH_INDEX_NAME = "geohash";

public static Class<? extends LayerIndexReader> resolveIndexClass(String index) {
if (index == null) {
return LayerRTreeIndex.class;
Expand All @@ -216,23 +218,25 @@ public static Class<? extends LayerIndexReader> resolveIndexClass(String index)
}

public EditableLayer getOrCreateSimplePointLayer(Transaction tx, String name, String index, String xProperty,
String yProperty) {
return getOrCreatePointLayer(tx, name, resolveIndexClass(index), SimplePointEncoder.class, xProperty,
String yProperty, String indexConfig) {
return getOrCreatePointLayer(tx, name, resolveIndexClass(index), SimplePointEncoder.class, indexConfig,
xProperty,
yProperty);
}

public EditableLayer getOrCreateNativePointLayer(Transaction tx, String name, String index,
String locationProperty) {
return getOrCreatePointLayer(tx, name, resolveIndexClass(index), SimplePointEncoder.class, locationProperty);
String locationProperty, String indexConfig) {
return getOrCreatePointLayer(tx, name, resolveIndexClass(index), SimplePointEncoder.class, indexConfig,
locationProperty);
}

public EditableLayer getOrCreatePointLayer(Transaction tx, String name,
Class<? extends LayerIndexReader> indexClass, Class<? extends GeometryEncoder> encoderClass,
String... encoderConfig) {
String indexConfig, String... encoderConfig) {
Layer layer = getLayer(tx, name);
if (layer == null) {
return (EditableLayer) createLayer(tx, name, encoderClass, SimplePointLayer.class, indexClass,
makeEncoderConfig(encoderConfig), DefaultGeographicCRS.WGS84);
makeEncoderConfig(encoderConfig), indexConfig, DefaultGeographicCRS.WGS84);
}
if (layer instanceof EditableLayer) {
return (EditableLayer) layer;
Expand All @@ -242,10 +246,10 @@ public EditableLayer getOrCreatePointLayer(Transaction tx, String name,
}

public Layer getOrCreateLayer(Transaction tx, String name, Class<? extends GeometryEncoder> geometryEncoder,
Class<? extends Layer> layerClass, String config) {
Class<? extends Layer> layerClass, String encoderConfig, String indexConfig) {
Layer layer = getLayer(tx, name);
if (layer == null) {
layer = createLayer(tx, name, geometryEncoder, layerClass, null, config);
layer = createLayer(tx, name, geometryEncoder, layerClass, null, encoderConfig, indexConfig);
} else if (!(layerClass == null || layerClass.isInstance(layer))) {
throw new SpatialDatabaseException(
"Existing layer '" + layer + "' is not of the expected type: " + layerClass);
Expand All @@ -254,8 +258,8 @@ public Layer getOrCreateLayer(Transaction tx, String name, Class<? extends Geome
}

public Layer getOrCreateLayer(Transaction tx, String name, Class<? extends GeometryEncoder> geometryEncoder,
Class<? extends Layer> layerClass) {
return getOrCreateLayer(tx, name, geometryEncoder, layerClass, "");
Class<? extends Layer> layerClass, String indexConfig) {
return getOrCreateLayer(tx, name, geometryEncoder, layerClass, "", indexConfig);
}

/**
Expand Down Expand Up @@ -298,8 +302,8 @@ public boolean containsLayer(Transaction tx, String name) {
return getLayer(tx, name) != null;
}

public Layer createWKBLayer(Transaction tx, String name) {
return createLayer(tx, name, WKBGeometryEncoder.class, EditableLayerImpl.class);
public Layer createWKBLayer(Transaction tx, String name, String indexConfig) {
return createLayer(tx, name, WKBGeometryEncoder.class, EditableLayerImpl.class, indexConfig);
}

public SimplePointLayer createSimplePointLayer(Transaction tx, String name) {
Expand All @@ -311,7 +315,7 @@ public SimplePointLayer createSimplePointLayer(Transaction tx, String name, Stri
}

public SimplePointLayer createSimplePointLayer(Transaction tx, String name, String... xybProperties) {
return createPointLayer(tx, name, LayerRTreeIndex.class, SimplePointEncoder.class, xybProperties);
return createPointLayer(tx, name, LayerRTreeIndex.class, SimplePointEncoder.class, null, xybProperties);
}

public SimplePointLayer createNativePointLayer(Transaction tx, String name) {
Expand All @@ -324,13 +328,14 @@ public SimplePointLayer createNativePointLayer(Transaction tx, String name, Stri
}

public SimplePointLayer createNativePointLayer(Transaction tx, String name, String... encoderConfig) {
return createPointLayer(tx, name, LayerRTreeIndex.class, NativePointEncoder.class, encoderConfig);
return createPointLayer(tx, name, LayerRTreeIndex.class, NativePointEncoder.class, null, encoderConfig);
}

public SimplePointLayer createPointLayer(Transaction tx, String name, Class<? extends LayerIndexReader> indexClass,
Class<? extends GeometryEncoder> encoderClass, String... encoderConfig) {
Class<? extends GeometryEncoder> encoderClass, String indexConfig, String... encoderConfig
) {
return (SimplePointLayer) createLayer(tx, name, encoderClass, SimplePointLayer.class, indexClass,
makeEncoderConfig(encoderConfig), org.geotools.referencing.crs.DefaultGeographicCRS.WGS84);
makeEncoderConfig(encoderConfig), indexConfig, org.geotools.referencing.crs.DefaultGeographicCRS.WGS84);
}

public static String makeEncoderConfig(String... args) {
Expand All @@ -349,19 +354,27 @@ public static String makeEncoderConfig(String... args) {
}

public Layer createLayer(Transaction tx, String name, Class<? extends GeometryEncoder> geometryEncoderClass,
Class<? extends Layer> layerClass) {
return createLayer(tx, name, geometryEncoderClass, layerClass, null, null);
}

public Layer createLayer(Transaction tx, String name, Class<? extends GeometryEncoder> geometryEncoderClass,
Class<? extends Layer> layerClass, Class<? extends LayerIndexReader> indexClass,
String encoderConfig) {
return createLayer(tx, name, geometryEncoderClass, layerClass, indexClass, encoderConfig, null);
Class<? extends Layer> layerClass, String indexConfig) {
return createLayer(tx, name, geometryEncoderClass, layerClass, null, null, indexConfig);
}

public Layer createLayer(Transaction tx, String name, Class<? extends GeometryEncoder> geometryEncoderClass,
Class<? extends Layer> layerClass, Class<? extends LayerIndexReader> indexClass,
String encoderConfig, CoordinateReferenceSystem crs) {
String encoderConfig,
String indexConfig
) {
return createLayer(tx, name, geometryEncoderClass, layerClass, indexClass, encoderConfig, indexConfig, null);
}

public Layer createLayer(Transaction tx,
String name,
Class<? extends GeometryEncoder> geometryEncoderClass,
Class<? extends Layer> layerClass,
Class<? extends LayerIndexReader> indexClass,
String encoderConfig,
String indexConfig,
CoordinateReferenceSystem crs
) {
if (containsLayer(tx, name)) {
throw new SpatialDatabaseException("Layer " + name + " already exists");
}
Expand All @@ -379,6 +392,17 @@ public Layer createLayer(Transaction tx, String name, Class<? extends GeometryEn
+ geometryEncoderClass);
}
}
if (indexConfig != null && !indexConfig.isEmpty()) {
LayerIndexReader index = layer.getIndex();
if (index instanceof Configurable) {
((Configurable) index).setConfiguration(indexConfig);
layer.getLayerNode(tx).setProperty(PROP_INDEX_CONFIG, indexConfig);
} else {
System.out.println(
"Warning: index configuration '" + indexConfig + "' passed to non-configurable index: "
+ indexClass);
}
}
if (crs != null && layer instanceof EditableLayer) {
((EditableLayer) layer).setCoordinateReferenceSystem(tx, crs);
}
Expand Down Expand Up @@ -465,7 +489,7 @@ public static int convertJtsClassToGeometryType(Class<? extends Geometry> jtsCla
* @return new Layer with copy of all geometries
*/
public Layer createResultsLayer(Transaction tx, String layerName, List<SpatialDatabaseRecord> results) {
EditableLayer layer = (EditableLayer) createWKBLayer(tx, layerName);
EditableLayer layer = (EditableLayer) createWKBLayer(tx, layerName, "");
for (SpatialDatabaseRecord record : results) {
layer.add(tx, record.getGeometry());
}
Expand Down Expand Up @@ -544,15 +568,16 @@ private static void addRegisteredLayerType(RegisteredLayerType type) {
registeredLayerTypes.put(type.typeName.toLowerCase(), type);
}

public Layer getOrCreateRegisteredTypeLayer(Transaction tx, String name, String type, String config) {
public Layer getOrCreateRegisteredTypeLayer(Transaction tx, String name, String type, String encoderConfig,
String indexConfig) {
RegisteredLayerType registeredLayerType = registeredLayerTypes.get(type.toLowerCase());
return getOrCreateRegisteredTypeLayer(tx, name, registeredLayerType, config);
return getOrCreateRegisteredTypeLayer(tx, name, registeredLayerType, encoderConfig, indexConfig);
}

public Layer getOrCreateRegisteredTypeLayer(Transaction tx, String name, RegisteredLayerType registeredLayerType,
String config) {
String encoderConfig, String indexConfig) {
return getOrCreateLayer(tx, name, registeredLayerType.geometryEncoder, registeredLayerType.layerClass,
(config == null) ? registeredLayerType.defaultConfig : config);
(encoderConfig == null) ? registeredLayerType.defaultConfig : encoderConfig, indexConfig);
}

public static Map<String, String> getRegisteredLayerTypes() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/neo4j/gis/spatial/osm/OSMImporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public long reIndex(GraphDatabaseService database, int commitInterval, boolean i
OSMDataset dataset;
try (Transaction tx = beginTx(database)) {
layer = (OSMLayer) spatialDatabase.getOrCreateLayer(tx, layerName, OSMGeometryEncoder.class,
OSMLayer.class);
OSMLayer.class, null);
dataset = OSMDataset.withDatasetId(tx, layer, osm_dataset);
tx.commit();
}
Expand Down
Loading