From 74bf0a63d994161d2dc8ab49d41ba4716e7b3fbc Mon Sep 17 00:00:00 2001 From: seab Date: Mon, 26 Feb 2024 22:07:45 -0500 Subject: [PATCH 01/10] Add missing @Override annotations and remove unneeded else clauses --- pom.xml | 14 +- .../data/neo4j/Neo4jSpatialDataStore.java | 21 +-- .../neo4j/Neo4jSpatialDataStoreFactory.java | 3 +- .../spatial/encoders/NativePointEncoder.java | 3 +- .../gis/spatial/filter/SearchIntersect.java | 1 + .../index/ExplicitIndexBackedPointIndex.java | 9 +- .../spatial/pipes/AbstractExtractGeoPipe.java | 5 +- .../spatial/pipes/AbstractFilterGeoPipe.java | 3 +- .../gis/spatial/pipes/impl/AbstractPipe.java | 44 ++++--- .../gis/spatial/pipes/impl/Pipeline.java | 30 +++-- .../osm/filtering/FilterOSMAttributes.java | 3 +- .../pipes/processing/OrthodromicDistance.java | 11 +- .../spatial/procedures/SpatialProcedures.java | 108 ++++++--------- .../neo4j/gis/spatial/rtree/EmptyMonitor.java | 5 +- .../org/neo4j/gis/spatial/rtree/Envelope.java | 3 +- .../rtree/ProgressLoggingListener.java | 3 +- .../gis/spatial/rtree/RTreeImageExporter.java | 6 +- .../neo4j/gis/spatial/rtree/RTreeIndex.java | 123 +++++++++--------- .../neo4j/gis/spatial/rtree/RTreeMonitor.java | 3 +- .../procedures/SpatialProceduresTest.java | 2 +- 20 files changed, 179 insertions(+), 221 deletions(-) diff --git a/pom.xml b/pom.xml index e287a296b..415b7c01d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,25 +2,25 @@ - 5.13.0 - 17 + 5.17.0 + 21 org.neo4j.maven.skins default-skin 2 - 30.0 + 30.1 20100819 20100819 UTF-8 org.neo4j.gis github - 5.10.0 - 3.2.1 + 5.10.2 + 3.2.2 4.0.0 neo4j-spatial org.neo4j - 0.30.0-neo4j-5.13.0 + 0.31.0-neo4j-5.17.0 Neo4j - Spatial Components Spatial utilities and components for Neo4j http://components.neo4j.org/${project.artifactId}/${project.version} @@ -37,7 +37,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 ${neo4j.java.version} ${neo4j.java.version} diff --git a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStore.java b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStore.java index 3183cd617..b0d4b4498 100644 --- a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStore.java +++ b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStore.java @@ -167,9 +167,8 @@ protected ContentFeatureSource createFeatureSource(ContentEntry contentEntry) th Neo4jSpatialFeatureSource source = new Neo4jSpatialFeatureSource(contentEntry, database, layer, buildFeatureType(contentEntry.getTypeName()), records, extraPropertyNames); if (layer instanceof EditableLayer) { return new Neo4jSpatialFeatureStore(contentEntry, database, (EditableLayer) layer, source); - } else { - return source; } + return source; } private CoordinateReferenceSystem getCRS(Transaction tx, Layer layer) { @@ -187,7 +186,7 @@ private Object getLayerStyle(String typeName) { Layer layer = spatialDatabase.getLayer(tx, typeName); tx.commit(); if (layer == null) return null; - else return layer.getStyle(); + return layer.getStyle(); } } @@ -217,20 +216,4 @@ public Style getStyle(String typeName) { } return result; } - - private EditableLayer getEditableLayer(String typeName) throws IOException { - try (Transaction tx = database.beginTx()) { - Layer layer = spatialDatabase.getLayer(tx, typeName); - if (layer == null) { - throw new IOException("Layer not found: " + typeName); - } - - if (!(layer instanceof EditableLayer)) { - throw new IOException("Cannot create a FeatureWriter on a read-only layer: " + layer); - } - tx.commit(); - - return (EditableLayer) layer; - } - } } diff --git a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java index 764583433..b3c939960 100644 --- a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java +++ b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java @@ -21,6 +21,7 @@ import org.geotools.api.data.DataStore; import org.geotools.api.data.DataStoreFactorySpi; +import org.geotools.api.data.Parameter; import org.geotools.util.KVP; import org.neo4j.dbms.api.DatabaseManagementService; import org.neo4j.dbms.api.DatabaseManagementServiceBuilder; @@ -46,7 +47,7 @@ public class Neo4jSpatialDataStoreFactory implements DataStoreFactorySpi { "db", true); public static final Param DBTYPE = new Param("dbtype", String.class, - "must be 'neo4j'", true, "neo4j", new KVP(Param.LEVEL, "program")); + "must be 'neo4j'", true, "neo4j", new KVP(Parameter.LEVEL, "program")); /** * Creates a new instance of Neo4jSpatialDataStoreFactory diff --git a/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java b/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java index 13fa58d09..9c9a52de4 100644 --- a/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java @@ -66,9 +66,8 @@ public Geometry decodeGeometry(Entity container) { double[] coordinate = point.getCoordinate().getCoordinate(); if (crs.dimensions() == 3) { return getGeometryFactory().createPoint(new Coordinate(coordinate[0], coordinate[1], coordinate[2])); - } else { - return getGeometryFactory().createPoint(new Coordinate(coordinate[0], coordinate[1])); } + return getGeometryFactory().createPoint(new Coordinate(coordinate[0], coordinate[1])); } @Override diff --git a/src/main/java/org/neo4j/gis/spatial/filter/SearchIntersect.java b/src/main/java/org/neo4j/gis/spatial/filter/SearchIntersect.java index 25cb05593..d2376e314 100644 --- a/src/main/java/org/neo4j/gis/spatial/filter/SearchIntersect.java +++ b/src/main/java/org/neo4j/gis/spatial/filter/SearchIntersect.java @@ -38,6 +38,7 @@ public SearchIntersect(Layer layer, Geometry other) { super(layer, other); } + @Override protected boolean onEnvelopeIntersection(Node geomNode, Envelope geomEnvelope) { Geometry geometry = decode(geomNode); return geometry.intersects(referenceGeometry); diff --git a/src/main/java/org/neo4j/gis/spatial/index/ExplicitIndexBackedPointIndex.java b/src/main/java/org/neo4j/gis/spatial/index/ExplicitIndexBackedPointIndex.java index 58ba3c435..5dec5d95d 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/ExplicitIndexBackedPointIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/index/ExplicitIndexBackedPointIndex.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; -import java.util.stream.Stream; import org.neo4j.gis.spatial.Layer; import org.neo4j.gis.spatial.filter.SearchRecords; import org.neo4j.gis.spatial.rtree.Envelope; @@ -188,9 +187,8 @@ private void prefetch() { next = node; monitor.hit(); break; - } else { - monitor.miss(); } + monitor.miss(); } } @@ -204,10 +202,9 @@ public Node next() { Node node = next; if (node == null) { throw new NoSuchElementException(); // GeoPipes relies on this behaviour instead of hasNext() - } else { - prefetch(); - return node; } + prefetch(); + return node; } } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/AbstractExtractGeoPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/AbstractExtractGeoPipe.java index 09d9555b2..8793529ed 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/AbstractExtractGeoPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/AbstractExtractGeoPipe.java @@ -36,10 +36,9 @@ public GeoPipeFlow processNextStart() { if (extractIterator != null) { if (extractIterator.hasNext()) { return extractIterator.next(); - } else { - extractIterator = null; - extracts.clear(); } + extractIterator = null; + extracts.clear(); } do { diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/AbstractFilterGeoPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/AbstractFilterGeoPipe.java index 5be9cea2c..c0fe0b962 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/AbstractFilterGeoPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/AbstractFilterGeoPipe.java @@ -32,9 +32,8 @@ protected AbstractFilterGeoPipe() { protected GeoPipeFlow process(GeoPipeFlow flow) { if (validate(flow)) { return flow; - } else { - return null; } + return null; } /** diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/AbstractPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/AbstractPipe.java index 65f44f98a..8e21b146c 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/AbstractPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/AbstractPipe.java @@ -30,18 +30,21 @@ public void setStarts(final Pipe starts) { this.starts = starts; } - public void setStarts(final Iterator starts) { + @Override + public void setStarts(final Iterator starts) { if (starts instanceof Pipe) this.starts = starts; else this.starts = new LastElementIterator<>(starts); } - public void setStarts(final Iterable starts) { + @Override + public void setStarts(final Iterable starts) { this.setStarts(starts.iterator()); } - public void reset() { + @Override + public void reset() { if (this.starts instanceof Pipe) { ((Pipe) this.starts).reset(); } @@ -53,7 +56,8 @@ public void reset() { this.available = false; } - public List getPath() { + @Override + public List getPath() { final List pathElements = getPathToHere(); final int size = pathElements.size(); // do not repeat filters as they dup the object @@ -63,30 +67,30 @@ public List getPath() { return pathElements; } - public void remove() { + @Override + public void remove() { throw new UnsupportedOperationException(); } - public E next() { + @Override + public E next() { if (this.available) { this.available = false; return (this.currentEnd = this.nextEnd); - } else { - return (this.currentEnd = this.processNextStart()); } + return (this.currentEnd = this.processNextStart()); } - public boolean hasNext() { + @Override + public boolean hasNext() { if (this.available) return true; - else { - try { - this.nextEnd = this.processNextStart(); - return (this.available = true); - } catch (final NoSuchElementException e) { - return (this.available = false); - } - } + try { + this.nextEnd = this.processNextStart(); + return (this.available = true); + } catch (final NoSuchElementException e) { + return (this.available = false); + } } /** @@ -95,11 +99,13 @@ public boolean hasNext() { * * @return the pipe from the perspective of an iterator */ - public Iterator iterator() { + @Override + public Iterator iterator() { return this; } - public String toString() { + @Override + public String toString() { return getClass().getSimpleName(); } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java index bf5f869f6..ef5be9a4f 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java @@ -78,19 +78,22 @@ public void addPipe(final Pipe pipe) { this.setPipes(this.pipes); } - public void setStarts(final Iterator starts) { + @Override + public void setStarts(final Iterator starts) { this.starts = starts; this.startPipe.setStarts(starts); } - public void setStarts(final Iterable starts) { + @Override + public void setStarts(final Iterable starts) { this.setStarts(starts.iterator()); } /** * An unsupported operation that throws an UnsupportedOperationException. */ - public void remove() { + @Override + public void remove() { throw new UnsupportedOperationException(); } @@ -99,7 +102,8 @@ public void remove() { * * @return true if an object can be next()'d out of the pipeline */ - public boolean hasNext() { + @Override + public boolean hasNext() { return this.endPipe.hasNext(); } @@ -109,11 +113,13 @@ public boolean hasNext() { * * @return the next emitted object */ - public E next() { + @Override + public E next() { return this.endPipe.next(); } - public List getPath() { + @Override + public List getPath() { return this.endPipe.getPath(); } @@ -126,7 +132,8 @@ public int size() { return this.pipes.size(); } - public void reset() { + @Override + public void reset() { this.startPipe.reset(); // Clear incoming state to avoid bug in Neo4j 4.3 with leaked RelationshipTraversalCursor this.endPipe.reset(); } @@ -136,11 +143,13 @@ public void reset() { * * @return returns the iterator representation of this pipeline */ - public Iterator iterator() { + @Override + public Iterator iterator() { return this; } - public String toString() { + @Override + public String toString() { return this.pipes.toString(); } @@ -160,7 +169,8 @@ public Pipe get(final int index) { return this.pipes.get(index); } - public boolean equals(final Object object) { + @Override + public boolean equals(final Object object) { return (object instanceof Pipeline) && areEqual(this, (Pipeline) object); } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/osm/filtering/FilterOSMAttributes.java b/src/main/java/org/neo4j/gis/spatial/pipes/osm/filtering/FilterOSMAttributes.java index cb2bc28ee..e7e7b684b 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/osm/filtering/FilterOSMAttributes.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/osm/filtering/FilterOSMAttributes.java @@ -51,8 +51,7 @@ protected GeoPipeFlow process(GeoPipeFlow flow) { if (tagNode.hasProperty(key) && comparison.compare(tagNode.getProperty(key), value)) { return flow; - } else { - return null; } + return null; } } \ No newline at end of file diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/processing/OrthodromicDistance.java b/src/main/java/org/neo4j/gis/spatial/pipes/processing/OrthodromicDistance.java index b9fb7c23a..c77bdadde 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/processing/OrthodromicDistance.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/processing/OrthodromicDistance.java @@ -64,13 +64,12 @@ public static double calculateDistanceToGeometry(Coordinate reference, Geometry if (geometry instanceof Point) { Point point = (Point) geometry; return calculateDistance(reference, point.getCoordinate()); - } else { - Geometry referencePoint = geometry.getFactory().createPoint(reference); - DistanceOp ops = new DistanceOp(referencePoint, geometry); - Coordinate[] nearest = ops.nearestPoints(); - assert nearest.length == 2; - return calculateDistance(nearest[0], nearest[1]); } + Geometry referencePoint = geometry.getFactory().createPoint(reference); + DistanceOp ops = new DistanceOp(referencePoint, geometry); + Coordinate[] nearest = ops.nearestPoints(); + assert nearest.length == 2; + return calculateDistance(nearest[0], nearest[1]); } public static Envelope suggestSearchWindow(Coordinate reference, double maxDistanceInKm) { diff --git a/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java b/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java index 838248e8f..10af4aa47 100644 --- a/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java +++ b/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java @@ -19,7 +19,6 @@ */ package org.neo4j.gis.spatial.procedures; -import javax.annotation.Nullable; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.locationtech.jts.geom.*; import org.locationtech.jts.io.ParseException; @@ -47,7 +46,6 @@ import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Transaction; -import org.neo4j.internal.kernel.api.exceptions.ProcedureException; import org.neo4j.internal.kernel.api.procs.ProcedureSignature; import org.neo4j.internal.kernel.api.security.SecurityContext; import org.neo4j.kernel.api.KernelTransaction; @@ -187,7 +185,7 @@ private static void populateEncoderClasses() { @Procedure("spatial.procedures") @Description("Lists all spatial procedures with name and signature") - public Stream listProcedures() throws ProcedureException { + public Stream listProcedures() { GlobalProcedures procedures = ((GraphDatabaseAPI) db).getDependencyResolver().resolveDependency(GlobalProcedures.class); Stream.Builder builder = Stream.builder(); for (ProcedureSignature proc : procedures.getCurrentView().getAllProcedures()) { @@ -249,9 +247,8 @@ public Stream addSimplePointLayer( return streamNode(sdb.createLayer(tx, name, SimplePointEncoder.class, SimplePointLayer.class, sdb.resolveIndexClass(indexType), null, selectCRS(crsName)).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addPointLayerGeohash", mode=WRITE) @@ -265,9 +262,8 @@ public Stream addSimplePointLayerGeohash( return streamNode(sdb.createLayer(tx, name, SimplePointEncoder.class, SimplePointLayer.class, LayerGeohashPointIndex.class, null, selectCRS(crsName)).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addPointLayerZOrder", mode=WRITE) @@ -277,9 +273,8 @@ public Stream addSimplePointLayerZOrder(@Name("name") String name) { Layer layer = sdb.getLayer(tx, name); if (layer == null) { return streamNode(sdb.createLayer(tx, name, SimplePointEncoder.class, SimplePointLayer.class, LayerZOrderPointIndex.class, null, DefaultGeographicCRS.WGS84).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addPointLayerHilbert", mode=WRITE) @@ -289,9 +284,8 @@ public Stream addSimplePointLayerHilbert(@Name("name") String name) Layer layer = sdb.getLayer(tx, name); if (layer == null) { return streamNode(sdb.createLayer(tx, name, SimplePointEncoder.class, SimplePointLayer.class, LayerHilbertPointIndex.class, null, DefaultGeographicCRS.WGS84).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addPointLayerXY", mode=WRITE) @@ -309,12 +303,10 @@ public Stream addSimplePointLayer( return streamNode(sdb.createLayer(tx, name, SimplePointEncoder.class, SimplePointLayer.class, sdb.resolveIndexClass(indexType), sdb.makeEncoderConfig(xProperty, yProperty), selectCRS(hintCRSName(crsName, yProperty))).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create layer '" + name + "': Missing encoder config values: xProperty[" + xProperty + "], yProperty[" + yProperty + "]"); } - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); + throw new IllegalArgumentException("Cannot create layer '" + name + "': Missing encoder config values: xProperty[" + xProperty + "], yProperty[" + yProperty + "]"); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addPointLayerWithConfig", mode=WRITE) @@ -331,12 +323,10 @@ public Stream addSimplePointLayerWithConfig( return streamNode(sdb.createLayer(tx, name, SimplePointEncoder.class, SimplePointLayer.class, sdb.resolveIndexClass(indexType), encoderConfig, selectCRS(hintCRSName(crsName, encoderConfig))).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create layer '" + name + "': invalid encoder config '" + encoderConfig + "'"); } - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); + throw new IllegalArgumentException("Cannot create layer '" + name + "': invalid encoder config '" + encoderConfig + "'"); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addNativePointLayer", mode=WRITE) @@ -349,9 +339,8 @@ public Stream addNativePointLayer( Layer layer = sdb.getLayer(tx, name); if (layer == null) { return streamNode(sdb.createLayer(tx, name, NativePointEncoder.class, SimplePointLayer.class, sdb.resolveIndexClass(indexType), null, selectCRS(crsName)).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addNativePointLayerGeohash", mode=WRITE) @@ -363,9 +352,8 @@ public Stream addNativePointLayerGeohash( Layer layer = sdb.getLayer(tx, name); if (layer == null) { return streamNode(sdb.createLayer(tx, name, NativePointEncoder.class, SimplePointLayer.class, LayerGeohashPointIndex.class, null, selectCRS(crsName)).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addNativePointLayerZOrder", mode=WRITE) @@ -375,9 +363,8 @@ public Stream addNativePointLayerZOrder(@Name("name") String name) { Layer layer = sdb.getLayer(tx, name); if (layer == null) { return streamNode(sdb.createLayer(tx, name, NativePointEncoder.class, SimplePointLayer.class, LayerZOrderPointIndex.class, null, DefaultGeographicCRS.WGS84).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addNativePointLayerHilbert", mode=WRITE) @@ -387,9 +374,8 @@ public Stream addNativePointLayerHilbert(@Name("name") String name) Layer layer = sdb.getLayer(tx, name); if (layer == null) { return streamNode(sdb.createLayer(tx, name, NativePointEncoder.class, SimplePointLayer.class, LayerHilbertPointIndex.class, null, DefaultGeographicCRS.WGS84).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addNativePointLayerXY", mode=WRITE) @@ -407,12 +393,10 @@ public Stream addNativePointLayer( return streamNode(sdb.createLayer(tx, name, NativePointEncoder.class, SimplePointLayer.class, sdb.resolveIndexClass(indexType), sdb.makeEncoderConfig(xProperty, yProperty), selectCRS(hintCRSName(crsName, yProperty))).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create layer '" + name + "': Missing encoder config values: xProperty[" + xProperty + "], yProperty[" + yProperty + "]"); } - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); + throw new IllegalArgumentException("Cannot create layer '" + name + "': Missing encoder config values: xProperty[" + xProperty + "], yProperty[" + yProperty + "]"); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addNativePointLayerWithConfig", mode=WRITE) @@ -429,12 +413,10 @@ public Stream addNativePointLayerWithConfig( return streamNode(sdb.createLayer(tx, name, NativePointEncoder.class, SimplePointLayer.class, sdb.resolveIndexClass(indexType), encoderConfig, selectCRS(hintCRSName(crsName, encoderConfig))).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create layer '" + name + "': invalid encoder config '" + encoderConfig + "'"); } - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); + throw new IllegalArgumentException("Cannot create layer '" + name + "': invalid encoder config '" + encoderConfig + "'"); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } public static final String UNSET_CRS_NAME = ""; @@ -449,19 +431,18 @@ public Stream addNativePointLayerWithConfig( public CoordinateReferenceSystem selectCRS(String name) { if (name == null) { return null; - } else { - switch (name.toLowerCase()) { - case WGS84_CRS_NAME: - return org.geotools.referencing.crs.DefaultGeographicCRS.WGS84; - case UNSET_CRS_NAME: - return null; - default: - throw new IllegalArgumentException("Unsupported CRS name: " + name); - } } + switch (name.toLowerCase()) { + case WGS84_CRS_NAME: + return org.geotools.referencing.crs.DefaultGeographicCRS.WGS84; + case UNSET_CRS_NAME: + return null; + default: + throw new IllegalArgumentException("Unsupported CRS name: " + name); + } } - private String hintCRSName(String crsName, String hint) { + private static String hintCRSName(String crsName, String hint) { if (crsName.equals(UNSET_CRS_NAME) && hint.toLowerCase().contains("lat")) { crsName = WGS84_CRS_NAME; } @@ -481,12 +462,10 @@ public Stream addLayerWithEncoder( Class layerClass = sdb.suggestLayerClassForEncoder(encoderClass); if (encoderClass != null) { return streamNode(sdb.createLayer(tx, name, encoderClass, layerClass, null, encoderConfig).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create layer '" + name + "': invalid encoder class '" + encoderClassName + "'"); } - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); + throw new IllegalArgumentException("Cannot create layer '" + name + "': invalid encoder class '" + encoderClassName + "'"); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } @Procedure(value="spatial.addLayer", mode=WRITE) @@ -501,19 +480,17 @@ public Stream addLayerOfType( Map knownTypes = sdb.getRegisteredLayerTypes(); if (knownTypes.containsKey(type.toLowerCase())) { return streamNode(sdb.getOrCreateRegisteredTypeLayer(tx, name, type, encoderConfig).getLayerNode(tx)); - } else { - throw new IllegalArgumentException("Cannot create layer '" + name + "': unknown type '" + type + "' - supported types are " + knownTypes.toString()); } - } else { - throw new IllegalArgumentException("Cannot create existing layer: " + name); + throw new IllegalArgumentException("Cannot create layer '" + name + "': unknown type '" + type + "' - supported types are " + knownTypes.toString()); } + throw new IllegalArgumentException("Cannot create existing layer: " + name); } - private Stream streamNode(Node node) { + private static Stream streamNode(Node node) { return Stream.of(new NodeResult(node)); } - private Stream streamNode(String nodeId) { + private static Stream streamNode(String nodeId) { return Stream.of(new NodeIdResult(nodeId)); } @@ -626,7 +603,7 @@ public Stream removeNodeIdsFromLayer(@Name("layerName") String name @Procedure(value="spatial.addWKT", mode=WRITE) @Description("Adds the given WKT string to the layer, returns the created geometry node") - public Stream addGeometryWKTToLayer(@Name("layerName") String name, @Name("geometry") String geometryWKT) throws ParseException { + public Stream addGeometryWKTToLayer(@Name("layerName") String name, @Name("geometry") String geometryWKT) { EditableLayer layer = getEditableLayerOrThrow(tx, spatial(), name); WKTReader reader = new WKTReader(layer.getGeometryFactory()); return streamNode(addGeometryWkt(layer, reader, geometryWKT)); @@ -634,7 +611,7 @@ public Stream addGeometryWKTToLayer(@Name("layerName") String name, @Procedure(value="spatial.addWKTs", mode=WRITE) @Description("Adds the given WKT string list to the layer, returns the created geometry nodes") - public Stream addGeometryWKTsToLayer(@Name("layerName") String name, @Name("geometry") List geometryWKTs) throws ParseException { + public Stream addGeometryWKTsToLayer(@Name("layerName") String name, @Name("geometry") List geometryWKTs) { EditableLayer layer = getEditableLayerOrThrow(tx, spatial(), name); WKTReader reader = new WKTReader(layer.getGeometryFactory()); return geometryWKTs.stream().map(geometryWKT -> addGeometryWkt(layer, reader, geometryWKT)).map(NodeResult::new); @@ -675,9 +652,8 @@ private List importShapefileToLayer(String shpPath, EditableLayerImpl laye if (layer == null) { String layerName = shpPath.substring(shpPath.lastIndexOf(File.separator) + 1); return importer.importFile(shpPath, layerName); - } else { - return importer.importFile(shpPath, layer, Charset.defaultCharset()); } + return importer.importFile(shpPath, layer, Charset.defaultCharset()); } @Procedure(value="spatial.importOSMToLayer", mode=WRITE) @@ -739,9 +715,8 @@ private static class OSMImportRunner implements Runnable { long getResult() { if (e == null) { return rc; - } else { - throw new RuntimeException("Failed to import " + osmPath + " to layer '" + layerName + "': " + e.getMessage(), e); } + throw new RuntimeException("Failed to import " + osmPath + " to layer '" + layerName + "': " + e.getMessage(), e); } @Override @@ -867,7 +842,7 @@ public Stream findGeometriesIntersecting( .stream().map(GeoPipeFlow::getGeomNode).map(NodeResult::new); } - private Geometry toJTSGeometry(Layer layer, Object value) { + private static Geometry toJTSGeometry(Layer layer, Object value) { GeometryFactory factory = layer.getGeometryFactory(); if (value instanceof org.neo4j.graphdb.spatial.Point) { org.neo4j.graphdb.spatial.Point point = (org.neo4j.graphdb.spatial.Point) value; @@ -895,9 +870,8 @@ private Geometry toJTSGeometry(Layer layer, Object value) { private static org.neo4j.graphdb.spatial.Coordinate toNeo4jCoordinate(Coordinate coordinate) { if (coordinate.z == Coordinate.NULL_ORDINATE) { return new org.neo4j.graphdb.spatial.Coordinate(coordinate.x, coordinate.y); - } else { - return new org.neo4j.graphdb.spatial.Coordinate(coordinate.x, coordinate.y, coordinate.z); } + return new org.neo4j.graphdb.spatial.Coordinate(coordinate.x, coordinate.y, coordinate.z); } private static List toNeo4jCoordinates(Coordinate[] coordinates) { @@ -988,9 +962,8 @@ private static Map toMap(org.neo4j.graphdb.spatial.Geometry geom if (geometry instanceof org.neo4j.graphdb.spatial.Point) { org.neo4j.graphdb.spatial.Point point = (org.neo4j.graphdb.spatial.Point) geometry; return map("type", geometry.getGeometryType(), "coordinate", point.getCoordinate().getCoordinate()); - } else { - return map("type", geometry.getGeometryType(), "coordinates", toCoordinateArrayFromCoordinates(geometry.getCoordinates())); } + return map("type", geometry.getGeometryType(), "coordinates", toCoordinateArrayFromCoordinates(geometry.getCoordinates())); } private Map toPublic(Map incoming) { @@ -1046,9 +1019,8 @@ private static Layer getLayerOrThrow(Transaction tx, SpatialDatabaseService spat EditableLayer layer = (EditableLayer) spatial.getLayer(tx, name); if (layer != null) { return layer; - } else { - throw new IllegalArgumentException("No such layer '" + name + "'"); } + throw new IllegalArgumentException("No such layer '" + name + "'"); } private static void assertLayerDoesNotExists(Transaction tx, SpatialDatabaseService spatial, String name) { diff --git a/src/main/java/org/neo4j/gis/spatial/rtree/EmptyMonitor.java b/src/main/java/org/neo4j/gis/spatial/rtree/EmptyMonitor.java index 7cc8f18af..7e34a871e 100644 --- a/src/main/java/org/neo4j/gis/spatial/rtree/EmptyMonitor.java +++ b/src/main/java/org/neo4j/gis/spatial/rtree/EmptyMonitor.java @@ -34,7 +34,8 @@ public void setHeight(int height) { } - public int getHeight() + @Override + public int getHeight() { return -1; } @@ -95,6 +96,6 @@ public void matchedTreeNode(int level, Node node) { @Override public List getMatchedTreeNodes(int level) { - return new ArrayList(); + return new ArrayList<>(); } } diff --git a/src/main/java/org/neo4j/gis/spatial/rtree/Envelope.java b/src/main/java/org/neo4j/gis/spatial/rtree/Envelope.java index 17f6f0245..c840f51ba 100644 --- a/src/main/java/org/neo4j/gis/spatial/rtree/Envelope.java +++ b/src/main/java/org/neo4j/gis/spatial/rtree/Envelope.java @@ -132,8 +132,7 @@ public Envelope bbox(Envelope other) { Envelope result = new Envelope(this); result.expandToInclude(other); return result; - } else { - throw new IllegalArgumentException("Cannot calculate bounding box of Envelopes with different dimensions: " + this.getDimension() + " != " + other.getDimension()); } + throw new IllegalArgumentException("Cannot calculate bounding box of Envelopes with different dimensions: " + this.getDimension() + " != " + other.getDimension()); } } diff --git a/src/main/java/org/neo4j/gis/spatial/rtree/ProgressLoggingListener.java b/src/main/java/org/neo4j/gis/spatial/rtree/ProgressLoggingListener.java index ce4b1d07d..5d78aa8cc 100644 --- a/src/main/java/org/neo4j/gis/spatial/rtree/ProgressLoggingListener.java +++ b/src/main/java/org/neo4j/gis/spatial/rtree/ProgressLoggingListener.java @@ -114,8 +114,7 @@ private void logNoMoreThanOnceASecond(String action) { private String percText() { if (totalUnits > 0) { return String.format(Locale.ENGLISH,"%.2f", 100.0 * workedSoFar / totalUnits); - } else { - return "NaN"; } + return "NaN"; } } diff --git a/src/main/java/org/neo4j/gis/spatial/rtree/RTreeImageExporter.java b/src/main/java/org/neo4j/gis/spatial/rtree/RTreeImageExporter.java index b8b138350..d3c52ab0f 100644 --- a/src/main/java/org/neo4j/gis/spatial/rtree/RTreeImageExporter.java +++ b/src/main/java/org/neo4j/gis/spatial/rtree/RTreeImageExporter.java @@ -194,17 +194,17 @@ private void drawEnvelopes(MapContent mapContent, List envelopes, Colo mapContent.addLayer(new org.geotools.map.FeatureLayer(makeEnvelopeFeatures(envelopes), style)); } - private void drawIndexNodes(int level, MapContent mapContent, List nodes, Color color) throws IOException { + private void drawIndexNodes(int level, MapContent mapContent, List nodes, Color color) { Style style = StyledImageExporter.createPolygonStyle(color, Color.WHITE, 0.8, 0.0, level + 1); mapContent.addLayer(new org.geotools.map.FeatureLayer(makeIndexNodeFeatures(nodes), style)); } - private void drawEnvelope(MapContent mapContent, Coordinate min, Coordinate max, Color color) throws IOException { + private void drawEnvelope(MapContent mapContent, Coordinate min, Coordinate max, Color color) { Style style = StyledImageExporter.createPolygonStyle(color, Color.WHITE, 0.8, 0.0, 3); mapContent.addLayer(new org.geotools.map.FeatureLayer(makeEnvelopeFeatures(min, max), style)); } - private void drawBounds(MapContent mapContent, ReferencedEnvelope bounds, Color color) throws IOException { + private void drawBounds(MapContent mapContent, ReferencedEnvelope bounds, Color color) { Style style = StyledImageExporter.createPolygonStyle(color, Color.WHITE, 0.8, 1.0, 6); double[] min = bounds.getLowerCorner().getCoordinate(); double[] max = bounds.getUpperCorner().getCoordinate(); diff --git a/src/main/java/org/neo4j/gis/spatial/rtree/RTreeIndex.java b/src/main/java/org/neo4j/gis/spatial/rtree/RTreeIndex.java index b68729159..46def2ac8 100644 --- a/src/main/java/org/neo4j/gis/spatial/rtree/RTreeIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/rtree/RTreeIndex.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.neo4j.gis.spatial.encoders.Configurable; @@ -77,7 +79,8 @@ public class RTreeIndex implements SpatialIndexWriter, Configurable { private int totalGeometryCount = 0; private boolean countSaved = false; - public void addMonitor(TreeMonitor monitor) { + @Override + public void addMonitor(TreeMonitor monitor) { this.monitor = monitor; } @@ -109,7 +112,8 @@ public void setConfiguration(String jsonConfig) { configure(config); } - public String getConfiguration() { + @Override + public String getConfiguration() { HashMap config = new HashMap<>(); config.put(KEY_SPLIT, this.splitMode); config.put(KEY_MAX_NODE_REFERENCES, this.maxNodeReferences); @@ -117,7 +121,8 @@ public String getConfiguration() { return JSONObject.toJSONString(config); } - public void configure(Map config) { + @Override + public void configure(Map config) { for (String key : config.keySet()) { switch (key) { case KEY_SPLIT: @@ -219,7 +224,7 @@ public void add(Transaction tx, List geomNodes) { } nodesToAdd.addAll(geomNodes); detachGeometryNodes(tx, false, getIndexRoot(tx), new NullListener()); - deleteTreeBelow(tx, getIndexRoot(tx)); + deleteTreeBelow(getIndexRoot(tx)); buildRtreeFromScratch(tx, getIndexRoot(tx), decodeGeometryNodeEnvelopes(nodesToAdd), 0.7); countSaved = false; totalGeometryCount = nodesToAdd.size(); @@ -273,10 +278,9 @@ int getHeight(Node rootNode, int height) { try (var relationships = rootNode.getRelationships(Direction.OUTGOING, RTreeRelationshipTypes.RTREE_CHILD)) { if (relationships.iterator().hasNext()) { return getHeight(relationships.iterator().next().getEndNode(), height + 1); - } else { - // Add one to account for the step to leaf nodes. - return height + 1; // todo should this really be +1 ? } + // Add one to account for the step to leaf nodes. + return height + 1; // todo should this really be +1 ? } } @@ -299,13 +303,12 @@ private List getIndexChildren(Node rootNode, int depth) { List rootChildren = getIndexChildren(rootNode); if (depth == 1) { return rootChildren; - } else { - List result = new ArrayList<>(rootChildren.size() * 5); - for (NodeWithEnvelope child : rootChildren) { - result.addAll(getIndexChildren(child.node, depth - 1)); - } - return result; } + List result = new ArrayList<>(rootChildren.size() * 5); + for (NodeWithEnvelope child : rootChildren) { + result.addAll(getIndexChildren(child.node, depth - 1)); + } + return result; } private List bulkInsertion(Transaction tx, Node rootNode, int rootNodeHeight, final List geomNodes, final double loadingFactor) { @@ -490,10 +493,9 @@ protected void mergeTwoSubtrees(Transaction tx, NodeWithEnvelope parent, List no // quick dirty way to partition a set into equal sized disjoint subsets // - TODO why not use list.sublist() without copying ? - private List> partitionList(List nodes, int numberOfPartitions) { + private static List> partitionList(List nodes, int numberOfPartitions) { int nodeCount = nodes.size(); List> partitions = new ArrayList<>(numberOfPartitions); @@ -633,13 +635,11 @@ private Node deleteEmptyTreeNodes(Node indexNode, RelationshipType relType) { indexNode.delete(); return deleteEmptyTreeNodes(parent, RTreeRelationshipTypes.RTREE_CHILD); - } else { - // root - return indexNode; } - } else { - return indexNode; + // root + return indexNode; } + return indexNode; } private void detachGeometryNodes(Transaction tx, final boolean deleteGeomNodes, Node indexRoot, final Listener monitor) { @@ -822,9 +822,8 @@ public Node getIndexRoot(Transaction tx) { private Envelope getChildNodeEnvelope(Node child, RelationshipType relType) { if (relType.name().equals(RTreeRelationshipTypes.RTREE_REFERENCE.name())) { return getLeafNodeEnvelope(child); - } else { - return getIndexNodeEnvelope(child); } + return getIndexNodeEnvelope(child); } /** @@ -935,7 +934,7 @@ private void saveCount(Transaction tx) { } } - private boolean nodeIsLeaf(Node node) { + private static boolean nodeIsLeaf(Node node) { return !node.hasRelationship(Direction.OUTGOING, RTreeRelationshipTypes.RTREE_CHILD); } @@ -1010,14 +1009,10 @@ private Node chooseIndexNodeWithSmallestArea(List indexNodes) { return result; } - private int countChildren(Node indexNode, RelationshipType relationshipType) { - int counter = 0; + private static int countChildren(Node indexNode, RelationshipType relationshipType) { try (var relationships = indexNode.getRelationships(Direction.OUTGOING, relationshipType)) { - for (Relationship ignored : relationships) { - counter++; - } + return (int) StreamSupport.stream(relationships.spliterator(), false).count(); } - return counter; } /** @@ -1053,20 +1048,18 @@ private void splitAndAdjustPathBoundingBox(Transaction tx, Node indexNode) { private Node quadraticSplit(Transaction tx, Node indexNode) { if (nodeIsLeaf(indexNode)) { return quadraticSplit(tx, indexNode, RTreeRelationshipTypes.RTREE_REFERENCE); - } else { - return quadraticSplit(tx, indexNode, RTreeRelationshipTypes.RTREE_CHILD); } + return quadraticSplit(tx, indexNode, RTreeRelationshipTypes.RTREE_CHILD); } private Node greenesSplit(Transaction tx, Node indexNode) { if (nodeIsLeaf(indexNode)) { return greenesSplit(tx, indexNode, RTreeRelationshipTypes.RTREE_REFERENCE); - } else { - return greenesSplit(tx, indexNode, RTreeRelationshipTypes.RTREE_CHILD); } + return greenesSplit(tx, indexNode, RTreeRelationshipTypes.RTREE_CHILD); } - private NodeWithEnvelope[] mostDistantByDeadSpace(List entries) { + private static NodeWithEnvelope[] mostDistantByDeadSpace(List entries) { NodeWithEnvelope seed1 = entries.get(0); NodeWithEnvelope seed2 = entries.get(0); double worst = Double.NEGATIVE_INFINITY; @@ -1085,7 +1078,7 @@ private NodeWithEnvelope[] mostDistantByDeadSpace(List entries return new NodeWithEnvelope[]{seed1, seed2}; } - private int findLongestDimension(List entries) { + private static int findLongestDimension(List entries) { if (entries.size() > 0) { Envelope env = new Envelope(entries.get(0).envelope); for (NodeWithEnvelope entry : entries) { @@ -1101,9 +1094,8 @@ private int findLongestDimension(List entries) { } } return longestDimension; - } else { - return 0; } + return 0; } private List extractChildNodesWithEnvelopes(Node indexNode, RelationshipType relationshipType) { @@ -1202,13 +1194,12 @@ private Node quadraticSplit(Transaction tx, Node indexNode, RelationshipType rel if (bestEntry == null) { throw new RuntimeException("Should not be possible to fail to find a best entry during quadratic split"); - } else { - // insert the best candidate entry in the best group - bestGroup.add(bestEntry); - bestGroupEnvelope.expandToInclude(bestEntry.envelope); - - entries.remove(bestEntry); } + // insert the best candidate entry in the best group + bestGroup.add(bestEntry); + bestGroupEnvelope.expandToInclude(bestEntry.envelope); + + entries.remove(bestEntry); } return reconnectTwoChildGroups(tx, indexNode, group1, group2, relationshipType); @@ -1295,9 +1286,8 @@ private boolean adjustParentBoundingBox(Node indexNode, RelationshipType relatio || bbox.getMaxY() != old[3]) { setIndexNodeEnvelope(indexNode, bbox); return true; - } else { - return false; } + return false; } protected void setIndexNodeEnvelope(Node indexNode, Envelope bbox) { @@ -1331,38 +1321,35 @@ protected boolean expandParentBoundingBoxAfterNewChild(Node parent, double[] chi return valueChanged; } - private boolean setMin(double[] parent, double[] child, int index) { + private static boolean setMin(double[] parent, double[] child, int index) { if (parent[index] > child[index]) { parent[index] = child[index]; return true; - } else { - return false; } + return false; } - private boolean setMax(double[] parent, double[] child, int index) { + private static boolean setMax(double[] parent, double[] child, int index) { if (parent[index] < child[index]) { parent[index] = child[index]; return true; - } else { - return false; } + return false; } - private Node getIndexNodeParent(Node indexNode) { + private static Node getIndexNodeParent(Node indexNode) { Relationship relationship = indexNode.getSingleRelationship(RTreeRelationshipTypes.RTREE_CHILD, Direction.INCOMING); if (relationship == null) { return null; - } else { - return relationship.getStartNode(); } + return relationship.getStartNode(); } - private double getArea(Envelope e) { + private static double getArea(Envelope e) { return e.getArea(); } - private void deleteTreeBelow(Transaction ignored, Node rootNode) { + private void deleteTreeBelow(Node rootNode) { try (var relationships = rootNode.getRelationships(Direction.OUTGOING, RTreeRelationshipTypes.RTREE_CHILD)) { for (Relationship relationship : relationships) { deleteRecursivelySubtree(relationship.getEndNode(), relationship); @@ -1410,7 +1397,7 @@ protected boolean isIndexNodeInThisIndex(Transaction tx, Node indexNode) { return root.getElementId().equals(getIndexRoot(tx).getElementId()); } - private void deleteNode(Node node) { + private static void deleteNode(Node node) { try (var relationships = node.getRelationships()) { for (Relationship r : relationships) { r.delete(); @@ -1435,11 +1422,13 @@ private static Envelope createEnvelope(Envelope e, Envelope e1) { // Private classes private static class WarmUpVisitor implements SpatialIndexVisitor { - public boolean needsToVisit(Envelope indexNodeEnvelope) { + @Override + public boolean needsToVisit(Envelope indexNodeEnvelope) { return true; } - public void onIndexReference(Node geomNode) { + @Override + public void onIndexReference(Node geomNode) { } } @@ -1456,12 +1445,14 @@ private class GeometryNodeIterator implements Iterator { Iterator geometryNodeIterator = null; - public boolean hasNext() { + @Override + public boolean hasNext() { checkGeometryNodeIterator(); return geometryNodeIterator != null && geometryNodeIterator.hasNext(); } - public Node next() { + @Override + public Node next() { checkGeometryNodeIterator(); return geometryNodeIterator == null ? null : geometryNodeIterator.next(); } @@ -1479,7 +1470,8 @@ private void checkGeometryNodeIterator() { } } - public void remove() { + @Override + public void remove() { } } @@ -1487,7 +1479,8 @@ public IndexNodeToGeometryNodeIterable(Iterable allIndexNodes) { this.allIndexNodeIterator = allIndexNodes.iterator(); } - public Iterator iterator() { + @Override + public Iterator iterator() { return new GeometryNodeIterator(); } } diff --git a/src/main/java/org/neo4j/gis/spatial/rtree/RTreeMonitor.java b/src/main/java/org/neo4j/gis/spatial/rtree/RTreeMonitor.java index 557b6a890..bcfb6b279 100644 --- a/src/main/java/org/neo4j/gis/spatial/rtree/RTreeMonitor.java +++ b/src/main/java/org/neo4j/gis/spatial/rtree/RTreeMonitor.java @@ -45,7 +45,8 @@ public void setHeight(int height) { this.height = height; } - public int getHeight() { + @Override + public int getHeight() { return height; } diff --git a/src/test/java/org/neo4j/gis/spatial/procedures/SpatialProceduresTest.java b/src/test/java/org/neo4j/gis/spatial/procedures/SpatialProceduresTest.java index 8cb4b090b..c916595e7 100644 --- a/src/test/java/org/neo4j/gis/spatial/procedures/SpatialProceduresTest.java +++ b/src/test/java/org/neo4j/gis/spatial/procedures/SpatialProceduresTest.java @@ -147,7 +147,7 @@ public static void registerProceduresAndFunctions(GraphDatabaseService db, Class procedures.registerFunction(procedure); } - private Layer makeLayerOfVariousTypes(SpatialDatabaseService spatial, Transaction tx, String name, int index) { + private static Layer makeLayerOfVariousTypes(SpatialDatabaseService spatial, Transaction tx, String name, int index) { switch (index % 3) { case 0: return spatial.getOrCreateSimplePointLayer(tx, name, SpatialDatabaseService.RTREE_INDEX_NAME, "x", "y"); From c13d2902ce48d8d1b5affa7363e42399b5b9da0d Mon Sep 17 00:00:00 2001 From: seab Date: Tue, 27 Feb 2024 22:37:32 -0500 Subject: [PATCH 02/10] More code cleanup, mostly removing else clause and adding overrides --- .../org/neo4j/gis/spatial/DefaultLayer.java | 74 +++++++++++------- .../org/neo4j/gis/spatial/DynamicLayer.java | 75 +++++++++---------- .../neo4j/gis/spatial/DynamicLayerConfig.java | 26 ++----- .../neo4j/gis/spatial/EditableLayerImpl.java | 2 + .../gis/spatial/OrderedEditableLayer.java | 6 +- .../neo4j/gis/spatial/ShapefileImporter.java | 24 +++--- .../gis/spatial/SpatialDatabaseRecord.java | 8 +- .../gis/spatial/SpatialDatabaseService.java | 19 +---- .../gis/spatial/SpatialTopologyUtils.java | 37 ++++----- .../java/org/neo4j/gis/spatial/Utilities.java | 4 +- .../neo4j/gis/spatial/WKBGeometryEncoder.java | 6 +- .../neo4j/gis/spatial/WKTGeometryEncoder.java | 6 +- .../spatial/attributes/PropertyMapper.java | 4 +- .../attributes/PropertyMappingManager.java | 7 -- .../spatial/encoders/SimpleGraphEncoder.java | 5 +- .../spatial/encoders/neo4j/Neo4jGeometry.java | 12 ++- .../neo4j/gis/spatial/filter/SearchCQL.java | 3 - .../neo4j/gis/spatial/index/IndexManager.java | 45 +++++------ .../spatial/index/LayerGeohashPointIndex.java | 13 ++-- .../spatial/index/LayerHilbertPointIndex.java | 3 +- .../LayerSpaceFillingCurvePointIndex.java | 20 ++--- .../spatial/index/LayerZOrderPointIndex.java | 3 +- .../index/PropertyEncodingNodeIndex.java | 1 - .../indexfilter/DynamicIndexReader.java | 10 +-- .../org/neo4j/gis/spatial/osm/OSMDataset.java | 20 +++-- .../gis/spatial/osm/OSMGeometryEncoder.java | 40 +++++----- .../neo4j/gis/spatial/osm/OSMImporter.java | 38 +++++----- .../org/neo4j/gis/spatial/osm/OSMLayer.java | 12 +-- .../spatial/pipes/AbstractGroupGeoPipe.java | 2 +- .../neo4j/gis/spatial/pipes/GeoPipeline.java | 3 +- .../gis/spatial/pipes/impl/Pipeline.java | 4 +- .../spatial/pipes/impl/RangeFilterPipe.java | 9 ++- .../gis/spatial/utilities/LayerUtilities.java | 10 ++- 33 files changed, 271 insertions(+), 280 deletions(-) diff --git a/src/main/java/org/neo4j/gis/spatial/DefaultLayer.java b/src/main/java/org/neo4j/gis/spatial/DefaultLayer.java index cab742c0f..9284adc76 100644 --- a/src/main/java/org/neo4j/gis/spatial/DefaultLayer.java +++ b/src/main/java/org/neo4j/gis/spatial/DefaultLayer.java @@ -53,22 +53,26 @@ public class DefaultLayer implements Constants, Layer, SpatialDataset { // Public methods - public String getName() { + @Override + public String getName() { return name; } - public LayerIndexReader getIndex() { + @Override + public LayerIndexReader getIndex() { return indexReader; } - public String getSignature() { + @Override + public String getSignature() { return "Layer(name='" + getName() + "', encoder=" + getGeometryEncoder().getSignature() + ")"; } /** * Add the geometry encoded in the given Node. This causes the geometry to appear in the index. */ - public SpatialDatabaseRecord add(Transaction tx, Node geomNode) { + @Override + public SpatialDatabaseRecord add(Transaction tx, Node geomNode) { Geometry geometry = getGeometryEncoder().decodeGeometry(geomNode); // add BBOX to Node if it's missing @@ -91,7 +95,8 @@ public int addAll(Transaction tx, List geomNodes) { return geomNodes.size(); } - public GeometryFactory getGeometryFactory() { + @Override + public GeometryFactory getGeometryFactory() { return geometryFactory; } @@ -100,13 +105,13 @@ public void setCoordinateReferenceSystem(Transaction tx, CoordinateReferenceSyst layerNode.setProperty(PROP_CRS, crs.toWKT()); } - public CoordinateReferenceSystem getCoordinateReferenceSystem(Transaction tx) { + @Override + public CoordinateReferenceSystem getCoordinateReferenceSystem(Transaction tx) { Node layerNode = getLayerNode(tx); if (layerNode.hasProperty(PROP_CRS)) { return GeotoolsAdapter.getCRS((String) layerNode.getProperty(PROP_CRS)); - } else { - return null; } + return null; } public void setGeometryType(Transaction tx, int geometryType) { @@ -118,17 +123,17 @@ public void setGeometryType(Transaction tx, int geometryType) { layerNode.setProperty(PROP_TYPE, geometryType); } - public Integer getGeometryType(Transaction tx) { + @Override + public Integer getGeometryType(Transaction tx) { Node layerNode = getLayerNode(tx); if (layerNode.hasProperty(PROP_TYPE)) { return (Integer) layerNode.getProperty(PROP_TYPE); - } else { - GuessGeometryTypeSearch geomTypeSearch = new GuessGeometryTypeSearch(); - indexReader.searchIndex(tx, geomTypeSearch).count(); - - // returns null for an empty layer! - return geomTypeSearch.firstFoundType; } + GuessGeometryTypeSearch geomTypeSearch = new GuessGeometryTypeSearch(); + indexReader.searchIndex(tx, geomTypeSearch).count(); + + // returns null for an empty layer! + return geomTypeSearch.firstFoundType; } private static class GuessGeometryTypeSearch implements SearchFilter { @@ -150,7 +155,8 @@ public boolean geometryMatches(Transaction tx, Node geomNode) { } } - public String[] getExtraPropertyNames(Transaction tx) { + @Override + public String[] getExtraPropertyNames(Transaction tx) { Node layerNode = getLayerNode(tx); String[] extraPropertyNames; if (layerNode.hasProperty(PROP_LAYERNODEEXTRAPROPS)) { @@ -248,14 +254,16 @@ public void initialize(Transaction tx, IndexManager indexManager, String name, N * All layers are associated with a single node in the database. This node will have properties, * relationships (sub-graph) or both to describe the contents of the layer */ - public Node getLayerNode(Transaction tx) { + @Override + public Node getLayerNode(Transaction tx) { return tx.getNodeByElementId(layerNodeId); } /** * Delete Layer */ - public void delete(Transaction tx, Listener monitor) { + @Override + public void delete(Transaction tx, Listener monitor) { indexWriter.removeAll(tx, true, monitor); Node layerNode = getLayerNode(tx); layerNode.delete(); @@ -279,11 +287,13 @@ public void delete(Transaction tx, Listener monitor) { protected LayerIndexReader indexReader; protected SpatialIndexWriter indexWriter; - public SpatialDataset getDataset() { + @Override + public SpatialDataset getDataset() { return this; } - public Iterable getAllGeometryNodes(Transaction tx) { + @Override + public Iterable getAllGeometryNodes(Transaction tx) { return indexReader.getAllIndexedNodes(tx); } @@ -298,7 +308,8 @@ public boolean containsGeometryNode(Transaction tx, Node geomNode) { * * @return iterable over geometries in the dataset */ - public Iterable getAllGeometries(Transaction tx) { + @Override + public Iterable getAllGeometries(Transaction tx) { return new NodeToGeometryIterable(getAllGeometryNodes(tx)); } @@ -312,15 +323,18 @@ private class NodeToGeometryIterable implements Iterable { private class GeometryIterator implements Iterator { - public boolean hasNext() { + @Override + public boolean hasNext() { return NodeToGeometryIterable.this.allGeometryNodeIterator.hasNext(); } - public Geometry next() { + @Override + public Geometry next() { return geometryEncoder.decodeGeometry(NodeToGeometryIterable.this.allGeometryNodeIterator.next()); } - public void remove() { + @Override + public void remove() { } } @@ -329,7 +343,8 @@ public void remove() { this.allGeometryNodeIterator = allGeometryNodes.iterator(); } - public Iterator iterator() { + @Override + public Iterator iterator() { return new GeometryIterator(); } @@ -341,7 +356,8 @@ public Iterator iterator() { * * @return GeometryEncoder for this dataset */ - public GeometryEncoder getGeometryEncoder() { + @Override + public GeometryEncoder getGeometryEncoder() { return geometryEncoder; } @@ -350,7 +366,8 @@ public GeometryEncoder getGeometryEncoder() { * * @return iterable over all Layers that can be viewed from this dataset */ - public Iterable getLayers() { + @Override + public Iterable getLayers() { return Collections.singletonList(this); } @@ -362,7 +379,8 @@ public Iterable getLayers() { * * @return null */ - public Object getStyle() { + @Override + public Object getStyle() { return null; } diff --git a/src/main/java/org/neo4j/gis/spatial/DynamicLayer.java b/src/main/java/org/neo4j/gis/spatial/DynamicLayer.java index d50c63f1e..b4d3c1721 100644 --- a/src/main/java/org/neo4j/gis/spatial/DynamicLayer.java +++ b/src/main/java/org/neo4j/gis/spatial/DynamicLayer.java @@ -102,41 +102,39 @@ public DynamicLayerConfig addCQLDynamicLayerOnGeometryType(Transaction tx, int g public DynamicLayerConfig addCQLDynamicLayerOnAttribute(Transaction tx, String key, String value, int gtype) { if (value == null) { return addLayerConfig(tx, "CQL:" + key, gtype, key + " IS NOT NULL AND " + makeGeometryCQL(gtype)); - } else { - // TODO: Better escaping here - //return addLayerConfig("CQL:" + key + "-" + value, gtype, key + " = '" + value + "' AND " + makeGeometryCQL(gtype)); - return addCQLDynamicLayerOnAttributes(tx, new String[]{key, value}, gtype); } + // TODO: Better escaping here + //return addLayerConfig("CQL:" + key + "-" + value, gtype, key + " = '" + value + "' AND " + makeGeometryCQL(gtype)); + return addCQLDynamicLayerOnAttributes(tx, new String[]{key, value}, gtype); } public DynamicLayerConfig addCQLDynamicLayerOnAttributes(Transaction tx, String[] attributes, int gtype) { if (attributes == null) { return addCQLDynamicLayerOnGeometryType(tx, gtype); - } else { - StringBuilder name = new StringBuilder(); - StringBuilder query = new StringBuilder(); - if (gtype != GTYPE_GEOMETRY) { - query.append(makeGeometryCQL(gtype)); - } - for (int i = 0; i < attributes.length; i += 2) { - String key = attributes[i]; - if (name.length() > 0) { - name.append("-"); - } - if (query.length() > 0) { - query.append(" AND "); - } - if (attributes.length > i + 1) { - String value = attributes[i + 1]; - name.append(key).append("-").append(value); - query.append(key).append(" = '").append(value).append("'"); - } else { - name.append(key); - query.append(key).append(" IS NOT NULL"); - } - } - return addLayerConfig(tx, "CQL:" + name.toString(), gtype, query.toString()); } + StringBuilder name = new StringBuilder(); + StringBuilder query = new StringBuilder(); + if (gtype != GTYPE_GEOMETRY) { + query.append(makeGeometryCQL(gtype)); + } + for (int i = 0; i < attributes.length; i += 2) { + String key = attributes[i]; + if (name.length() > 0) { + name.append("-"); + } + if (query.length() > 0) { + query.append(" AND "); + } + if (attributes.length > i + 1) { + String value = attributes[i + 1]; + name.append(key).append("-").append(value); + query.append(key).append(" = '").append(value).append("'"); + } else { + name.append(key); + query.append(key).append(" IS NOT NULL"); + } + } + return addLayerConfig(tx, "CQL:" + name.toString(), gtype, query.toString()); } public DynamicLayerConfig addLayerConfig(Transaction tx, String name, int type, String query) { @@ -156,14 +154,13 @@ public DynamicLayerConfig addLayerConfig(Transaction tx, String name, int type, if (config.getGeometryType(tx) != type || !config.getQuery().equals(query)) { System.err.println("Existing LayerConfig with different geometry type or query: " + config); return null; - } else { - return config; } - } else { - System.err.println("Existing Layer has same name as requested LayerConfig: " + layer.getName()); - return null; + return config; } - } else synchronized (this) { + System.err.println("Existing Layer has same name as requested LayerConfig: " + layer.getName()); + return null; + } + synchronized (this) { DynamicLayerConfig config = new DynamicLayerConfig(tx, this, name, type, query); layers = null; // force recalculation of layers cache return config; @@ -191,14 +188,12 @@ public DynamicLayerConfig restrictLayerProperties(Transaction tx, String name, S config.setExtraPropertyNames(tx, names); } return config; - } else { - System.err.println("Existing Layer has same name as requested LayerConfig: " + layer.getName()); - return null; } - } else { - System.err.println("No such layer: " + name); - return null; + System.err.println("Existing Layer has same name as requested LayerConfig: " + layer.getName()); + return null; } + System.err.println("No such layer: " + name); + return null; } /** diff --git a/src/main/java/org/neo4j/gis/spatial/DynamicLayerConfig.java b/src/main/java/org/neo4j/gis/spatial/DynamicLayerConfig.java index c480e45ea..87d793005 100644 --- a/src/main/java/org/neo4j/gis/spatial/DynamicLayerConfig.java +++ b/src/main/java/org/neo4j/gis/spatial/DynamicLayerConfig.java @@ -20,7 +20,6 @@ package org.neo4j.gis.spatial; import java.io.File; -import java.io.PrintStream; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -120,9 +119,8 @@ public SpatialDataset getDataset() { public String[] getExtraPropertyNames(Transaction tx) { if (propertyNames != null && propertyNames.length > 0) { return propertyNames; - } else { - return parent.getExtraPropertyNames(tx); } + return parent.getExtraPropertyNames(tx); } private static class PropertyUsageSearch implements SearchFilter { @@ -167,12 +165,6 @@ public String[] getNames() { public int getNodeCount() { return nodeCount; } - - public void describeUsage(PrintStream out) { - for (String name : names.keySet()) { - out.println(name + "\t" + names.get(name)); - } - } } /** @@ -224,17 +216,15 @@ public LayerIndexReader getIndex() { if (query.startsWith("{")) { // Make a standard JSON based dynamic layer return new DynamicIndexReader((LayerTreeIndexReader) parent.indexReader, query); - } else { - // Make a CQL based dynamic layer - try { - return new CQLIndexReader((LayerTreeIndexReader) parent.indexReader, this, query); - } catch (CQLException e) { - throw new SpatialDatabaseException("Error while creating CQL based DynamicLayer", e); - } } - } else { - throw new SpatialDatabaseException("Cannot make a DynamicLayer from a non-LayerTreeIndexReader Layer"); + // Make a CQL based dynamic layer + try { + return new CQLIndexReader((LayerTreeIndexReader) parent.indexReader, this, query); + } catch (CQLException e) { + throw new SpatialDatabaseException("Error while creating CQL based DynamicLayer", e); + } } + throw new SpatialDatabaseException("Cannot make a DynamicLayer from a non-LayerTreeIndexReader Layer"); } @Override diff --git a/src/main/java/org/neo4j/gis/spatial/EditableLayerImpl.java b/src/main/java/org/neo4j/gis/spatial/EditableLayerImpl.java index 614e1aa3d..b7472fd60 100644 --- a/src/main/java/org/neo4j/gis/spatial/EditableLayerImpl.java +++ b/src/main/java/org/neo4j/gis/spatial/EditableLayerImpl.java @@ -29,6 +29,7 @@ public class EditableLayerImpl extends DefaultLayer implements EditableLayer { /** * Add a geometry to this layer. */ + @Override public SpatialDatabaseRecord add(Transaction tx, Geometry geometry) { return add(tx, geometry, null, null); } @@ -77,6 +78,7 @@ protected Node addGeomNode(Transaction tx, Geometry geom, String[] fieldsName, O return geomNode; } + @Override public String getSignature() { return "Editable" + super.getSignature(); } diff --git a/src/main/java/org/neo4j/gis/spatial/OrderedEditableLayer.java b/src/main/java/org/neo4j/gis/spatial/OrderedEditableLayer.java index 0f177e71a..5441303fb 100644 --- a/src/main/java/org/neo4j/gis/spatial/OrderedEditableLayer.java +++ b/src/main/java/org/neo4j/gis/spatial/OrderedEditableLayer.java @@ -49,7 +49,8 @@ enum OrderedRelationshipTypes implements RelationshipType { GEOMETRIES, NEXT_GEOM } - protected Node addGeomNode(Transaction tx, Geometry geom, String[] fieldsName, Object[] fields) { + @Override + protected Node addGeomNode(Transaction tx, Geometry geom, String[] fieldsName, Object[] fields) { Node geomNode = super.addGeomNode(tx, geom, fieldsName, fields); Node layerNode = getLayerNode(tx); if (previousGeomNode == null) { @@ -81,7 +82,8 @@ protected Node addGeomNode(Transaction tx, Geometry geom, String[] fieldsName, O * @return iterable over geometry nodes in the dataset * @param tx */ - public Iterable getAllGeometryNodes(Transaction tx) { + @Override + public Iterable getAllGeometryNodes(Transaction tx) { TraversalDescription td = new MonoDirectionalTraversalDescription() .depthFirst() .evaluator(Evaluators.excludeStartPosition()) diff --git a/src/main/java/org/neo4j/gis/spatial/ShapefileImporter.java b/src/main/java/org/neo4j/gis/spatial/ShapefileImporter.java index db322cfe0..92fc20c3f 100644 --- a/src/main/java/org/neo4j/gis/spatial/ShapefileImporter.java +++ b/src/main/java/org/neo4j/gis/spatial/ShapefileImporter.java @@ -120,15 +120,13 @@ public List importFile(String dataset, EditableLayerImpl layer, Charset ch throw new IllegalArgumentException("Failed to access the shapefile at either '" + dataset + "' or '" + dataset + ".shp'", e); } } - - ShapefileReader shpReader = new ShapefileReader(shpFiles, false, true, geomFactory); - try { + + try (ShapefileReader shpReader = new ShapefileReader(shpFiles, false, true, geomFactory)) { Class geometryClass = JTSUtilities.findBestGeometryClass(shpReader.getHeader().getShapeType()); int geometryType = SpatialDatabaseService.convertJtsClassToGeometryType(geometryClass); - // TODO ask charset to user? - DbaseFileReader dbfReader = new DbaseFileReader(shpFiles, true, charset); - try { + // TODO ask charset to user? + try (DbaseFileReader dbfReader = new DbaseFileReader(shpFiles, true, charset)) { DbaseFileHeader dbaseFileHeader = dbfReader.getHeader(); String[] fieldsName = new String[dbaseFileHeader.getNumFields() + 1]; @@ -212,19 +210,15 @@ record = shpReader.nextRecord(); } finally { monitor.done(); } - } finally { - dbfReader.close(); - } - } finally { - shpReader.close(); - } + } + } long stopTime = System.currentTimeMillis(); log("info | elapsed time in seconds: " + (1.0 * (stopTime - startTime) / 1000)); return added; } - private CoordinateReferenceSystem readCRS(ShpFiles shpFiles, ShapefileReader shpReader) { + private static CoordinateReferenceSystem readCRS(ShpFiles shpFiles, ShapefileReader shpReader) { try (PrjFileReader prjReader = new PrjFileReader(shpFiles.getReadChannel(ShpFileType.PRJ, shpReader))){ return prjReader.getCoordinateReferenceSystem(); } catch (IOException | FactoryException e) { @@ -233,11 +227,11 @@ private CoordinateReferenceSystem readCRS(ShpFiles shpFiles, ShapefileReader shp } } - private void log(String message) { + private static void log(String message) { System.out.println(message); } - private void log(String message, Exception e) { + private static void log(String message, Exception e) { System.out.println(message); e.printStackTrace(); } diff --git a/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseRecord.java b/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseRecord.java index 3982cc675..72786028f 100644 --- a/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseRecord.java +++ b/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseRecord.java @@ -70,7 +70,8 @@ public void refreshGeomNode(Transaction tx) { * @deprecated This method is of questionable value, since it is better to * query the geometry object directly, outside the result */ - public int getType() { + @Deprecated + public int getType() { //TODO: Get the type from the geometryEncoder return SpatialDatabaseService.convertJtsClassToGeometryType(getGeometry().getClass()); } @@ -119,7 +120,8 @@ public Object[] getPropertyValues(Transaction tx) { return values; } - public Map getProperties(Transaction tx) { + @Override + public Map getProperties(Transaction tx) { Map result = new HashMap<>(); String[] names = getPropertyNames(tx); @@ -174,7 +176,7 @@ protected SpatialDatabaseRecord(Layer layer, Node geomNode, Geometry geometry) { // Private methods - private void checkIsNotReservedProperty(String name) { + private static void checkIsNotReservedProperty(String name) { for (String property : RESERVED_PROPS) { if (property.equals(name)) { throw new SpatialDatabaseException("Updating not allowed for Reserved Property: " + name); diff --git a/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseService.java b/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseService.java index 12caef3d1..a78de7c2e 100644 --- a/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseService.java +++ b/src/main/java/org/neo4j/gis/spatial/SpatialDatabaseService.java @@ -50,7 +50,6 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; -import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.Transaction; /** @@ -169,11 +168,10 @@ public Layer getDynamicLayer(Transaction tx, String name) { public DynamicLayer asDynamicLayer(Transaction tx, Layer layer) { if (layer instanceof DynamicLayer) { return (DynamicLayer) layer; - } else { - Node node = layer.getLayerNode(tx); - node.setProperty(PROP_LAYER_CLASS, DynamicLayer.class.getCanonicalName()); - return (DynamicLayer) LayerUtilities.makeLayerFromNode(tx, indexManager, node); } + Node node = layer.getLayerNode(tx); + node.setProperty(PROP_LAYER_CLASS, DynamicLayer.class.getCanonicalName()); + return (DynamicLayer) LayerUtilities.makeLayerFromNode(tx, indexManager, node); } public DefaultLayer getOrCreateDefaultLayer(Transaction tx, String name) { @@ -273,17 +271,6 @@ public Layer findLayerContainingGeometryNode(Transaction tx, Node geometryNode) return null; } - private Layer getLayerFromChild(Transaction tx, Node child, RelationshipType relType) { - Relationship indexRel = child.getSingleRelationship(relType, Direction.INCOMING); - if (indexRel != null) { - Node layerNode = indexRel.getStartNode(); - if (layerNode.hasProperty(PROP_LAYER)) { - return LayerUtilities.makeLayerFromNode(tx, indexManager, layerNode); - } - } - return null; - } - public boolean containsLayer(Transaction tx, String name) { return getLayer(tx, name) != null; } diff --git a/src/main/java/org/neo4j/gis/spatial/SpatialTopologyUtils.java b/src/main/java/org/neo4j/gis/spatial/SpatialTopologyUtils.java index 436d58f90..4044ac8d4 100644 --- a/src/main/java/org/neo4j/gis/spatial/SpatialTopologyUtils.java +++ b/src/main/java/org/neo4j/gis/spatial/SpatialTopologyUtils.java @@ -50,11 +50,13 @@ private PointResult(Point point, SpatialDatabaseRecord record, double distance) this.distance = distance; } - public Point getKey() { + @Override + public Point getKey() { return point; } - public SpatialDatabaseRecord getValue() { + @Override + public SpatialDatabaseRecord getValue() { return record; } @@ -62,15 +64,18 @@ public double getDistance() { return distance; } - public SpatialDatabaseRecord setValue(SpatialDatabaseRecord value) { + @Override + public SpatialDatabaseRecord setValue(SpatialDatabaseRecord value) { return this.record = value; } - public int compareTo(PointResult other) { + @Override + public int compareTo(PointResult other) { return Double.compare(this.distance, other.distance); } - public String toString() { + @Override + public String toString() { return "Point[" + point + "] distance[" + distance + "] record[" + record + "]"; } } @@ -82,17 +87,16 @@ public static List findClosestEdges(Transaction tx, Point point, La public static List findClosestEdges(Transaction tx, Point point, Layer layer, double distance) { if (layer.getIndex().isEmpty(tx)) { return new ArrayList<>(0); - } else { - ReferencedEnvelope env = new ReferencedEnvelope( - Utilities.fromNeo4jToJts(layer.getIndex().getBoundingBox(tx)), - layer.getCoordinateReferenceSystem(tx)); - if (distance <= 0.0) - distance = env.getSpan(0) / 100.0; - Envelope search = new Envelope(point.getCoordinate()); - search.expandBy(distance); - GeometryFactory factory = layer.getGeometryFactory(); - return findClosestEdges(tx, point, layer, factory.toGeometry(search)); } + ReferencedEnvelope env = new ReferencedEnvelope( + Utilities.fromNeo4jToJts(layer.getIndex().getBoundingBox(tx)), + layer.getCoordinateReferenceSystem(tx)); + if (distance <= 0.0) + distance = env.getSpan(0) / 100.0; + Envelope search = new Envelope(point.getCoordinate()); + search.expandBy(distance); + GeometryFactory factory = layer.getGeometryFactory(); + return findClosestEdges(tx, point, layer, factory.toGeometry(search)); } /** @@ -281,9 +285,8 @@ public static Envelope createEnvelopeForGeometryDensityEstimate(Transaction tx, int count = layer.getIndex().count(tx); if (count > limit) { return createEnvelopeForGeometryDensityEstimate(tx, layer, point, (double) limit / (double) count); - } else { - return Utilities.fromNeo4jToJts(layer.getIndex().getBoundingBox(tx)); } + return Utilities.fromNeo4jToJts(layer.getIndex().getBoundingBox(tx)); } /** diff --git a/src/main/java/org/neo4j/gis/spatial/Utilities.java b/src/main/java/org/neo4j/gis/spatial/Utilities.java index c9ec95f3f..8d8b8a761 100644 --- a/src/main/java/org/neo4j/gis/spatial/Utilities.java +++ b/src/main/java/org/neo4j/gis/spatial/Utilities.java @@ -95,7 +95,6 @@ private static org.neo4j.gis.spatial.rtree.Envelope extractEnvelopeFromFilter(Fi return null; } - @SuppressWarnings("deprecation") private static Envelope extractEnvelopeFromGeometryFilter(GeometryFilterImpl intersectFilter) { if (intersectFilter.getExpression1() instanceof LiteralExpressionImpl) { return extractEnvelopeFromLiteralExpression((LiteralExpressionImpl) intersectFilter.getExpression1()); @@ -109,9 +108,8 @@ private static Envelope extractEnvelopeFromGeometryFilter(GeometryFilterImpl int private static Envelope extractEnvelopeFromLiteralExpression(LiteralExpressionImpl exp) { if (exp.getValue() instanceof Geometry) { return fromJtsToNeo4j(((Geometry) exp.getValue()).getEnvelopeInternal()); - } else { - return null; } + return null; } private static Envelope extractEnvelopeFromBBox(BBOXImpl boundingBox) { diff --git a/src/main/java/org/neo4j/gis/spatial/WKBGeometryEncoder.java b/src/main/java/org/neo4j/gis/spatial/WKBGeometryEncoder.java index 82e197a23..b946ff4c0 100644 --- a/src/main/java/org/neo4j/gis/spatial/WKBGeometryEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/WKBGeometryEncoder.java @@ -24,13 +24,13 @@ import org.locationtech.jts.io.WKBReader; import org.locationtech.jts.io.WKBWriter; import org.neo4j.gis.spatial.encoders.AbstractSinglePropertyEncoder; -import org.neo4j.gis.spatial.encoders.Configurable; import org.neo4j.graphdb.Entity; import org.neo4j.graphdb.Transaction; -public class WKBGeometryEncoder extends AbstractSinglePropertyEncoder implements Configurable { +public class WKBGeometryEncoder extends AbstractSinglePropertyEncoder { - public Geometry decodeGeometry(Entity container) { + @Override + public Geometry decodeGeometry(Entity container) { try { WKBReader reader = new WKBReader(layer.getGeometryFactory()); return reader.read((byte[]) container.getProperty(geomProperty)); diff --git a/src/main/java/org/neo4j/gis/spatial/WKTGeometryEncoder.java b/src/main/java/org/neo4j/gis/spatial/WKTGeometryEncoder.java index 5195dbcd1..ad1c05dba 100644 --- a/src/main/java/org/neo4j/gis/spatial/WKTGeometryEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/WKTGeometryEncoder.java @@ -24,13 +24,13 @@ import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.io.WKTWriter; import org.neo4j.gis.spatial.encoders.AbstractSinglePropertyEncoder; -import org.neo4j.gis.spatial.encoders.Configurable; import org.neo4j.graphdb.Entity; import org.neo4j.graphdb.Transaction; -public class WKTGeometryEncoder extends AbstractSinglePropertyEncoder implements Configurable { +public class WKTGeometryEncoder extends AbstractSinglePropertyEncoder { - public Geometry decodeGeometry(Entity container) { + @Override + public Geometry decodeGeometry(Entity container) { try { WKTReader reader = new WKTReader(layer.getGeometryFactory()); return reader.read((String) container.getProperty(geomProperty)); diff --git a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java index 755de4389..85f4f7f51 100644 --- a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java +++ b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java @@ -37,13 +37,13 @@ public PropertyMapper(String from, String to, String type, String params) { this.params = params; } + @Override public boolean equals(Object obj) { if (obj instanceof PropertyMapper) { PropertyMapper other = (PropertyMapper) obj; return this.key().equals(other.key()); - } else { - return false; } + return false; } protected void save(Transaction tx, Node node) { diff --git a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java index a5b6eab01..77bc80ea3 100644 --- a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java +++ b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java @@ -28,7 +28,6 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; -import org.neo4j.graphdb.ResourceIterable; import org.neo4j.graphdb.Transaction; public class PropertyMappingManager { @@ -88,12 +87,6 @@ private void addPropertyMapper(Transaction tx, PropertyMapper mapper) { save(tx); } - private PropertyMapper removePropertyMapper(Transaction tx, String to) { - PropertyMapper mapper = getPropertyMappers(tx).remove(to); - if (mapper != null) save(tx); - return mapper; - } - public PropertyMapper getPropertyMapper(Transaction tx, String to) { return getPropertyMappers(tx).get(to); } diff --git a/src/main/java/org/neo4j/gis/spatial/encoders/SimpleGraphEncoder.java b/src/main/java/org/neo4j/gis/spatial/encoders/SimpleGraphEncoder.java index aa05032dc..aae0aff3b 100644 --- a/src/main/java/org/neo4j/gis/spatial/encoders/SimpleGraphEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/encoders/SimpleGraphEncoder.java @@ -48,7 +48,7 @@ private GeometryFactory getGeometryFactory() { return geometryFactory; } - private Node testIsNode(Entity container) { + private static Node testIsNode(Entity container) { if (!(container instanceof Node)) { throw new SpatialDatabaseException("Cannot decode non-node geometry: " + container); } @@ -74,7 +74,8 @@ protected void encodeGeometryShape(Transaction tx, Geometry geometry, Entity con } } - public Geometry decodeGeometry(Entity container) { + @Override + public Geometry decodeGeometry(Entity container) { Node node = testIsNode(container); CoordinateList coordinates = new CoordinateList(); TraversalDescription td = new MonoDirectionalTraversalDescription().depthFirst() diff --git a/src/main/java/org/neo4j/gis/spatial/encoders/neo4j/Neo4jGeometry.java b/src/main/java/org/neo4j/gis/spatial/encoders/neo4j/Neo4jGeometry.java index dd8805279..98e3dc356 100644 --- a/src/main/java/org/neo4j/gis/spatial/encoders/neo4j/Neo4jGeometry.java +++ b/src/main/java/org/neo4j/gis/spatial/encoders/neo4j/Neo4jGeometry.java @@ -37,15 +37,18 @@ public Neo4jGeometry(String geometryType, List getCoordinates() { + @Override + public List getCoordinates() { return this.coordinates; } - public CRS getCRS() { + @Override + public CRS getCRS() { return this.crs; } @@ -53,7 +56,8 @@ public static String coordinateString(List return coordinates.stream().map(c -> Arrays.stream(c.getCoordinate()).mapToObj(Double::toString).collect(Collectors.joining(", "))).collect(Collectors.joining(", ")); } - public String toString() { + @Override + public String toString() { return geometryType + "(" + coordinateString(coordinates) + ")[" + crs + "]"; } } diff --git a/src/main/java/org/neo4j/gis/spatial/filter/SearchCQL.java b/src/main/java/org/neo4j/gis/spatial/filter/SearchCQL.java index 7a55ab00a..606659b6f 100644 --- a/src/main/java/org/neo4j/gis/spatial/filter/SearchCQL.java +++ b/src/main/java/org/neo4j/gis/spatial/filter/SearchCQL.java @@ -38,14 +38,12 @@ */ public class SearchCQL implements SearchFilter { - private final Transaction tx; private final Neo4jFeatureBuilder featureBuilder; private final Layer layer; private final org.geotools.api.filter.Filter filter; private final Envelope filterEnvelope; public SearchCQL(Transaction tx, Layer layer, org.geotools.api.filter.Filter filter) { - this.tx = tx; this.layer = layer; this.featureBuilder = Neo4jFeatureBuilder.fromLayer(tx, layer); this.filter = filter; @@ -53,7 +51,6 @@ public SearchCQL(Transaction tx, Layer layer, org.geotools.api.filter.Filter fil } public SearchCQL(Transaction tx, Layer layer, String cql) { - this.tx = tx; this.layer = layer; this.featureBuilder = Neo4jFeatureBuilder.fromLayer(tx, layer); try { diff --git a/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java b/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java index 1d567c621..a85221b39 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java +++ b/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java @@ -79,24 +79,22 @@ private IndexDefinition indexFor(Transaction tx, String indexName, Label label, Thread exists = findThread(name); if (exists != null) { throw new IllegalStateException("Already have thread: " + exists.getName()); - } else { - IndexMaker indexMaker = new IndexMaker(indexName, label, propertyKey); - Thread indexMakerThread = new Thread(indexMaker, name); - if (waitFor) { - indexMakerThread.start(); - try { - indexMakerThread.join(); - if (indexMaker.e != null) { - throw new RuntimeException("Failed to make index " + indexMaker.description(), indexMaker.e); - } - return indexMaker.index; - } catch (InterruptedException e) { - throw new RuntimeException("Failed to make index " + indexMaker.description(), e); - } - } else { - return null; - } } + IndexMaker indexMaker = new IndexMaker(indexName, label, propertyKey); + Thread indexMakerThread = new Thread(indexMaker, name); + if (waitFor) { + indexMakerThread.start(); + try { + indexMakerThread.join(); + if (indexMaker.e != null) { + throw new RuntimeException("Failed to make index " + indexMaker.description(), indexMaker.e); + } + return indexMaker.index; + } catch (InterruptedException e) { + throw new RuntimeException("Failed to make index " + indexMaker.description(), e); + } + } + return null; } public void deleteIndex(IndexDefinition index) { @@ -116,7 +114,7 @@ public void waitForDeletions() { waitForThreads("IndexRemover"); } - private void waitForThreads(String prefix) { + private static void waitForThreads(String prefix) { Thread found; while ((found = findThread(prefix)) != null) { try { @@ -127,7 +125,7 @@ private void waitForThreads(String prefix) { } } - private Thread findThread(String prefix) { + private static Thread findThread(String prefix) { ThreadGroup rootGroup = Thread.currentThread().getThreadGroup(); Thread found = findThread(rootGroup, prefix); if (found != null) { @@ -146,7 +144,7 @@ private Thread findThread(String prefix) { return null; } - private Thread findThread(ThreadGroup group, String prefix) { + private static Thread findThread(ThreadGroup group, String prefix) { Thread[] threads = new Thread[group.activeCount()]; while (group.enumerate(threads, true) == threads.length) { threads = new Thread[threads.length * 2]; @@ -207,9 +205,8 @@ private boolean indexMatches(IndexDefinition anIndex) { List propertyKeys = (List) anIndex.getPropertyKeys(); if (labels.size() == 1 && propertyKeys.size() == 1 && labels.get(0).equals(label) && propertyKeys.get(0).equals(propertyKey)) { return true; - } else { - throw new IllegalStateException("Found index with matching name but different specification: " + anIndex); } + throw new IllegalStateException("Found index with matching name but different specification: " + anIndex); } catch (ClassCastException e) { throw new RuntimeException("Neo4j API Changed - Failed to retrieve IndexDefinition for index " + description() + ": " + e.getMessage()); } @@ -224,11 +221,8 @@ private String description() { private class IndexRemover implements Runnable { private final IndexDefinition index; - private Exception e; - private IndexRemover(IndexDefinition index) { this.index = index; - this.e = null; } @Override @@ -243,7 +237,6 @@ public void run() { tx.commit(); } } catch (Exception e) { - this.e = e; } } } diff --git a/src/main/java/org/neo4j/gis/spatial/index/LayerGeohashPointIndex.java b/src/main/java/org/neo4j/gis/spatial/index/LayerGeohashPointIndex.java index 1dd47e7d9..489e48dc1 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/LayerGeohashPointIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/index/LayerGeohashPointIndex.java @@ -19,7 +19,6 @@ */ package org.neo4j.gis.spatial.index; -import java.util.stream.Stream; import org.apache.lucene.util.BitUtil; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Point; @@ -28,7 +27,6 @@ import org.neo4j.gis.spatial.rtree.filter.SearchFilter; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.StringSearchMode; import org.neo4j.graphdb.Transaction; import org.neo4j.kernel.api.KernelTransaction; @@ -57,7 +55,7 @@ protected String getIndexValueFor(Transaction tx, Node geomNode) { return geoTermToString(encoded); } - private String greatestCommonPrefix(String a, String b) { + private static String greatestCommonPrefix(String a, String b) { int minLength = Math.min(a.length(), b.length()); for (int i = 0; i < minLength; i++) { if (a.charAt(i) != b.charAt(i)) { @@ -67,15 +65,15 @@ private String greatestCommonPrefix(String a, String b) { return a.substring(0, minLength); } - protected Neo4jIndexSearcher searcherFor(Transaction tx, SearchFilter filter) { + @Override + protected Neo4jIndexSearcher searcherFor(Transaction tx, SearchFilter filter) { if (filter instanceof AbstractSearchEnvelopeIntersection) { Envelope referenceEnvelope = ((AbstractSearchEnvelopeIntersection) filter).getReferenceEnvelope(); String maxHash = geoTermToString(encode(referenceEnvelope.getMaxY(), referenceEnvelope.getMaxX())); String minHash = geoTermToString(encode(referenceEnvelope.getMinY(), referenceEnvelope.getMinX())); return new PrefixSearcher(greatestCommonPrefix(minHash, maxHash)); - } else { - throw new UnsupportedOperationException("Geohash Index only supports searches based on AbstractSearchEnvelopeIntersection, not " + filter.getClass().getCanonicalName()); } + throw new UnsupportedOperationException("Geohash Index only supports searches based on AbstractSearchEnvelopeIntersection, not " + filter.getClass().getCanonicalName()); } public static class PrefixSearcher implements Neo4jIndexSearcher { @@ -85,7 +83,8 @@ public static class PrefixSearcher implements Neo4jIndexSearcher { this.prefix = prefix; } - public Iterator search(KernelTransaction ktx, Label label, String propertyKey) { + @Override + public Iterator search(KernelTransaction ktx, Label label, String propertyKey) { return ktx.internalTransaction().findNodes(label, propertyKey, prefix, StringSearchMode.PREFIX).stream().iterator(); } } diff --git a/src/main/java/org/neo4j/gis/spatial/index/LayerHilbertPointIndex.java b/src/main/java/org/neo4j/gis/spatial/index/LayerHilbertPointIndex.java index 718043802..d93dad61a 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/LayerHilbertPointIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/index/LayerHilbertPointIndex.java @@ -29,7 +29,8 @@ protected String indexTypeName() { return "hilbert"; } - protected SpaceFillingCurve makeCurve(Envelope envelope, int maxLevels) { + @Override + protected SpaceFillingCurve makeCurve(Envelope envelope, int maxLevels) { return new HilbertSpaceFillingCurve2D(envelope, maxLevels); } } diff --git a/src/main/java/org/neo4j/gis/spatial/index/LayerSpaceFillingCurvePointIndex.java b/src/main/java/org/neo4j/gis/spatial/index/LayerSpaceFillingCurvePointIndex.java index 0cf732282..406795680 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/LayerSpaceFillingCurvePointIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/index/LayerSpaceFillingCurvePointIndex.java @@ -48,7 +48,6 @@ import java.util.List; import static org.neo4j.internal.helpers.collection.Iterators.emptyResourceIterator; -import static org.neo4j.kernel.api.ResourceTracker.EMPTY_RESOURCE_TRACKER; public abstract class LayerSpaceFillingCurvePointIndex extends ExplicitIndexBackedPointIndex { @@ -81,16 +80,16 @@ private SpaceFillingCurve getCurve(Transaction tx) { protected abstract SpaceFillingCurve makeCurve(Envelope envelope, int maxLevels); - private double getMin(CoordinateSystemAxis axis) { + private static double getMin(CoordinateSystemAxis axis) { double min = axis.getMinimumValue(); if (Double.isInfinite(min)) return 0.0; - else return min; + return min; } - private double getMax(CoordinateSystemAxis axis) { + private static double getMax(CoordinateSystemAxis axis) { double max = axis.getMaximumValue(); if (Double.isInfinite(max)) return 1.0; - else return max; + return max; } @Override @@ -101,13 +100,13 @@ protected Long getIndexValueFor(Transaction tx, Node geomNode) { return getCurve(tx).derivedValueFor(new double[]{point.getX(), point.getY()}); } - protected Neo4jIndexSearcher searcherFor(Transaction tx, SearchFilter filter) { + @Override + protected Neo4jIndexSearcher searcherFor(Transaction tx, SearchFilter filter) { if (filter instanceof AbstractSearchEnvelopeIntersection) { org.neo4j.gis.spatial.rtree.Envelope referenceEnvelope = ((AbstractSearchEnvelopeIntersection) filter).getReferenceEnvelope(); return new RangeSearcher(getCurve(tx).getTilesIntersectingEnvelope(referenceEnvelope.getMin(), referenceEnvelope.getMax(), new StandardConfiguration())); - } else { - throw new UnsupportedOperationException("Hilbert Index only supports searches based on AbstractSearchEnvelopeIntersection, not " + filter.getClass().getCanonicalName()); } + throw new UnsupportedOperationException("Hilbert Index only supports searches based on AbstractSearchEnvelopeIntersection, not " + filter.getClass().getCanonicalName()); } public static class RangeSearcher implements Neo4jIndexSearcher { private final List tiles; @@ -116,7 +115,8 @@ public static class RangeSearcher implements Neo4jIndexSearcher { this.tiles = tiles; } - public Iterator search(KernelTransaction ktx, Label label, String propertyKey) { + @Override + public Iterator search(KernelTransaction ktx, Label label, String propertyKey) { int labelId = ktx.tokenRead().nodeLabel(label.name()); int propId = ktx.tokenRead().propertyKey(propertyKey); ArrayList> results = new ArrayList<>(); @@ -127,7 +127,7 @@ public Iterator search(KernelTransaction ktx, Label label, String property return Iterators.concat(results.iterator()); } - private ResourceIterator nodesByLabelAndProperty(KernelTransaction transaction, int labelId, PropertyIndexQuery query) { + private static ResourceIterator nodesByLabelAndProperty(KernelTransaction transaction, int labelId, PropertyIndexQuery query) { Read read = transaction.dataRead(); if (query.propertyKeyId() == TokenRead.NO_TOKEN || labelId == TokenRead.NO_TOKEN) { diff --git a/src/main/java/org/neo4j/gis/spatial/index/LayerZOrderPointIndex.java b/src/main/java/org/neo4j/gis/spatial/index/LayerZOrderPointIndex.java index 07fbf2980..715727d04 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/LayerZOrderPointIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/index/LayerZOrderPointIndex.java @@ -29,7 +29,8 @@ protected String indexTypeName() { return "zorder"; } - protected SpaceFillingCurve makeCurve(Envelope envelope, int maxLevels) { + @Override + protected SpaceFillingCurve makeCurve(Envelope envelope, int maxLevels) { return new ZOrderSpaceFillingCurve2D(envelope, maxLevels); } } diff --git a/src/main/java/org/neo4j/gis/spatial/index/PropertyEncodingNodeIndex.java b/src/main/java/org/neo4j/gis/spatial/index/PropertyEncodingNodeIndex.java index f0220af90..acd7640c1 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/PropertyEncodingNodeIndex.java +++ b/src/main/java/org/neo4j/gis/spatial/index/PropertyEncodingNodeIndex.java @@ -1,7 +1,6 @@ package org.neo4j.gis.spatial.index; import java.util.Iterator; -import java.util.stream.Stream; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Transaction; diff --git a/src/main/java/org/neo4j/gis/spatial/indexfilter/DynamicIndexReader.java b/src/main/java/org/neo4j/gis/spatial/indexfilter/DynamicIndexReader.java index 4e042a110..95ccb6c28 100644 --- a/src/main/java/org/neo4j/gis/spatial/indexfilter/DynamicIndexReader.java +++ b/src/main/java/org/neo4j/gis/spatial/indexfilter/DynamicIndexReader.java @@ -79,7 +79,7 @@ public DynamicIndexReader(LayerTreeIndexReader index, String query) { this.query = (JSONObject) JSONValue.parse(query); } - private boolean queryIndexNode(Envelope indexNodeEnvelope) { + private static boolean queryIndexNode(Envelope indexNodeEnvelope) { // TODO: Support making the query on each index node for performance return true; } @@ -112,15 +112,13 @@ private boolean stepAndQuery(Node source, JSONObject step) { Node node = rel.getOtherNode(source); step = (JSONObject) step.get("step"); return queryNodeProperties(node, properties) && stepAndQuery(node, step); - } else { - return false; } - } else { - return true; + return false; } + return true; } - private boolean queryNodeProperties(Node node, JSONObject properties) { + private static boolean queryNodeProperties(Node node, JSONObject properties) { if (properties != null) { if (properties.containsKey("geometry")) { System.out.println("Unexpected 'geometry' in query string"); diff --git a/src/main/java/org/neo4j/gis/spatial/osm/OSMDataset.java b/src/main/java/org/neo4j/gis/spatial/osm/OSMDataset.java index c1ccf16fe..3da54880b 100644 --- a/src/main/java/org/neo4j/gis/spatial/osm/OSMDataset.java +++ b/src/main/java/org/neo4j/gis/spatial/osm/OSMDataset.java @@ -75,10 +75,9 @@ public static OSMDataset fromLayer(Transaction tx, OSMLayer layer) { Relationship rel = layer.getLayerNode(tx).getSingleRelationship(SpatialRelationshipTypes.LAYERS, Direction.INCOMING); if (rel == null) { throw new SpatialDatabaseException("Layer '" + layer + "' does not have an associated dataset"); - } else { - String datasetNodeId = rel.getStartNode().getElementId(); - return new OSMDataset(layer, datasetNodeId); } + String datasetNodeId = rel.getStartNode().getElementId(); + return new OSMDataset(layer, datasetNodeId); } public Iterable getAllUserNodes(Transaction tx) { @@ -200,7 +199,8 @@ public Node getNode() { return node; } - public String toString() { + @Override + public String toString() { if (node.hasProperty("name")) { return node.getProperty("name").toString(); } else if (getGeometry() != null) { @@ -226,22 +226,26 @@ public Iterable getWayPoints() { return this; } - public Iterator iterator() { + @Override + public Iterator iterator() { if (wayPointNodeIterator == null || !wayPointNodeIterator.hasNext()) { wayPointNodeIterator = getWayNodes().iterator(); } return this; } - public boolean hasNext() { + @Override + public boolean hasNext() { return wayPointNodeIterator.hasNext(); } - public WayPoint next() { + @Override + public WayPoint next() { return new WayPoint(wayPointNodeIterator.next()); } - public void remove() { + @Override + public void remove() { throw new UnsupportedOperationException("Cannot modify way-point collection"); } diff --git a/src/main/java/org/neo4j/gis/spatial/osm/OSMGeometryEncoder.java b/src/main/java/org/neo4j/gis/spatial/osm/OSMGeometryEncoder.java index b98a45514..47171068d 100644 --- a/src/main/java/org/neo4j/gis/spatial/osm/OSMGeometryEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/osm/OSMGeometryEncoder.java @@ -167,14 +167,17 @@ private static class NodeProxyIterator implements Iterator { traverser = createTraverserInBackwardsCompatibleWay(traversalDescription, first).iterator(); } + @Override public boolean hasNext() { return traverser.hasNext(); } + @Override public Node next() { return traverser.next().endNode().getSingleRelationship(OSMRelation.NODE, Direction.OUTGOING).getEndNode(); } + @Override public void remove() { } @@ -185,12 +188,14 @@ public Iterable getPointNodesFromWayNode(Node wayNode) { final NodeProxyIterator iterator = new NodeProxyIterator(firstNode); return new Iterable() { + @Override public Iterator iterator() { return iterator; } }; } + @Override public Geometry decodeGeometry(Entity container) { Node geomNode = testIsNode(container); try { @@ -234,9 +239,8 @@ private Geometry decodeGeometryFromRelation(Node osmNode, int gtype, GeometryFac } if (outer != null) { return geomFactory.createPolygon(outer, inner.toArray(new LinearRing[inner.size()])); - } else { - return null; } + return null; case GTYPE_MULTIPOLYGON: ArrayList polygons = new ArrayList<>(); try(var relationships = osmNode.getRelationships(Direction.OUTGOING, OSMRelation.MEMBER)){ @@ -257,9 +261,8 @@ private Geometry decodeGeometryFromRelation(Node osmNode, int gtype, GeometryFac } if (polygons.size() > 0) { return geomFactory.createMultiPolygon(polygons.toArray(new Polygon[polygons.size()])); - } else { - return null; } + return null; default: return null; } @@ -277,22 +280,20 @@ private LinearRing getOuterLinearRingFromGeometry(Geometry geometry) { LineString line = (LineString) geometry; if (line.getCoordinates().length < 3) { return null; - } else { - Coordinate[] coords = line.getCoordinates(); - if (!line.isClosed()) { - coords = closeCoords(coords); - } - LinearRing ring = geometry.getFactory().createLinearRing(coords); - if (ring.isValid()) { - return ring; - } else { - return getConvexHull(ring); - } } + Coordinate[] coords = line.getCoordinates(); + if (!line.isClosed()) { + coords = closeCoords(coords); + } + LinearRing ring = geometry.getFactory().createLinearRing(coords); + if (ring.isValid()) { + return ring; + } + return getConvexHull(ring); } else if (geometry instanceof LinearRing) { return (LinearRing) geometry; } else if (geometry instanceof Polygon) { - return (LinearRing) ((Polygon) geometry).getExteriorRing(); + return ((Polygon) geometry).getExteriorRing(); } else { return getConvexHull(geometry); } @@ -304,7 +305,7 @@ private LinearRing getOuterLinearRingFromGeometry(Geometry geometry) { * @param coords original array that is not closed * @return new array one point longer */ - private Coordinate[] closeCoords(Coordinate[] coords) { + private static Coordinate[] closeCoords(Coordinate[] coords) { Coordinate[] nc = new Coordinate[coords.length + 1]; System.arraycopy(coords, 0, nc, 0, coords.length); nc[coords.length] = coords[0]; @@ -444,7 +445,7 @@ private Node makeOSMWay(Transaction tx, Geometry geometry, Node geomNode, int gt return way; } - private Node makeOSMRelation(Geometry geometry, Node geomNode) { + private static Node makeOSMRelation(Geometry geometry, Node geomNode) { relationId++; throw new SpatialDatabaseException("Unimplemented: makeOSMRelation()"); } @@ -516,6 +517,7 @@ private CombinedAttributes getProperties(Node geomNode) { * @param name attribute to check for existence of * @return true if node has the specified attribute */ + @Override public boolean hasAttribute(Node geomNode, String name) { return getProperties(geomNode).hasProperty(name); } @@ -531,6 +533,7 @@ public boolean hasAttribute(Node geomNode, String name) { * @param name attribute to access * @return attribute value, or null */ + @Override public Object getAttribute(Node geomNode, String name) { return getProperties(geomNode).getProperty(name); } @@ -543,6 +546,7 @@ public enum OSMId { this.name = name; } + @Override public String toString() { return name; } diff --git a/src/main/java/org/neo4j/gis/spatial/osm/OSMImporter.java b/src/main/java/org/neo4j/gis/spatial/osm/OSMImporter.java index c0b0cff8c..a78fc0979 100644 --- a/src/main/java/org/neo4j/gis/spatial/osm/OSMImporter.java +++ b/src/main/java/org/neo4j/gis/spatial/osm/OSMImporter.java @@ -120,10 +120,9 @@ int add(String key) { int num = stats.get(key); stats.put(key, ++num); return num; - } else { - stats.put(key, 1); - return 1; } + stats.put(key, 1); + return 1; } /** @@ -138,12 +137,12 @@ String[] getTags() { } Collections.sort(tags); return tags.toArray(new String[0]); - } else { - return new String[0]; } + return new String[0]; } - public String toString() { + @Override + public String toString() { return "TagStats[" + name + "]: " + asList(getTags()); } } @@ -335,7 +334,7 @@ public long reIndex(GraphDatabaseService database, int commitInterval, boolean i return count; } - private List toList(Iterable iterable) { + private static List toList(Iterable iterable) { ArrayList list = new ArrayList<>(); if (iterable != null) { for (Node e : iterable) { @@ -491,7 +490,7 @@ void logNodesFound(long currentTime) { LogCounter found = nodeFindStats.get(type); double rate = 0.0f; if (found.totalTime > 0) { - rate = (1000.0 * (float) found.count / (float) found.totalTime); + rate = (1000.0 * found.count / found.totalTime); } System.out.println("\t" + type + ": \t" + found.count + "/" + (found.totalTime / 1000) @@ -517,7 +516,7 @@ void logNodeAddition(LinkedHashMap tags, logTime = currentTime; } if (currentTime - logTime > 1432) { - System.out.println(new Date(currentTime) + ": Saving " + type + " " + count + " \t(" + (1000.0 * (float) count / (float) (currentTime - firstLogTime)) + " " + type + "/second)"); + System.out.println(new Date(currentTime) + ": Saving " + type + " " + count + " \t(" + (1000.0 * (float) count / (currentTime - firstLogTime)) + " " + type + "/second)"); logTime = currentTime; } } @@ -999,7 +998,8 @@ protected void startRelations() { System.out.println("Finished populating way and relation indexes"); } - protected void optimize() { + @Override + protected void optimize() { for (IndexDefinition index : new IndexDefinition[]{nodeIndex, wayIndex, relationIndex}) { if (index != null) { tx.schema().awaitIndexOnline(index, 30, TimeUnit.MINUTES); @@ -1010,11 +1010,10 @@ protected void optimize() { private Label getLabelHashed(Label label) { if (hashedLabels.containsKey(label)) { return hashedLabels.get(label); - } else { - Label hashed = Label.label(label.name() + "_" + layerHash); - hashedLabels.put(label, hashed); - return hashed; } + Label hashed = Label.label(label.name() + "_" + layerHash); + hashedLabels.put(label, hashed); + return hashed; } private Node findNodeByLabelProperty(Transaction tx, Label label, String propertyKey, Object value) { @@ -1046,15 +1045,14 @@ private IndexDefinition createIndexIfNotNull(IndexDefinition index, Label label, return index; } - private IndexDefinition findIndex(Transaction tx, String indexName, Label label, String propertyKey) { + private static IndexDefinition findIndex(Transaction tx, String indexName, Label label, String propertyKey) { for (IndexDefinition index : tx.schema().getIndexes(label)) { for (String prop : index.getPropertyKeys()) { if (prop.equals(propertyKey)) { if (index.getName().equals(indexName)) { return index; - } else { - throw new IllegalStateException(String.format("Found pre-existing index '%s' for index '%s'", index.getName(), indexName)); } + throw new IllegalStateException(String.format("Found pre-existing index '%s' for index '%s'", index.getName(), indexName)); } } } @@ -1276,7 +1274,8 @@ protected WrappedNode getUserNode(Map nodeProps) { return currentUserNode; } - public String toString() { + @Override + public String toString() { return "OSMGraphWriter: DatabaseService[" + graphDb + "]:txInterval[" + this.txInterval + "]"; } @@ -1319,7 +1318,8 @@ public int getPercentRead() { return (int) (100.0 * getProgress()); } - public int read(char[] cbuf, int offset, int length) + @Override + public int read(char[] cbuf, int offset, int length) throws IOException { int read = super.read(cbuf, offset, length); if (read > 0) charsRead += read; diff --git a/src/main/java/org/neo4j/gis/spatial/osm/OSMLayer.java b/src/main/java/org/neo4j/gis/spatial/osm/OSMLayer.java index b9e160f6c..0587f17e7 100644 --- a/src/main/java/org/neo4j/gis/spatial/osm/OSMLayer.java +++ b/src/main/java/org/neo4j/gis/spatial/osm/OSMLayer.java @@ -57,7 +57,8 @@ public Integer getGeometryType() { * * @param tx */ - public CoordinateReferenceSystem getCoordinateReferenceSystem(Transaction tx) { + @Override + public CoordinateReferenceSystem getCoordinateReferenceSystem(Transaction tx) { try { return DefaultGeographicCRS.WGS84; } catch (Exception e) { @@ -97,9 +98,8 @@ public Node addWay(Transaction tx, Node way, boolean verifyGeom) { // e.printStackTrace(System.err); } return geomNode; - } else { - return null; } + return null; } /** @@ -112,7 +112,8 @@ public Node addWay(Transaction tx, Node way, boolean verifyGeom) { * @param tx * @return iterable over geometry nodes in the dataset */ - public Iterable getAllGeometryNodes(Transaction tx) { + @Override + public Iterable getAllGeometryNodes(Transaction tx) { return indexReader.getAllIndexedNodes(tx); } @@ -257,7 +258,8 @@ public DynamicLayerConfig addSimpleDynamicLayer(Transaction tx, int gtype) { * * @return Style or null */ - public File getStyle() { + @Override + public File getStyle() { // TODO: Replace with a proper resource lookup, since this will be in the JAR return new File("dev/neo4j/neo4j-spatial/src/main/resources/sld/osm/osm.sld"); } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/AbstractGroupGeoPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/AbstractGroupGeoPipe.java index eff43c028..767bf0dcb 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/AbstractGroupGeoPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/AbstractGroupGeoPipe.java @@ -34,7 +34,7 @@ public GeoPipeFlow processNextStart() { if (groupIterator == null) { try { while (true) { - group((GeoPipeFlow) starts.next()); + group(starts.next()); } } catch (NoSuchElementException e) { } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/GeoPipeline.java b/src/main/java/org/neo4j/gis/spatial/pipes/GeoPipeline.java index 7ea8c9471..4a0d18b50 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/GeoPipeline.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/GeoPipeline.java @@ -44,7 +44,6 @@ import org.geotools.api.feature.simple.SimpleFeature; import org.geotools.api.feature.simple.SimpleFeatureType; -import java.io.IOException; import java.util.*; public class GeoPipeline extends Pipeline { @@ -787,7 +786,7 @@ public ReferencedEnvelope getBounds() { }; } - public FeatureCollection toFeatureCollection(final Transaction tx) throws IOException { + public FeatureCollection toFeatureCollection(final Transaction tx) { return toFeatureCollection(tx, Neo4jFeatureBuilder.getTypeFromLayer(tx, layer)); } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java index ef5be9a4f..7cca2e073 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/Pipeline.java @@ -52,8 +52,8 @@ public Pipeline(final Pipe... pipes) { * @param pipes the ordered list of pipes to chain together into a pipeline */ protected void setPipes(final List pipes) { - this.startPipe = (Pipe) pipes.get(0); - this.endPipe = (Pipe) pipes.get(pipes.size() - 1); + this.startPipe = pipes.get(0); + this.endPipe = pipes.get(pipes.size() - 1); for (int i = 1; i < pipes.size(); i++) { pipes.get(i).setStarts((Iterator) pipes.get(i - 1)); } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/RangeFilterPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/RangeFilterPipe.java index 76a8295b2..61e0305f0 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/RangeFilterPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/RangeFilterPipe.java @@ -23,7 +23,8 @@ public RangeFilterPipe(final long low, final long high) { } } - protected S processNextStart() { + @Override + protected S processNextStart() { while (true) { final S s = this.starts.next(); this.counter++; @@ -36,11 +37,13 @@ protected S processNextStart() { } } - public String toString() { + @Override + public String toString() { return String.format("%s (%d, %d)",getClass().getSimpleName(),low,high); } - public void reset() { + @Override + public void reset() { this.counter = -1; super.reset(); } diff --git a/src/main/java/org/neo4j/gis/spatial/utilities/LayerUtilities.java b/src/main/java/org/neo4j/gis/spatial/utilities/LayerUtilities.java index e93d96886..7a4737551 100644 --- a/src/main/java/org/neo4j/gis/spatial/utilities/LayerUtilities.java +++ b/src/main/java/org/neo4j/gis/spatial/utilities/LayerUtilities.java @@ -19,6 +19,8 @@ */ package org.neo4j.gis.spatial.utilities; +import java.lang.reflect.InvocationTargetException; + import org.neo4j.gis.spatial.*; import org.neo4j.gis.spatial.index.IndexManager; import org.neo4j.gis.spatial.index.LayerIndexReader; @@ -82,11 +84,11 @@ public static Layer makeLayerAndNode(Transaction tx, IndexManager indexManager, } catch (Exception e) { throw new SpatialDatabaseException(e); } - } - - private static Layer makeLayerInstance(Transaction tx, IndexManager indexManager, String name, Node layerNode, Class layerClass) throws InstantiationException, IllegalAccessException { + } + + private static Layer makeLayerInstance(Transaction tx, IndexManager indexManager, String name, Node layerNode, Class layerClass) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { if (layerClass == null) layerClass = Layer.class; - Layer layer = layerClass.newInstance(); + Layer layer = layerClass.getDeclaredConstructor().newInstance(); layer.initialize(tx, indexManager, name, layerNode); return layer; } From 4bc4dda6f8e16cf5186d78e28c82fb1b9815833a Mon Sep 17 00:00:00 2001 From: seab Date: Wed, 28 Feb 2024 17:24:12 -0500 Subject: [PATCH 03/10] Match neo4j, java, and package versions of remote --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 415b7c01d..4cd781922 100644 --- a/pom.xml +++ b/pom.xml @@ -2,8 +2,8 @@ - 5.17.0 - 21 + 5.13.0 + 17 org.neo4j.maven.skins default-skin 2 @@ -20,7 +20,7 @@ 4.0.0 neo4j-spatial org.neo4j - 0.31.0-neo4j-5.17.0 + 0.30.0-neo4j-5.13.0 Neo4j - Spatial Components Spatial utilities and components for Neo4j http://components.neo4j.org/${project.artifactId}/${project.version} From ba6b5eae51137208d4dca28379ed368ac7ce7290 Mon Sep 17 00:00:00 2001 From: Andreas Berger Date: Wed, 29 May 2024 16:32:05 +0200 Subject: [PATCH 04/10] fix review comments --- src/main/java/org/neo4j/gis/spatial/index/IndexManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java b/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java index 0172038df..7e93c0c58 100644 --- a/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java +++ b/src/main/java/org/neo4j/gis/spatial/index/IndexManager.java @@ -244,7 +244,7 @@ public void run() { } tx.commit(); } - } catch (Exception e) { + } catch (Exception ignored) { } } } From 7d8c46f0ad11a91b4a72a9cfd93f8855600bbfd0 Mon Sep 17 00:00:00 2001 From: seab Date: Wed, 29 May 2024 13:15:41 -0400 Subject: [PATCH 05/10] neo4j 5.19, polishes --- pom.xml | 6 +- .../data/neo4j/DefaultResourceInfo.java | 7 + .../neo4j/Neo4jSpatialDataStoreFactory.java | 4 +- .../data/neo4j/StyledImageExporter.java | 13 +- .../gis/spatial/AbstractGeometryEncoder.java | 9 +- .../neo4j/gis/spatial/ConsoleListener.java | 3 + .../spatial/attributes/PropertyMapper.java | 2 +- .../attributes/PropertyMappingManager.java | 2 +- .../spatial/encoders/NativePointEncoder.java | 2 +- .../pipes/filtering/FilterProperty.java | 52 ++-- .../gis/spatial/pipes/impl/IdentityPipe.java | 4 +- .../pipes/impl/LastElementIterator.java | 9 +- .../utilities/RelationshipTraversal.java | 2 +- .../gis/spatial/RTreeBulkInsertTest.java | 240 ++++++------------ 14 files changed, 135 insertions(+), 220 deletions(-) diff --git a/pom.xml b/pom.xml index 4cd781922..3e59c6e1c 100644 --- a/pom.xml +++ b/pom.xml @@ -2,8 +2,8 @@ - 5.13.0 - 17 + 5.19.0 + 21 org.neo4j.maven.skins default-skin 2 @@ -20,7 +20,7 @@ 4.0.0 neo4j-spatial org.neo4j - 0.30.0-neo4j-5.13.0 + 0.33.3-neo4j-5.19.0 Neo4j - Spatial Components Spatial utilities and components for Neo4j http://components.neo4j.org/${project.artifactId}/${project.version} diff --git a/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java b/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java index c49207a8a..f983043cf 100644 --- a/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java +++ b/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java @@ -56,42 +56,49 @@ public DefaultResourceInfo(String name, CoordinateReferenceSystem crs, Reference /** * */ + @Override public String getName() { return name; } /** * */ + @Override public String getTitle() { return name; } /** * */ + @Override public String getDescription() { return description; } /** * */ + @Override public Set getKeywords() { return keywords; } /** * */ + @Override public URI getSchema() { return FeatureTypes.DEFAULT_NAMESPACE; } /** * */ + @Override public CoordinateReferenceSystem getCRS() { return crs; } /** * */ + @Override public ReferencedEnvelope getBounds() { return bbox; } diff --git a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java index b3c939960..7879263cc 100644 --- a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java +++ b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java @@ -56,7 +56,7 @@ public Neo4jSpatialDataStoreFactory() { } @Override - public boolean canProcess(Map params) { + public boolean canProcess(Map params) { String type = (String) params.get("dbtype"); if (type != null) { return type.equalsIgnoreCase("neo4j"); @@ -80,7 +80,7 @@ public DataStore createDataStore(Map params) throws IOException { } @Override - public DataStore createNewDataStore(Map params) throws IOException { + public DataStore createNewDataStore(Map params) throws IOException { throw new UnsupportedOperationException("Neo4j Spatial cannot create a new database!"); } diff --git a/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java b/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java index a48d45a43..302143821 100644 --- a/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java +++ b/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java @@ -88,9 +88,8 @@ public void setStyleFiles(String[] files) { public Style getStyle(int i) { if (styleFiles != null && i < styleFiles.length) { return getStyleFromSLDFile(styleFiles[i]); - } else { - return null; } + return null; } /** @@ -121,8 +120,8 @@ private File checkFile(File file) { return file; } - @SuppressWarnings({ "unchecked", "unused" }) - private void debugStore(DataStore store, String[] layerNames) throws IOException { + @SuppressWarnings({ "unused" }) + private static void debugStore(DataStore store, String[] layerNames) throws IOException { for (int i = 0; i < layerNames.length; i++) { System.out.println(asList(store.getTypeNames())); System.out.println(asList(store.getSchema(layerNames[i]).getAttributeDescriptors())); @@ -202,7 +201,7 @@ public void saveLayerImage(String[] layerNames, String sldFile, File imagefile, } if (featureStyle == null) { - featureStyle = createStyleFromGeometry((SimpleFeatureType) featureSource.getSchema(), Color.BLUE, Color.CYAN); + featureStyle = createStyleFromGeometry(featureSource.getSchema(), Color.BLUE, Color.CYAN); System.out.println("Created style from geometry '" + featureSource.getSchema().getGeometryDescriptor().getType() + "': " + featureStyle); } @@ -220,7 +219,7 @@ public void saveLayerImage(String[] layerNames, String sldFile, File imagefile, } } - private Style getStyleFromSLDFile(String sldFile) { + private static Style getStyleFromSLDFile(String sldFile) { Style style = null; if (sldFile != null) { style = createStyleFromSLD(sldFile); @@ -256,7 +255,7 @@ private void saveMapContentToImageFile(MapContent mapContent, File imagefile, Re /** * Create a Style object from a definition in a SLD document */ - private Style createStyleFromSLD(String sldFile) { + private static Style createStyleFromSLD(String sldFile) { try { SLDParser stylereader = new SLDParser(styleFactory, new File(sldFile).toURI().toURL()); Style[] style = stylereader.readXML(); diff --git a/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java b/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java index 38fcb1cd6..d9e9de5b1 100644 --- a/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java @@ -100,7 +100,8 @@ protected Integer encodeGeometryType(String jtsGeometryType) { * of the geometry node. This behaviour can be changed by other domain * models with different encodings. */ - public boolean hasAttribute(Node geomNode, String name) { + @Override + public boolean hasAttribute(Node geomNode, String name) { return geomNode.hasProperty(name); } @@ -111,7 +112,8 @@ public boolean hasAttribute(Node geomNode, String name) { * domain models with different encodings. If the property does not exist, * the method returns null. */ - public Object getAttribute(Node geomNode, String name) { + @Override + public Object getAttribute(Node geomNode, String name) { return geomNode.getProperty(name, null); } @@ -120,7 +122,8 @@ public Object getAttribute(Node geomNode, String name) { * * @return descriptive signature of encoder, type and configuration */ - public String getSignature() { + @Override + public String getSignature() { return "GeometryEncoder(bbox='" + bboxProperty + "')"; } diff --git a/src/main/java/org/neo4j/gis/spatial/ConsoleListener.java b/src/main/java/org/neo4j/gis/spatial/ConsoleListener.java index bb32d7022..959d41ca5 100644 --- a/src/main/java/org/neo4j/gis/spatial/ConsoleListener.java +++ b/src/main/java/org/neo4j/gis/spatial/ConsoleListener.java @@ -42,11 +42,13 @@ public ConsoleListener(PrintStream out) { this.out = out; } + @Override public void begin(int unitsOfWork) { total = unitsOfWork; current = 0; } + @Override public void worked(int workedSinceLastNotification) { current += workedSinceLastNotification; if (total < 1) { @@ -59,6 +61,7 @@ public void worked(int workedSinceLastNotification) { } } + @Override public void done() { } diff --git a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java index 85f4f7f51..cc1691149 100644 --- a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java +++ b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMapper.java @@ -46,7 +46,7 @@ public boolean equals(Object obj) { return false; } - protected void save(Transaction tx, Node node) { + protected void save(Node node) { node.setProperty("from", this.from); node.setProperty("to", this.to); node.setProperty("type", this.type); diff --git a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java index 77bc80ea3..5e3b9043b 100644 --- a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java +++ b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java @@ -77,7 +77,7 @@ private void save(Transaction tx) { } for (PropertyMapper mapper : toSave) { Node node = tx.createNode(); - mapper.save(tx, node); + mapper.save(node); layer.getLayerNode(tx).createRelationshipTo(node, SpatialRelationshipTypes.PROPERTY_MAPPING); } } diff --git a/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java b/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java index 9c9a52de4..541f38bc2 100644 --- a/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java @@ -39,7 +39,7 @@ public class NativePointEncoder extends AbstractGeometryEncoder implements Confi private String locationProperty = DEFAULT_GEOM; private Neo4jCRS crs = Neo4jCRS.findCRS("WGS-84"); - protected GeometryFactory getGeometryFactory() { + protected static GeometryFactory getGeometryFactory() { if (geometryFactory == null) geometryFactory = new GeometryFactory(); return geometryFactory; } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java b/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java index 032fee352..afba866dc 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java @@ -41,37 +41,29 @@ public FilterProperty(String key, Object value, FilterPipe.Filter comparison) { this.value = value; this.comparison = comparison; } - + @Override protected boolean validate(GeoPipeFlow flow) { - final Object leftObject = flow.getProperties().get(key); - switch (comparison) { - case EQUAL: - if (null == leftObject) - return value == null; - return leftObject.equals(value); - case NOT_EQUAL: - if (null == leftObject) - return value != null; - return !leftObject.equals(value); - case GREATER_THAN: - if (null == leftObject || value == null) - return false; - return ((Comparable) leftObject).compareTo(value) == 1; - case LESS_THAN: - if (null == leftObject || value == null) - return false; - return ((Comparable) leftObject).compareTo(value) == -1; - case GREATER_THAN_EQUAL: - if (null == leftObject || value == null) - return false; - return ((Comparable) leftObject).compareTo(value) >= 0; - case LESS_THAN_EQUAL: - if (null == leftObject || value == null) - return false; - return ((Comparable) leftObject).compareTo(value) <= 0; - default: - throw new IllegalArgumentException("Invalid state as no valid filter was provided"); - } + final Object leftObject = flow.getProperties().get(key); + return switch (comparison) { + case EQUAL -> (leftObject == null) ? value == null : leftObject.equals(value); + case NOT_EQUAL -> (leftObject == null) ? value != null : !leftObject.equals(value); + case GREATER_THAN, LESS_THAN, GREATER_THAN_EQUAL, LESS_THAN_EQUAL -> { + if (leftObject == null || value == null) yield false; + if (!(leftObject instanceof Comparable comparable)) + throw new IllegalArgumentException("leftObject is not Comparable"); + + int compareRes = comparable.compareTo(value); + yield switch (comparison) { + case GREATER_THAN -> compareRes > 0; + case LESS_THAN -> compareRes < 0; + case GREATER_THAN_EQUAL -> compareRes >= 0; + case LESS_THAN_EQUAL -> compareRes <= 0; + default -> throw new AssertionError("Unexpected comparison: " + comparison); + }; + } + default -> throw new IllegalArgumentException("Invalid state as no valid filter was provided"); + }; + } } \ No newline at end of file diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java index 02f69e6ed..70528879a 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java @@ -14,7 +14,9 @@ * @author Marko A. Rodriguez (http://markorodriguez.com) */ public class IdentityPipe extends AbstractPipe { - protected S processNextStart() { + + @Override + protected S processNextStart() { return this.starts.next(); } } diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java index 8aa0e42c1..c041c0bd7 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java @@ -13,15 +13,18 @@ public LastElementIterator(final Iterator source) { this.source = source; } - public boolean hasNext() { + @Override + public boolean hasNext() { return source.hasNext(); } - public T next() { + @Override + public T next() { return lastElement = source.next(); } - public void remove() { + @Override + public void remove() { throw new UnsupportedOperationException("remove not supported"); } diff --git a/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java b/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java index 9890a64aa..681e9ba96 100644 --- a/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java +++ b/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java @@ -47,7 +47,7 @@ public static Node getFirstNode(Iterable nodes) { * Iterators, with no access to the original sources and no way to close the resources properly. * So to avoid the Neo4j 4.3 bug with leaked RelationshipTraversalCursor, we need to exhaust the iterator. */ - public static void exhaustIterator(Iterator source) { + public static void exhaustIterator(Iterator source) { while (source.hasNext()) { source.next(); } diff --git a/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java b/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java index 319cd5d45..8246ba56e 100644 --- a/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java +++ b/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java @@ -18,7 +18,6 @@ import org.neo4j.internal.kernel.api.security.SecurityContext; import org.neo4j.kernel.internal.GraphDatabaseAPI; import org.geotools.api.feature.simple.SimpleFeatureType; -import org.geotools.api.referencing.FactoryException; import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import java.io.File; @@ -51,7 +50,7 @@ public void before() throws IOException { } @After - public void after() throws IOException { + public void after() { doCleanShutdown(); } @@ -138,8 +137,6 @@ private EditableLayer getOrCreateSimplePointLayer(String name, String index, Str @Ignore public void shouldInsertSimpleRTree() { int width = 20; - int blockSize = 10000; - CoordinateReferenceSystem crs = DefaultEngineeringCRS.GENERIC_2D; EditableLayer layer = getOrCreateSimplePointLayer("Coordinates", "rtree", "lon", "lat"); List nodes = new ArrayList<>(); try (Transaction tx = db.beginTx()) { @@ -181,7 +178,7 @@ public void shouldInsertSimpleRTree() { } - private List idsToNodes(Transaction tx, List nodeIds) { + private static List idsToNodes(Transaction tx, List nodeIds) { return nodeIds.stream().map(tx::getNodeByElementId).collect(Collectors.toList()); } @@ -288,7 +285,6 @@ public void verifyStructure() { } private class ZOrderIndexMaker implements IndexMaker { - private final SpatialDatabaseService spatial = spatial(); private final String name; private final String insertMode; private final IndexTestConfig config; @@ -405,7 +401,8 @@ private RTreeIndexMaker(String name, String splitMode, String insertMode, int ma this.config = config; } - public EditableLayer setupLayer(Transaction tx) { + @Override + public EditableLayer setupLayer(Transaction tx) { this.nodes = setup(name, "rtree", config.width); this.layer = (EditableLayer) spatial.getLayer(tx, name); layer.getIndex().configure(map( @@ -450,52 +447,52 @@ public void verifyStructure() { */ @Test - public void shouldInsertManyNodesIndividuallyWithGeohash_very_small() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithGeohash_very_small() { insertManyNodesIndividually(new GeohashIndexMaker("Coordinates", "Single", testConfigs.get("very_small")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithGeohash_very_small() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGeohash_very_small() { insertManyNodesInBulk(new GeohashIndexMaker("Coordinates", "Bulk", testConfigs.get("very_small")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithZOrder_very_small() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithZOrder_very_small() { insertManyNodesIndividually(new ZOrderIndexMaker("Coordinates", "Single", testConfigs.get("very_small")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithZOrder_very_small() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithZOrder_very_small() { insertManyNodesInBulk(new ZOrderIndexMaker("Coordinates", "Bulk", testConfigs.get("very_small")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithHilbert_very_small() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithHilbert_very_small() { insertManyNodesIndividually(new HilbertIndexMaker("Coordinates", "Single", testConfigs.get("very_small")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithHilbert_very_small() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithHilbert_very_small() { insertManyNodesInBulk(new HilbertIndexMaker("Coordinates", "Bulk", testConfigs.get("very_small")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_very_small_10() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("very_small")); } @Test - public void shouldInsertManyNodesIndividuallyGreenesSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_very_small_10() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("very_small")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_very_small_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("very_small")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_very_small_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("very_small")); } @@ -504,52 +501,52 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_very_small_10() throws F */ @Test - public void shouldInsertManyNodesIndividuallyWithGeohash_small() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithGeohash_small() { insertManyNodesIndividually(new GeohashIndexMaker("Coordinates", "Single", testConfigs.get("small")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithGeohash_small() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGeohash_small() { insertManyNodesInBulk(new GeohashIndexMaker("Coordinates", "Bulk", testConfigs.get("small")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithZOrder_small() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithZOrder_small() { insertManyNodesIndividually(new ZOrderIndexMaker("Coordinates", "Single", testConfigs.get("small")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithZOrder_small() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithZOrder_small() { insertManyNodesInBulk(new ZOrderIndexMaker("Coordinates", "Bulk", testConfigs.get("small")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithHilbert_small() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithHilbert_small() { insertManyNodesIndividually(new HilbertIndexMaker("Coordinates", "Single", testConfigs.get("small")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithHilbert_small() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithHilbert_small() { insertManyNodesInBulk(new HilbertIndexMaker("Coordinates", "Bulk", testConfigs.get("small")), 5000); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_10() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("small")); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesIndividuallyGreenesSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_small_10() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_small_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("small")); } @@ -558,22 +555,22 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_small_10() throws Factor */ @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_100() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("small")); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesIndividuallyGreenesSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_small_100() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_100() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_small_100() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("small")); } @@ -582,62 +579,62 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_small_100() throws Facto */ @Test - public void shouldInsertManyNodesIndividuallyWithGeohash_medium() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithGeohash_medium() { insertManyNodesIndividually(new GeohashIndexMaker("Coordinates", "Single", testConfigs.get("medium")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithGeohash_medium() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGeohash_medium() { insertManyNodesInBulk(new GeohashIndexMaker("Coordinates", "Bulk", testConfigs.get("medium")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithZOrder_medium() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithZOrder_medium() { insertManyNodesIndividually(new ZOrderIndexMaker("Coordinates", "Single", testConfigs.get("medium")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithZOrder_medium() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithZOrder_medium() { insertManyNodesInBulk(new ZOrderIndexMaker("Coordinates", "Bulk", testConfigs.get("medium")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithHilbert_medium() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithHilbert_medium() { insertManyNodesIndividually(new HilbertIndexMaker("Coordinates", "Single", testConfigs.get("medium")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithHilbert_medium() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithHilbert_medium() { insertManyNodesInBulk(new HilbertIndexMaker("Coordinates", "Bulk", testConfigs.get("medium")), 5000); } @Ignore - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_10() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("medium")); } @Ignore - public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_10() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("medium")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("medium")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("medium")); } @Ignore - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10_merge() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("medium"), true); } @Ignore - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10_merge() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("medium"), true); } @@ -646,32 +643,32 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10_merge() throws */ @Ignore - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_100() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("medium")); } @Ignore - public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_100() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("medium")); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("medium")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("medium")); } @Ignore - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100_merge() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("medium"), true); } @Ignore - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100_merge() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("medium"), true); } @@ -680,52 +677,52 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100_merge() throw */ @Test - public void shouldInsertManyNodesIndividuallyWithGeohash_large() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithGeohash_large() { insertManyNodesIndividually(new GeohashIndexMaker("Coordinates", "Single", testConfigs.get("large")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithGeohash_large() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGeohash_large() { insertManyNodesInBulk(new GeohashIndexMaker("Coordinates", "Bulk", testConfigs.get("large")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithZOrder_large() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithZOrder_large() { insertManyNodesIndividually(new ZOrderIndexMaker("Coordinates", "Single", testConfigs.get("large")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithZOrder_large() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithZOrder_large() { insertManyNodesInBulk(new ZOrderIndexMaker("Coordinates", "Bulk", testConfigs.get("large")), 5000); } @Test - public void shouldInsertManyNodesIndividuallyWithHilbert_large() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithHilbert_large() { insertManyNodesIndividually(new HilbertIndexMaker("Coordinates", "Single", testConfigs.get("large")), 5000); } @Test - public void shouldInsertManyNodesInBulkWithHilbert_large() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithHilbert_large() { insertManyNodesInBulk(new HilbertIndexMaker("Coordinates", "Bulk", testConfigs.get("large")), 5000); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("large")); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesInBulkWithGreenesSplit_large_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_large_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("large")); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_100() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("large")); } @Ignore // takes too long, change to @Test when benchmarking - public void shouldInsertManyNodesInBulkWithGreenesSplit_large_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_large_100() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("large")); } @@ -795,7 +792,7 @@ private void printRTreeImage(String context, Node rootNode, List envel } private void insertManyNodesIndividually(String splitMode, int blockSize, int maxNodeReferences, IndexTestConfig config) - throws FactoryException, IOException { + { insertManyNodesIndividually(new RTreeIndexMaker("Coordinates", splitMode, "Single", maxNodeReferences, config), blockSize); } @@ -841,7 +838,7 @@ private void insertManyNodesIndividually(IndexMaker indexMaker, int blockSize) { * ffmpeg -f image2 -r 12 -i rtree-single/rtree-%d.png -r 12 -s 1280x960 rtree-single2_12fps.mp4 */ @Ignore - public void shouldInsertManyNodesIndividuallyAndGenerateImagesForAnimation() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyAndGenerateImagesForAnimation() throws IOException { IndexTestConfig config = testConfigs.get("medium"); int blockSize = 5; int maxBlockSize = 1000; @@ -870,7 +867,7 @@ public void shouldInsertManyNodesIndividuallyAndGenerateImagesForAnimation() thr int currBlock = 1; while (currBlock < nodes.size()) { List slice = nodes.subList(prevBlock, currBlock); - long startIndexing = System.currentTimeMillis(); + System.currentTimeMillis(); try (Transaction tx = db.beginTx()) { for (String node : slice) { layer.add(tx, tx.getNodeByElementId(node)); @@ -901,12 +898,12 @@ public void shouldInsertManyNodesIndividuallyAndGenerateImagesForAnimation() thr } private void insertManyNodesInBulk(String splitMode, int blockSize, int maxNodeReferences, IndexTestConfig config) - throws FactoryException, IOException { + { insertManyNodesInBulk(new RTreeIndexMaker("Coordinates", splitMode, "Bulk", maxNodeReferences, config, false), blockSize); } private void insertManyNodesInBulk(String splitMode, int blockSize, int maxNodeReferences, IndexTestConfig config, - boolean shouldMergeTrees) throws FactoryException, IOException { + boolean shouldMergeTrees) { insertManyNodesInBulk(new RTreeIndexMaker("Coordinates", splitMode, "Bulk", maxNodeReferences, config, shouldMergeTrees), blockSize); } @@ -944,7 +941,7 @@ private void insertManyNodesInBulk(IndexMaker indexMaker, int blockSize) { * ffmpeg -f image2 -r 12 -i rtree-single/rtree-%d.png -r 12 -s 1280x960 rtree-single2_12fps.mp4 */ @Ignore - public void shouldInsertManyNodesInBulkAndGenerateImagesForAnimation() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkAndGenerateImagesForAnimation() throws IOException { IndexTestConfig config = testConfigs.get("medium"); int blockSize = 1000; int maxNodeReferences = 10; @@ -996,10 +993,7 @@ public void shouldInsertManyNodesInBulkAndGenerateImagesForAnimation() throws Fa @Ignore public void shouldAccessIndexAfterBulkInsertion() throws Exception { - // Use these two lines if you want to examine the output. -// File dbPath = new File("target/var/BulkTest"); -// GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase(dbPath.getCanonicalPath()); - SpatialDatabaseService sdbs = spatial(); + spatial(); EditableLayer layer = getOrCreateSimplePointLayer("Coordinates", "rtree", "lon", "lat"); final long numNodes = 100000; @@ -1071,7 +1065,7 @@ public void shouldBuildTreeFromScratch() throws Exception { //GraphDatabaseService db = this.databases.database("BultTest2"); GraphDatabaseService db = this.db; - SpatialDatabaseService sdbs = spatial(); + spatial(); GeometryEncoder encoder = new SimplePointEncoder(); Method decodeEnvelopes = RTreeIndex.class.getDeclaredMethod("decodeEnvelopes", List.class); @@ -1214,87 +1208,6 @@ private List populateSquareTestData(int width) { return nodes; } - private List populateSquareTestDataHeavy(int width) { - List nodes = populateSquareTestData(width); - Random rand = new Random(42); - - for (int i = 0; i < width / 2; i++) { - try (Transaction tx = db.beginTx()) { - for (int j = 0; j < width / 2; j++) { - Node node = tx.createNode(); - node.addLabel(Label.label("Coordinates")); - - node.setProperty("lat", ((double) rand.nextInt(width / 10) / (double) width)); - node.setProperty("lon", ((double) rand.nextInt(width / 10) / (double) width)); - nodes.add(node.getElementId()); - } - tx.commit(); - } - } - java.util.Collections.shuffle(nodes, new Random(8)); - return nodes; - } - - private List populateSquareWithStreets(int width) { - List nodes = new ArrayList<>(); - double squareValue = 0.25; - for (int i = 1; i < 4; i += 2) { - try (Transaction tx = db.beginTx()) { - for (int j = (int) squareValue * width; j < 2 * squareValue * width; j++) { - Node node = tx.createNode(); - node.addLabel(Label.label("Coordinates")); - node.setProperty("lat", i * squareValue); - node.setProperty("lon", (j + squareValue) / width + squareValue); - nodes.add(node.getElementId()); - Node node2 = tx.createNode(); - node2.addLabel(Label.label("Coordinates")); - node2.setProperty("lat", (j + squareValue) / width + squareValue); - node2.setProperty("lon", i * squareValue); - nodes.add(node2.getElementId()); - - } - tx.commit(); - } - } - for (int i = 0; i < width; i++) { - try (Transaction tx = db.beginTx()) { - - Node node = tx.createNode(); - node.addLabel(Label.label("Coordinates")); - node.setProperty("lat", ((double) i / (double) width)); - node.setProperty("lon", ((double) i / (double) width)); - nodes.add(node.getElementId()); - Node node2 = tx.createNode(); - node2.addLabel(Label.label("Coordinates")); - node2.setProperty("lat", ((double) (width - i) / (double) width)); - node2.setProperty("lon", ((double) i / (double) width)); - nodes.add(node2.getElementId()); - tx.commit(); - } - } - java.util.Collections.shuffle(nodes, new Random(8)); - return nodes; - } - - - private void searchForPos(int numNodes, GraphDatabaseService db) { - System.out.println("Searching with spatial.withinDistance"); - long start = System.currentTimeMillis(); - try (Transaction tx = db.beginTx()) { // 'points',{longitude:15.0,latitude:60.0},100 - Result result = tx.execute("CALL spatial.withinDistance('Coordinates',{longitude:0.5, latitude:0.5},1000.0) yield node"); - int i = 0; - ResourceIterator thing = result.columnAs("node"); - while (thing.hasNext()) { - assertNotNull(thing.next()); - i++; - } - //assertEquals(i, numNodes); - tx.commit(); - } - System.out.println("\t" + (System.currentTimeMillis() - start) + "ms"); - - } - private List setup(String name, String index, int width) { long start = System.currentTimeMillis(); List nodes = populateSquareTestData(width); @@ -1313,7 +1226,7 @@ private static class NodeWithEnvelope { } } - private void checkIndexOverlaps(Transaction tx, Layer layer, TestStats stats) { + private static void checkIndexOverlaps(Transaction tx, Layer layer, TestStats stats) { RTreeIndex index = (RTreeIndex) layer.getIndex(); Node root = index.getIndexRoot(tx); ArrayList> nodes = new ArrayList<>(); @@ -1329,9 +1242,8 @@ private void checkIndexOverlaps(Transaction tx, Layer layer, TestStats stats) { } if (children.isEmpty()) { break; - } else { - nodes.add(children); } + nodes.add(children); } while (true); System.out.println("Comparison of index node areas to root area for " + nodes.size() + " index levels:"); for (int level = 0; level < nodes.size(); level++) { @@ -1342,7 +1254,7 @@ private void checkIndexOverlaps(Transaction tx, Layer layer, TestStats stats) { } } - private double[] calculateOverlap(NodeWithEnvelope root, List nodes) { + private static double[] calculateOverlap(NodeWithEnvelope root, List nodes) { double rootArea = root.envelope.getArea(); double nodesArea = 0.0; for (NodeWithEnvelope entry : nodes) { @@ -1364,7 +1276,7 @@ private List queryRTree(Layer layer, TreeMonitor monitor, TestStats stats) if (layer.getIndex() instanceof RTreeIndex) { getRTreeIndexStats((RTreeIndex) layer.getIndex(), monitor, stats, true, nodes.size()); } else if (layer.getIndex() instanceof ExplicitIndexBackedPointIndex) { - getExplicitIndexBackedIndexStats((ExplicitIndexBackedPointIndex) layer.getIndex(), stats, true, nodes.size()); + getExplicitIndexBackedIndexStats((ExplicitIndexBackedPointIndex) layer.getIndex(), stats); } return nodes; } @@ -1428,7 +1340,7 @@ private void getRTreeIndexStats(RTreeIndex index, TreeMonitor monitor, TestStats } } - private void getExplicitIndexBackedIndexStats(ExplicitIndexBackedPointIndex index, TestStats stats, boolean assertTouches, long countGeometries) { + private static void getExplicitIndexBackedIndexStats(ExplicitIndexBackedPointIndex index, TestStats stats) { IndexTestConfig config = stats.config; ExplicitIndexBackedMonitor monitor = index.getMonitor(); long touched = monitor.getHits() + monitor.getMisses(); @@ -1444,7 +1356,6 @@ private void getExplicitIndexBackedIndexStats(ExplicitIndexBackedPointIndex inde } private class TimedLogger { - String title; long count; long gap; long start; @@ -1455,7 +1366,6 @@ private TimedLogger(String title, long count) { } private TimedLogger(String title, long count, long gap) { - this.title = title; this.count = count; this.gap = gap; this.start = System.currentTimeMillis(); @@ -1480,17 +1390,17 @@ private void log(String line, long number) { } } - private void verifyGeohashIndex(Layer layer) { + private static void verifyGeohashIndex(Layer layer) { LayerIndexReader index = layer.getIndex(); assertTrue("Index should be a geohash index", index instanceof LayerGeohashPointIndex); } - private void verifyHilbertIndex(Layer layer) { + private static void verifyHilbertIndex(Layer layer) { LayerIndexReader index = layer.getIndex(); assertTrue("Index should be a hilbert index", index instanceof LayerHilbertPointIndex); } - private void verifyZOrderIndex(Layer layer) { + private static void verifyZOrderIndex(Layer layer) { LayerIndexReader index = layer.getIndex(); assertTrue("Index should be a Z-Order index", index instanceof LayerZOrderPointIndex); } @@ -1590,7 +1500,7 @@ private void restart() throws IOException { db = databases.database(DEFAULT_DATABASE_NAME); } - private void doCleanShutdown() throws IOException { + private void doCleanShutdown() { try { System.out.println("Shutting down database"); if (databases != null) { @@ -1636,10 +1546,6 @@ public void put(String key, Object value) { data.put(key, value); } - public void get(String key) { - data.get(key); - } - private static String[] headerArray() { return new String[]{"Size Name", "Insert Mode", "Split Mode", "Data Width", "Data Size", "Block Size", "Max Node References"}; } From 2cfb14bb6c598cd3550db579784d510e70e7a5c2 Mon Sep 17 00:00:00 2001 From: Tim Lenz Date: Thu, 30 May 2024 15:38:50 -0400 Subject: [PATCH 06/10] Delete .factorypath --- .factorypath | 299 --------------------------------------------------- 1 file changed, 299 deletions(-) delete mode 100644 .factorypath diff --git a/.factorypath b/.factorypath deleted file mode 100644 index 64fd452f5..000000000 --- a/.factorypath +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f369c98b36536bb0a53142b56128898c7bb47174 Mon Sep 17 00:00:00 2001 From: seab Date: Thu, 30 May 2024 15:41:06 -0400 Subject: [PATCH 07/10] Added back newline at end of file --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index df2184faa..fce635a9a 100644 --- a/pom.xml +++ b/pom.xml @@ -700,3 +700,4 @@ + From 5eefe695253aed7a1b5a66fcfee43913e25be6af Mon Sep 17 00:00:00 2001 From: seab Date: Thu, 30 May 2024 16:35:06 -0400 Subject: [PATCH 08/10] Removed private unused methods, variables and unthrown exceptions --- .../attributes/PropertyMappingManager.java | 8 - .../gis/spatial/RTreeBulkInsertTest.java | 171 ++++-------------- 2 files changed, 35 insertions(+), 144 deletions(-) diff --git a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java index 5af590fc7..02e46c069 100644 --- a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java +++ b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java @@ -89,14 +89,6 @@ private void addPropertyMapper(Transaction tx, PropertyMapper mapper) { save(tx); } - private PropertyMapper removePropertyMapper(Transaction tx, String to) { - PropertyMapper mapper = getPropertyMappers(tx).remove(to); - if (mapper != null) { - save(tx); - } - return mapper; - } - public PropertyMapper getPropertyMapper(Transaction tx, String to) { return getPropertyMappers(tx).get(to); } diff --git a/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java b/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java index 8b1a80e93..6938fd87d 100644 --- a/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java +++ b/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java @@ -43,9 +43,10 @@ import java.util.Random; import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.StreamSupport; + import org.apache.commons.io.FileUtils; import org.geotools.api.feature.simple.SimpleFeatureType; -import org.geotools.api.referencing.FactoryException; import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import org.geotools.data.neo4j.Neo4jFeatureBuilder; import org.geotools.referencing.crs.DefaultEngineeringCRS; @@ -100,7 +101,7 @@ public void before() throws IOException { } @AfterEach - public void after() throws IOException { + public void after() { doCleanShutdown(); } @@ -190,8 +191,6 @@ private EditableLayer getOrCreateSimplePointLayer(String name, String index, Str @Test public void shouldInsertSimpleRTree() { int width = 20; - int blockSize = 10000; - CoordinateReferenceSystem crs = DefaultEngineeringCRS.GENERIC_2D; EditableLayer layer = getOrCreateSimplePointLayer("Coordinates", "rtree", "lon", "lat"); List nodes = new ArrayList<>(); try (Transaction tx = db.beginTx()) { @@ -348,7 +347,6 @@ public void verifyStructure() { private class ZOrderIndexMaker implements IndexMaker { - private final SpatialDatabaseService spatial = spatial(); private final String name; private final String insertMode; private final IndexTestConfig config; @@ -552,23 +550,22 @@ public void shouldInsertManyNodesInBulkWithHilbert_very_small() { } @Test - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_very_small_10() - throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_very_small_10() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("very_small")); } @Test - public void shouldInsertManyNodesIndividuallyGreenesSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_very_small_10() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("very_small")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_very_small_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("very_small")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_very_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_very_small_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("very_small")); } @@ -608,23 +605,23 @@ public void shouldInsertManyNodesInBulkWithHilbert_small() { @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_10() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("small")); } @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesIndividuallyGreenesSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_small_10() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_small_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_small_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("small")); } @@ -634,23 +631,23 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_small_10() throws Factor @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_small_100() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("small")); } @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesIndividuallyGreenesSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_small_100() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_small_100() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("small")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_small_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_small_100() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("small")); } @@ -690,35 +687,35 @@ public void shouldInsertManyNodesInBulkWithHilbert_medium() { @Disabled @Test - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_10() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("medium")); } @Disabled @Test - public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_10() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("medium")); } @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("medium")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("medium")); } @Disabled @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_10_merge() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("medium"), true); } @Disabled @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10_merge() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("medium"), true); } @@ -728,36 +725,36 @@ public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_10_merge() throws @Disabled @Test - public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyWithQuadraticSplit_medium_100() { insertManyNodesIndividually(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("medium")); } @Disabled @Test - public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesIndividuallyGreenesSplit_medium_100() { insertManyNodesIndividually(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("medium")); } @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("medium")); } @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("medium")); } @Disabled @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_medium_100_merge() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("medium"), true); } @Disabled @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100_merge() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_medium_100_merge() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("medium"), true); } @@ -797,25 +794,25 @@ public void shouldInsertManyNodesInBulkWithHilbert_large() { @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_10() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 10, testConfigs.get("large")); } @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_large_10() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_large_10() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 10, testConfigs.get("large")); } @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithQuadraticSplit_large_100() { insertManyNodesInBulk(RTreeIndex.QUADRATIC_SPLIT, 5000, 100, testConfigs.get("large")); } @Disabled // takes too long, change to @Test when benchmarking @Test - public void shouldInsertManyNodesInBulkWithGreenesSplit_large_100() throws FactoryException, IOException { + public void shouldInsertManyNodesInBulkWithGreenesSplit_large_100() { insertManyNodesInBulk(RTreeIndex.GREENES_SPLIT, 5000, 100, testConfigs.get("large")); } @@ -967,7 +964,6 @@ public void shouldInsertManyNodesIndividuallyAndGenerateImagesForAnimation() thr int currBlock = 1; while (currBlock < nodes.size()) { List slice = nodes.subList(prevBlock, currBlock); - long startIndexing = System.currentTimeMillis(); try (Transaction tx = db.beginTx()) { for (String node : slice) { layer.add(tx, tx.getNodeByElementId(node)); @@ -1108,10 +1104,6 @@ public void shouldInsertManyNodesInBulkAndGenerateImagesForAnimation() throws IO @Disabled @Test public void shouldAccessIndexAfterBulkInsertion() { - // Use these two lines if you want to examine the output. -// File dbPath = new File("target/var/BulkTest"); -// GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase(dbPath.getCanonicalPath()); - SpatialDatabaseService sdbs = spatial(); EditableLayer layer = getOrCreateSimplePointLayer("Coordinates", "rtree", "lon", "lat"); final long numNodes = 100000; @@ -1186,7 +1178,6 @@ public void shouldBuildTreeFromScratch() throws Exception { //GraphDatabaseService db = this.databases.database("BultTest2"); GraphDatabaseService db = this.db; - SpatialDatabaseService sdbs = spatial(); GeometryEncoder encoder = new SimplePointEncoder(); Method decodeEnvelopes = RTreeIndex.class.getDeclaredMethod("decodeEnvelopes", List.class); @@ -1331,88 +1322,6 @@ private List populateSquareTestData(int width) { return nodes; } - private List populateSquareTestDataHeavy(int width) { - List nodes = populateSquareTestData(width); - Random rand = new Random(42); - - for (int i = 0; i < width / 2; i++) { - try (Transaction tx = db.beginTx()) { - for (int j = 0; j < width / 2; j++) { - Node node = tx.createNode(); - node.addLabel(Label.label("Coordinates")); - - node.setProperty("lat", ((double) rand.nextInt(width / 10) / (double) width)); - node.setProperty("lon", ((double) rand.nextInt(width / 10) / (double) width)); - nodes.add(node.getElementId()); - } - tx.commit(); - } - } - java.util.Collections.shuffle(nodes, new Random(8)); - return nodes; - } - - private List populateSquareWithStreets(int width) { - List nodes = new ArrayList<>(); - double squareValue = 0.25; - for (int i = 1; i < 4; i += 2) { - try (Transaction tx = db.beginTx()) { - for (int j = (int) squareValue * width; j < 2 * squareValue * width; j++) { - Node node = tx.createNode(); - node.addLabel(Label.label("Coordinates")); - node.setProperty("lat", i * squareValue); - node.setProperty("lon", (j + squareValue) / width + squareValue); - nodes.add(node.getElementId()); - Node node2 = tx.createNode(); - node2.addLabel(Label.label("Coordinates")); - node2.setProperty("lat", (j + squareValue) / width + squareValue); - node2.setProperty("lon", i * squareValue); - nodes.add(node2.getElementId()); - - } - tx.commit(); - } - } - for (int i = 0; i < width; i++) { - try (Transaction tx = db.beginTx()) { - - Node node = tx.createNode(); - node.addLabel(Label.label("Coordinates")); - node.setProperty("lat", ((double) i / (double) width)); - node.setProperty("lon", ((double) i / (double) width)); - nodes.add(node.getElementId()); - Node node2 = tx.createNode(); - node2.addLabel(Label.label("Coordinates")); - node2.setProperty("lat", ((double) (width - i) / (double) width)); - node2.setProperty("lon", ((double) i / (double) width)); - nodes.add(node2.getElementId()); - tx.commit(); - } - } - java.util.Collections.shuffle(nodes, new Random(8)); - return nodes; - } - - - private static void searchForPos(int numNodes, GraphDatabaseService db) { - System.out.println("Searching with spatial.withinDistance"); - long start = System.currentTimeMillis(); - try (Transaction tx = db.beginTx()) { // 'points',{longitude:15.0,latitude:60.0},100 - Result result = tx.execute( - "CALL spatial.withinDistance('Coordinates',{longitude:0.5, latitude:0.5},1000.0) yield node"); - int i = 0; - ResourceIterator thing = result.columnAs("node"); - while (thing.hasNext()) { - assertNotNull(thing.next()); - i++; - } - //assertEquals(i, numNodes); - tx.commit(); - } - System.out.println("\t" + (System.currentTimeMillis() - start) + "ms"); - - } - private List setup(String name, String index, int width) { long start = System.currentTimeMillis(); List nodes = populateSquareTestData(width); @@ -1484,8 +1393,7 @@ private List queryRTree(Layer layer, TreeMonitor monitor, TestStats stats) if (layer.getIndex() instanceof RTreeIndex) { getRTreeIndexStats((RTreeIndex) layer.getIndex(), monitor, stats, true, nodes.size()); } else if (layer.getIndex() instanceof ExplicitIndexBackedPointIndex) { - getExplicitIndexBackedIndexStats((ExplicitIndexBackedPointIndex) layer.getIndex(), stats, true, - nodes.size()); + getExplicitIndexBackedIndexStats((ExplicitIndexBackedPointIndex) layer.getIndex(), stats); } return nodes; } @@ -1525,10 +1433,8 @@ private void getRTreeIndexStats(RTreeIndex index, TreeMonitor monitor, TestStats int matched = monitor.getCaseCounts().get("Geometry Matches"); int indexSize = 0; try (Transaction tx = db.beginTx()) { - for (Node ignored : index.getAllIndexInternalNodes(tx)) { - indexSize++; - } - tx.commit(); + indexSize += StreamSupport.stream(index.getAllIndexInternalNodes(tx).spliterator(), false).count(); + tx.commit(); } stats.put("Index Size", indexSize); stats.put("Found", matched); @@ -1561,8 +1467,7 @@ private void getRTreeIndexStats(RTreeIndex index, TreeMonitor monitor, TestStats } } - private static void getExplicitIndexBackedIndexStats(ExplicitIndexBackedPointIndex index, TestStats stats, - boolean assertTouches, long countGeometries) { + private static void getExplicitIndexBackedIndexStats(ExplicitIndexBackedPointIndex index, TestStats stats) { IndexTestConfig config = stats.config; ExplicitIndexBackedMonitor monitor = index.getMonitor(); long touched = monitor.getHits() + monitor.getMisses(); @@ -1581,7 +1486,6 @@ private static void getExplicitIndexBackedIndexStats(ExplicitIndexBackedPointInd private class TimedLogger { - String title; long count; long gap; long start; @@ -1592,7 +1496,6 @@ private TimedLogger(String title, long count) { } private TimedLogger(String title, long count, long gap) { - this.title = title; this.count = count; this.gap = gap; this.start = System.currentTimeMillis(); @@ -1783,10 +1686,6 @@ public void put(String key, Object value) { data.put(key, value); } - public void get(String key) { - data.get(key); - } - private static String[] headerArray() { return new String[]{"Size Name", "Insert Mode", "Split Mode", "Data Width", "Data Size", "Block Size", "Max Node References"}; From aafc1cd9f68f5661b039fec772bf5268c1e6e0aa Mon Sep 17 00:00:00 2001 From: seab Date: Fri, 31 May 2024 10:51:41 -0400 Subject: [PATCH 09/10] Added back line breaks at end of files --- src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java | 2 +- .../org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java | 2 +- src/main/java/org/geotools/data/neo4j/StyledImageExporter.java | 2 +- .../java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java | 2 +- .../neo4j/gis/spatial/attributes/PropertyMappingManager.java | 2 +- .../java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java | 2 +- .../org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java | 2 +- .../java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java | 2 +- .../org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java | 2 +- .../org/neo4j/gis/spatial/utilities/RelationshipTraversal.java | 2 +- src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java b/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java index 25410d344..f32d94030 100644 --- a/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java +++ b/src/main/java/org/geotools/data/neo4j/DefaultResourceInfo.java @@ -85,4 +85,4 @@ public ReferencedEnvelope getBounds() { return bbox; } -} \ No newline at end of file +} diff --git a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java index e7b6e2407..b796eed43 100644 --- a/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java +++ b/src/main/java/org/geotools/data/neo4j/Neo4jSpatialDataStoreFactory.java @@ -102,4 +102,4 @@ public Param[] getParametersInfo() { return new Param[]{DBTYPE, DIRECTORY}; } -} \ No newline at end of file +} diff --git a/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java b/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java index 7a6b59c83..e6fb9d62d 100644 --- a/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java +++ b/src/main/java/org/geotools/data/neo4j/StyledImageExporter.java @@ -477,4 +477,4 @@ public static void main(String[] args) { databases.shutdown(); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java b/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java index 47fc82f03..8db100ebc 100644 --- a/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/AbstractGeometryEncoder.java @@ -120,4 +120,4 @@ public String getSignature() { // Attributes protected Layer layer; -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java index 02e46c069..01c98e4f1 100644 --- a/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java +++ b/src/main/java/org/neo4j/gis/spatial/attributes/PropertyMappingManager.java @@ -97,4 +97,4 @@ public void addPropertyMapper(Transaction tx, String from, String to, String typ addPropertyMapper(tx, PropertyMapper.fromParams(from, to, type, params)); } -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java b/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java index 82ca9b468..37d0dc066 100644 --- a/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java +++ b/src/main/java/org/neo4j/gis/spatial/encoders/NativePointEncoder.java @@ -102,4 +102,4 @@ public String getSignature() { return "NativePointEncoder(geometry='" + locationProperty + "', bbox='" + bboxProperty + "', crs=" + crs.getCode() + ")"; } -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java b/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java index c5626a7c7..ce146faf5 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/filtering/FilterProperty.java @@ -47,4 +47,4 @@ protected boolean validate(GeoPipeFlow flow) { final Object leftObject = flow.getProperties().get(key); return comparison.compare(leftObject, value); } -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java index 6a5332888..4e17dad7a 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/IdentityPipe.java @@ -39,4 +39,4 @@ public class IdentityPipe extends AbstractPipe { protected S processNextStart() { return this.starts.next(); } -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java b/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java index 99527090e..d55467898 100644 --- a/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java +++ b/src/main/java/org/neo4j/gis/spatial/pipes/impl/LastElementIterator.java @@ -60,4 +60,4 @@ public void reset() { // to achieve in a generic way without a full-stack code change. RelationshipTraversal.exhaustIterator(source); } -} \ No newline at end of file +} diff --git a/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java b/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java index c8a0c3153..5c80b269a 100644 --- a/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java +++ b/src/main/java/org/neo4j/gis/spatial/utilities/RelationshipTraversal.java @@ -55,4 +55,4 @@ public static void exhaustIterator(Iterator source) { source.next(); } } -} \ No newline at end of file +} diff --git a/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java b/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java index 6938fd87d..d1d5dea7b 100644 --- a/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java +++ b/src/test/java/org/neo4j/gis/spatial/RTreeBulkInsertTest.java @@ -1731,4 +1731,4 @@ public static void afterClass() { System.out.println(stats); } } -} \ No newline at end of file +} From f77248a000303b97810ed3db16d396a6d625290c Mon Sep 17 00:00:00 2001 From: seab Date: Mon, 4 Nov 2024 12:43:08 -0500 Subject: [PATCH 10/10] Fix spatial procedures call to be compatible with 5.23+ --- docs/index.html | 2160 +++++++++++++++++ pom.xml | 6 +- .../spatial/procedures/SpatialProcedures.java | 12 +- 3 files changed, 2170 insertions(+), 8 deletions(-) create mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 000000000..639f1bec3 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,2160 @@ + + + + + + + +Neo4j Spatial v5.20.1-SNAPSHOT + + + + + +
+
+

Introduction

+
+
+

Neo4j Spatial is a library of utilities for Neo4j that facilitate the enabling of spatial operations on data. +In particular, you can add spatial indexes to already located data, and perform spatial operations on the data like searching for data within specified regions or within a specified distance of a point of interest. +In addition, classes are provided to expose the data to GeoTools and thereby to GeoTools-enabled applications like GeoServer and uDig.

+
+
+
+one street +
+
+
+

The key features include:

+
+
+
    +
  • +

    Utilities for importing from ESRI Shapefile as well as Open Street Map files

    +
  • +
  • +

    Support for all the common geometry types: Point, LineString, Polygon, etc.

    +
  • +
  • +

    An RTree index for fast searches on geometries

    +
  • +
  • +

    Support for topology operations during the search (contains, within, intersects, covers, disjoint, etc.)

    +
  • +
  • +

    The possibility to enable spatial operations on any graph of data, regardless of the way the spatial data is stored, as long as an adapter is provided to map from the graph to the geometries.

    +
  • +
  • +

    Ability to split a single layer or dataset into multiple sub-layers or views with pre-configured filters

    +
  • +
+
+
+

Get Started

+
+

The easiest way to get started with neo4j-spatial is to grab the server-plugin-*.jar from the latest release, copy it to your $NEO4J_HOME/plugins and restart your Neo4j server.

+
+
+

From there you can use all the Neo4j Spatial Procedures in your Cypher queries to add Nodes to the spatial index and perform a number of spatial point, distance and intersection queries.

+
+
+
Simple Example
+
+
CALL spatial.addPointLayer('geom');
+CALL spatial.layers();
+
+CREATE (n:Node {latitude:60.1,longitude:15.2})
+WITH n
+CALL spatial.addNode('geom',n) YIELD node
+RETURN node;
+
+CALL spatial.bbox('geom',{lon:15.0,lat:60.0}, {lon:15.3, lat:61.0});
+
+
+
+

A good example blog post for how to use them with one of the neo4j drivers, is Spatial Procedures in Legis Graph by William Lyon (Part 1).

+
+ +
+

A general introduction to Neo4j Spatial and a simple example on how to use the Spatial Java APIs can be found in this blog post by Craig Taverner.

+
+
+
+
+
+

Index and Querying

+
+
+

The current index is an RTree index, but it has been developed in an extensible way allowing for other indices to be added if necessary.

+
+
+

Loading and Indexing

+
+

It is possible to load data into the database and add it to the index during the load. +It is also possible to add existing spatial data to the index later. These are two very different scenarios, and in fact can lead to different graph structures, so we will explain them each in turn.

+
+
+

To load data directly into the index, the simplest approach is to start by creating a Layer that suites your data. +There are many possible choices built into Neo4j-Spatial, but two common ones +would be:

+
+
+
    +
  • +

    SimplePointLayer - an editable layer that allows you to add only Points to the database. +This is a good choice if you only have point data and are interested primarily in proximity searches. +This layer includes utility methods specifically for that case.

    +
  • +
  • +

    EditableLayer(Impl) - this is the default editable layer implementation and can handle any type of simple geometry. +This includes Point, LineString and Polygon, as well as Multi-Point, Multi-LineString and Multi-Polygon. +Since it is a generic implementation and cannot know about the topology of your data model, it stores each geometry separately in a single property of a single node. +The storage format is WKB, or 'Well Known Binary', which is a binary format specific to geographic geometries, and also used by the popular open source spatial database PostGIS.

    +
  • +
+
+
+
+
+
+

Layers and GeometryEncoders

+
+
+

The primary type that defines a collection of geometries is the Layer. +A layer contains an index for querying. +In addition, a Layer can be an EditableLayer if it is possible to add and modify geometries in the layer. +The next most important interface is the GeometryEncoder.

+
+
+

The DefaultLayer is the standard layer, making use of the WKBGeometryEncoder for storing all geometry types as byte[] properties of one node per geometry instance.

+
+
+

The OSMLayer is a special layer supporting Open Street Map and storing the OSM model as a single fully connected graph. +The set of Geometries provided by this layer includes Points, LineStrings and Polygons, and as such cannot be exported to Shapefile format, since that format only allows a single Geometry per layer. +However, OMSLayer extends DynamicLayer, which allow it to provide any number of sub-layers, each with a specific geometry type and in addition based on an OSM tag filter. +For example, you can have a layer providing all cycle paths as LineStrings, or a layer providing all lakes as Polygons. +Underneath these are all still backed by the same fully connected graph, but exposed dynamically as apparently separate geometry layers.

+
+
+
+
+

Neo4j Spatial Procedures

+
+
+

Neo4j Spatial is also packaged as a ZIP file that can be unzipped into the Neo4j Server $NEO4J_HOME/plugins directory. +After restarting the server, you should be able to use the following procedure calls from the Cypher query language.

+
+ + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1. Available Spatial Procedures
namedescriptionsignature

"spatial.addLayer"

"Adds a new layer with the given type (see spatial.getAllLayerTypes) and configuration, returns the layer root node"

"spatial.addLayer(name :: STRING?, type :: STRING?, encoderConfig :: STRING?) :: (node :: NODE?)"

"spatial.addLayerWithEncoder"

"Adds a new layer with the given encoder class and configuration, returns the layer root node"

"spatial.addLayerWithEncoder(name :: STRING?, encoder :: STRING?, encoderConfig :: STRING?) :: (node :: NODE?)"

"spatial.addNode"

"Adds the given node to the layer, returns the geometry-node"

"spatial.addNode(layerName :: STRING?, node :: NODE?) :: (node :: NODE?)"

"spatial.addNodes"

"Adds the given nodes list to the layer, returns the count"

"spatial.addNodes(layerName :: STRING?, nodes :: LIST? OF NODE?) :: (count :: INTEGER?)"

"spatial.addPointLayer"

"Adds a new simple point layer, returns the layer root node"

"spatial.addPointLayer(name :: STRING?) :: (node :: NODE?)"

"spatial.addPointLayerWithConfig"

"Adds a new simple point layer with the given configuration, returns the layer root node"

"spatial.addPointLayerWithConfig(name :: STRING?, encoderConfig :: STRING?) :: (node :: NODE?)"

"spatial.addPointLayerXY"

"Adds a new simple point layer with the given properties for x and y coordinates, returns the layer root node"

"spatial.addPointLayerXY(name :: STRING?, xProperty :: STRING?, yProperty :: STRING?) :: (node :: NODE?)"

"spatial.addWKT"

"Adds the given WKT string to the layer, returns the created geometry node"

"spatial.addWKT(layerName :: STRING?, geometry :: STRING?) :: (node :: NODE?)"

"spatial.addWKTLayer"

"Adds a new WKT layer with the given node property to hold the WKT string, returns the layer root node"

"spatial.addWKTLayer(name :: STRING?, nodePropertyName :: STRING?) :: (node :: NODE?)"

"spatial.addWKTs"

"Adds the given WKT string list to the layer, returns the created geometry nodes"

"spatial.addWKTs(layerName :: STRING?, geometry :: LIST? OF STRING?) :: (node :: NODE?)"

"spatial.asExternalGeometry"

"Returns a geometry object as an external geometry type to be returned to a client"

"spatial.asExternalGeometry(geometry :: ANY?) :: (geometry :: ANY?)"

"spatial.asGeometry"

"Returns a geometry object as an internal cypher geometry type, to be passed to other procedures but not returned to a client"

"spatial.asGeometry(geometry :: ANY?) :: (geometry :: ANY?)"

"spatial.bbox"

"Finds all geometry nodes in the given layer within the lower left and upper right coordinates of a box"

"spatial.bbox(layerName :: STRING?, min :: ANY?, max :: ANY?) :: (node :: NODE?)"

"spatial.closest"

"Finds all geometry nodes in the layer within the distance to the given coordinate"

"spatial.closest(layerName :: STRING?, coordinate :: ANY?, distanceInKm :: FLOAT?) :: (node :: NODE?)"

"spatial.decodeGeometry"

"Returns a geometry of a layer node as internal cypher geometry type, to be passed to other procedures but not returned to a client"

"spatial.decodeGeometry(layerName :: STRING?, node :: NODE?) :: (geometry :: ANY?)"

"spatial.getFeatureAttributes"

"Returns feature attributes of the given layer"

"spatial.getFeatureAttributes(name :: STRING?) :: (name :: STRING?)"

"spatial.importOSM"

"Imports the provided osm-file from URI to a layer of the same name, returns the count of data added"

"spatial.importOSM(uri :: STRING?) :: (count :: INTEGER?)"

"spatial.importOSMToLayer"

"Imports the provided osm-file from URI to a layer, returns the count of data added"

"spatial.importOSMToLayer(layerName :: STRING?, uri :: STRING?) :: (count :: INTEGER?)"

"spatial.importShapefile"

"Imports the provided shape-file from URI to a layer of the same name, returns the count of data added"

"spatial.importShapefile(uri :: STRING?) :: (count :: INTEGER?)"

"spatial.importShapefileToLayer"

"Imports the provided shape-file from URI to the given layer, returns the count of data added"

"spatial.importShapefileToLayer(layerName :: STRING?, uri :: STRING?) :: (count :: INTEGER?)"

"spatial.intersects"

"Returns all geometry nodes that intersect the given geometry (shape, polygon) in the layer"

"spatial.intersects(layerName :: STRING?, geometry :: ANY?) :: (node :: NODE?)"

"spatial.layer"

"Returns the layer root node for the given layer name"

"spatial.layer(name :: STRING?) :: (node :: NODE?)"

"spatial.layerTypes"

"Returns the different registered layer types"

"spatial.layerTypes() :: (name :: STRING?, signature :: STRING?)"

"spatial.layers"

"Returns name, and details for all layers"

"spatial.layers() :: (name :: STRING?, signature :: STRING?)"

"spatial.procedures"

"Lists all spatial procedures with name and signature"

"spatial.procedures() :: (name :: STRING?, signature :: STRING?)"

"spatial.removeLayer"

"Removes the given layer"

"spatial.removeLayer(name :: STRING?) :: VOID"

"spatial.setFeatureAttributes"

"Sets the feature attributes of the given layer"

"spatial.setFeatureAttributes(name :: STRING?, attributeNames :: LIST? OF STRING?) :: (node :: NODE?)"

"spatial.updateFromWKT"

"Internal procedure, updates the geometry node with the given id with a new WKT string"

"spatial.updateFromWKT(layerName :: STRING?, geometry :: STRING?, geometryNodeId :: INTEGER?) :: (node :: NODE?)"

"spatial.withinDistance"

"Returns all geometry nodes and their ordered distance in the layer within the distance to the given coordinate"

"spatial.withinDistance(layerName :: STRING?, coordinate :: ANY?, distanceInKm :: FLOAT?) :: (node :: NODE?, distance :: FLOAT?)"

+
+
+
+

Querying

+
+
+

JTS Queries

+
+

Neo4j-Spatial contains the 'Java Topology Suite', a library of geometries and geometry operations. In fact, whenever we use the term 'Geometry' we are refering to the JTS class Geometry. Likewise, the subclasses of Geometry: Point, LineString, Polygon and others are all from JTS. +This means that you can use all the capabilities of JTS to operate on Geometry instances you obtain from the database. If, for example, you perform a search for geometries in a certain area, you will be able to +iterate over the results and for each geometry returned, call JTS methods on that class. For example, you could call geometry.

+
+
+

But +The spatial queries implemented are:

+
+
+
    +
  • +

    Contain

    +
  • +
  • +

    Cover

    +
  • +
  • +

    Covered By

    +
  • +
  • +

    Cross

    +
  • +
  • +

    Disjoint

    +
  • +
  • +

    Intersect

    +
  • +
  • +

    Intersect Window

    +
  • +
  • +

    Overlap

    +
  • +
  • +

    Touch

    +
  • +
  • +

    Within

    +
  • +
  • +

    Within Distance

    +
  • +
+
+
+
+
+
+

Examples

+
+
+

Importing a shapefile

+
+

Neo4j-Spatial includes a utility for importing ESRI Shapefile data. The ShapefileImporter will create a new Layer for each Shapefile imported, and will store each Geometry as WKB in a single property of a single node. All attributes of the Feature will be stored as additional properties of that node. For more information on how this is implemented, you can refer to the classes WKBGeometryEncoder. However, you do not need to know any of that to use this feature. Consider the simple code below.

+
+
+
+
ShapefileImporter importer = new ShapefileImporter(database);
+importer.importFile("shp/highway.shp", "highway", StandardCharsets.UTF_8);
+
+
+
+

This code will import the layer 'highway' from the file 'shp/highway.shp' which is included in the source distribution. This layer will be indexed using an RTree and can therefore be queried using any of the supported spatial operations. See the example on querying layers below.

+
+
+
+

Importing an Open Street Map file

+
+

This is more complex because the current OSMImporter class runs in two phases, the first requiring a batch-inserter on the database. +The is ongoing work to allow for a non-batch-inserter on the entire process, and possibly when you have read this that will already be available. +Refer to the unit tests in classes TestDynamicLayers and TestOSMImport for the latest code for importing OSM data. For example:

+
+
+
+
OSMImporter importer = new OSMImporter("map.osm");
+importer.setCharset(StandardCharsets.UTF_8);
+importer.importFile(db, "map.osm");
+importer.reIndex(db);
+
+
+
+

This code will import the map.osm Open Street Map file, populating the database with a little over 200 geometries, including streets, buildings and points of interest.

+
+
+
+

Executing a spatial query

+
+

Assuming you imported the map.osm file as in the previous example, you can now perform spatial searches on the data. The following example will search within a rectangle for a whatever geometries it can find:

+
+
+
+
SpatialDatabaseService spatial = new SpatialDatabaseService(
+                new IndexManager((GraphDatabaseAPI) graphDb, SecurityContext.AUTH_DISABLED));
+try (Transaction tx = database.beginTx()) {
+        Layer layer = spatial.getLayer(tx, "map.osm");
+        LayerIndexReader spatialIndex = layer.getIndex();
+        System.out.println("Have " + spatialIndex.count(tx) + " geometries in " + spatialIndex.getBoundingBox(tx));
+
+        Envelope bbox = new Envelope(12.94, 12.96, 56.04, 56.06);
+        List<SpatialDatabaseRecord> results = GeoPipeline
+                        .startIntersectWindowSearch(tx, layer, bbox)
+                        .toSpatialDatabaseRecordList();
+
+        doGeometryTestsOnResults(bbox, results);
+        tx.commit();
+}
+
+
+
+

For more examples of query code, refer to the test code in the LayerTest and the SpatialTest classes. +Also review the classes in the org.neo4j.gis.spatial.query package for the full range or search queries currently implemented.

+
+
+
+

Export a shapefile

+
+

The ESRI Shapefile that we imported in the first example above was actually created by Neo4j-Spatial. It is possible to use the results of a query, or a DynamicLayer, to create a new Shapefile using the ShapefileExporter. If we were to export the complete layer created from importing a shapefile, we would not achieve much, but we could use this capability to create shapefiles that are subsets of other layers, or that are created from data in another format.

+
+
+
+
SpatialDatabaseService spatial = new SpatialDatabaseService(
+                new IndexManager((GraphDatabaseAPI) graphDb, SecurityContext.AUTH_DISABLED));
+String wayLayerName;
+try (Transaction tx = database.beginTx()) {
+        OSMLayer layer = (OSMLayer) spatial.getLayer(tx, "map.osm");
+        DynamicLayerConfig wayLayer = layer.addSimpleDynamicLayer(tx, Constants.GTYPE_LINESTRING);
+        wayLayerName = wayLayer.getName();
+        tx.commit();
+}
+ShapefileExporter shpExporter = new ShapefileExporter(database);
+shpExporter.exportLayer(wayLayerName);
+
+
+
+

This example shows how we can import an OSM dataset, which contains data with a number of different Geometry types, and then by using a DynamicLayer to select for only geometries of type 'LineString', we can export all the OSM ways to a Shapefile. This is particularly important when you consider that ESRI Shapefile format does not allow more than one Geometry type per shapefile.

+
+
+
+
SpatialDatabaseService spatial = new SpatialDatabaseService(
+                new IndexManager((GraphDatabaseAPI) graphDb, SecurityContext.AUTH_DISABLED));
+Envelope bbox = new Envelope(12.94, 12.96, 56.04, 56.06);
+List<SpatialDatabaseRecord> results;
+try (Transaction tx = database.beginTx()) {
+        Layer layer = spatial.getLayer(tx, "map.osm");
+        LayerIndexReader spatialIndex = layer.getIndex();
+        System.out.println("Have " + spatialIndex.count(tx) + " geometries in " + spatialIndex.getBoundingBox(tx));
+
+        results = GeoPipeline
+                        .startIntersectWindowSearch(tx, layer, bbox)
+                        .toSpatialDatabaseRecordList();
+
+        spatial.createResultsLayer(tx, "results", results);
+        tx.commit();
+
+}
+ShapefileExporter shpExporter = new ShapefileExporter(database);
+shpExporter.exportLayer("results");
+
+
+
+

This time we import the same OSM model, but query for all geometries inside an envelope, and export that to a new Shapefile.

+
+
+
+

GeoPipes

+
+

Base Layers

+
+

These are the different base layers being used for the following examples:

+
+
+

OsmLayer:

+
+
+
+osmLayer +
+
+
+

IntersectionLayer:

+
+
+
+intersectionLayer +
+
+
+

LinesLayer:

+
+
+
+linesLayer +
+
+
+

BoxesLayer:

+
+
+
+boxesLayer +
+
+
+

ConcaveLayer:

+
+
+
+concaveLayer +
+
+
+

EqualLayer:

+
+
+
+equalLayer +
+
+
+
+
+

GeoPipes Examples

+
+

Below follows a non-exhaustive lists of interesting GeoPipes that can be chained together to contruct a geoprocessing system in while trying to keep the processing as lazy as possible using iterators through the different steps.

+
+
+

Search within geometry

+
+

This pipe performs a search within a geometry in this example, both OSM street geometries should be found in when searching with an enclosing rectangle Envelope.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline
+                .startWithinSearch(tx, osmLayer,
+                                osmLayer.getGeometryFactory().toGeometry(new Envelope(10, 20, 50, 60)));
+
+
+
+
+

Intersecting windows

+
+

The FilterIntersectWindow pipe finds geometries that intersects a given rectangle. This pipeline:

+
+
+
+
GeoPipeline pipeline = GeoPipeline
+                .start(tx, boxesLayer)
+                .windowIntersectionFilter(new Envelope(0, 10, 0, 10));
+
+
+
+

will output:

+
+
+
+intersecting windows +
+
+
+
+

Intersect All

+
+

The IntersectAll pipe intersects geometries of every item contained in the pipeline. +It groups every item in the pipeline in a single item containing the geometry output of the intersection.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, intersectionLayer).intersectAll();
+
+
+
+

Output:

+
+
+
+intersect all +
+
+
+
+

Unite All

+
+

The Union All pipe unites geometries of every item contained in the pipeline. This pipe groups every item in the pipeline in a single item containing the geometry output of the union.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, intersectionLayer).unionAll();
+
+
+
+

Output:

+
+
+
+unite all +
+
+
+
+

Extract Points

+
+

The Extract Points pipe extracts every point from a geometry.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, boxesLayer).extractPoints();
+
+
+
+
+extract points +
+
+
+
+

Filter by cql using complex cql

+
+

This filter will apply the provided CQL expression to the different geometries and only let the matching ones pass.

+
+
+
Example:
+
+
long counter = GeoPipeline.start(tx, osmLayer)
+                .cqlFilter(tx, "highway is not null and geometryType(the_geom) = 'LineString'").count();
+
+
+
+
+

Boundary

+
+

The boundary pipe calculates boundary of every geometry in the pipeline.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, boxesLayer).toBoundary();
+
+
+
+

Output:

+
+
+
+boundary +
+
+
+
+

Centroid

+
+

The Centroid pipe calculates geometry centroid.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, boxesLayer).toCentroid();
+
+
+
+

Output:

+
+
+
+centroid +
+
+
+
+

Convex Hull

+
+

The ConvexHull pipe calculates geometry convex hull.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, concaveLayer).toConvexHull();
+
+
+
+

Output:

+
+
+
+convex hull +
+
+
+
+

Densify

+
+

The Densify pipe inserts extra vertices along the line segments in the geometry. The densified geometry contains no line segment which is longer than the given distance tolerance.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, concaveLayer).densify(5).extractPoints();
+
+
+
+

Output:

+
+
+
+densify +
+
+
+
+

Envelope

+
+

The Envelope pipe computes the minimum bounding box of item geometry.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline
+                .start(tx, linesLayer)
+                .toEnvelope();
+
+
+
+

Output:

+
+
+
+envelope +
+
+
+
+

Export to GML

+
+

This pipe exports every geometry as a GML snippet.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, boxesLayer).createGML();
+for (GeoPipeFlow flow : pipeline) {
+        System.out.println(flow.getProperties().get("GML"));
+}
+
+
+
+

Output:

+
+
+
+
<gml:Polygon>
+        <gml:outerBoundaryIs>
+                <gml:LinearRing>
+                        <gml:coordinates>
+                                12.0,26.0 12.0,27.0 13.0,27.0 13.0,26.0 12.0,26.0
+                        </gml:coordinates>
+                </gml:LinearRing>
+        </gml:outerBoundaryIs>
+</gml:Polygon>
+<gml:Polygon>
+<gml:outerBoundaryIs>
+        <gml:LinearRing>
+                <gml:coordinates>
+                        2.0,3.0 2.0,5.0 6.0,5.0 6.0,3.0 2.0,3.0
+                </gml:coordinates>
+        </gml:LinearRing>
+</gml:outerBoundaryIs>
+</gml:Polygon>
+
+
+
+
+

Intersection

+
+

The Intersection pipe computes a geometry representing the intersection between item geometry and the given geometry.

+
+
+
Example:
+
+
WKTReader reader = new WKTReader(intersectionLayer.getGeometryFactory());
+Geometry geometry = reader.read("POLYGON ((3 3, 3 5, 7 7, 7 3, 3 3))");
+GeoPipeline pipeline = GeoPipeline.start(tx, intersectionLayer).intersect(geometry);
+
+
+
+

Output:

+
+
+
+intersection +
+
+
+
+

Union

+
+

The Union pipe unites item geometry with a given geometry.

+
+
+
Example:
+
+
WKTReader reader = new WKTReader(intersectionLayer.getGeometryFactory());
+Geometry geometry = reader.read("POLYGON ((3 3, 3 5, 7 7, 7 3, 3 3))");
+SearchFilter filter = new SearchIntersectWindow(intersectionLayer, new Envelope(7, 10, 7, 10));
+GeoPipeline pipeline = GeoPipeline.start(tx, intersectionLayer, filter).union(geometry);
+
+
+
+

Output:

+
+
+
+union +
+
+
+
+

Start Point

+
+

The StartPoint pipe finds the starting point of item geometry.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline
+                .start(tx, linesLayer)
+                .toStartPoint();
+
+
+
+

Output:

+
+
+
+start point +
+
+
+
+

End Point

+
+

The EndPoint pipe finds the ending point of item geometry.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline
+                .start(tx, linesLayer)
+                .toEndPoint();
+
+
+
+

Output:

+
+
+
+end point +
+
+
+
+

Max

+
+

The Max pipe computes the maximum value of the specified property and discard items with a value less than the maximum.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, boxesLayer)
+                .calculateArea()
+                .getMax("Area");
+
+
+
+

Output:

+
+
+
+max +
+
+
+
+

Min

+
+

The Min pipe computes the minimum value of the specified property and discard items with a value greater than the minimum.

+
+
+
Example:
+
+
GeoPipeline pipeline = GeoPipeline.start(tx, boxesLayer)
+                .calculateArea()
+                .getMin("Area");
+
+
+
+

Output:

+
+
+
+min +
+
+
+
+

Break up all geometries into points and make density islands

+
+

A more complex Open Street Map example.

+
+
+
Example:
+
+
//step1
+GeoPipeline pipeline = OSMGeoPipeline.startOsm(tx, osmLayer)
+                //step2
+                .extractOsmPoints()
+                //step3
+                .groupByDensityIslands(0.0005)
+                //step4
+                .toConvexHull()
+                //step5
+                .toBuffer(0.0004);
+
+
+
+

Output:

+
+
+
+step1 break up all geometries into points and make density islands +
+
Figure 1. Step1
+
+
+
+step2 break up all geometries into points and make density islands +
+
Figure 2. Step2
+
+
+
+step3 break up all geometries into points and make density islands +
+
Figure 3. Step3
+
+
+
+step4 break up all geometries into points and make density islands +
+
Figure 4. Step4
+
+
+
+step5 break up all geometries into points and make density islands +
+
Figure 5. Step5
+
+
+
+
+
+
+

Appendix: Integrations

+
+ +
+
+
+

Neo4j Spatial in uDig

+
+
+

Neo4j Spatial supports Geotools, and therefor also Geotools based platforms like GeoServer and uDig. For information on setting up and running Neo4j Spatial in GeoServer, see the wiki page [geoserver].

+
+
+

uDig SDK

+
+

Here we will discuss how to set up a development environment for developing code for uDig making use of Neo4j Spatial. For example, if you want to build a uDig plugin that makes use of Neo4j for the data model, or if you have a custom extension to Neo4j Spatial, and want to visualize the data in uDig.

+
+
+
+

Setting up uDig SDK

+
+

Follow the uDig SDK Quickstart instructions on the uDig wiki at http://udig.refractions.net/confluence/display/DEV/1+SDK+Quickstart. It is best to follow those instructions in detail, since all steps are explained and alternatives given. However, for the impatient and foolish, we include simplified instructions here:

+
+
+ +
+
+
+

Adding Neo4j Spatial

+
+

Versions and Dependencies:

+
+
+
    +
  • +

    Note that the trunk version of Neo4j Spatial requires uDig 1.2.1, which was not yet released at the time of writing. However, there was a SNAPSHOT build available at http://udig.refractions.net/files/downloads/branches, dated 10th September. If you cannot find a SNAPSHOT SDK at that date, or more recent, then look in the normal location, or consider building the SDK yourself according to the instructions athttp://udig.refractions.net/confluence/display/ADMIN/02+Development+Environment

    +
  • +
  • +

    If you wish to use uDig 1.2.0 official release, then you need to use an older version of Neo4j Spatial. Specifically any version earlier than the upgrade to GeoTools 2.7 which occurred on the 1st October. +Adding Neo4j Spatial to uDig:

    +
  • +
  • +

    Install Maven2 support for Eclipse:

    +
  • +
  • +

    Go to 'Help→Install New Software' and add a new update site for M2Eclipse using URL http://m2eclipse.sonatype.org/sites/m2e

    +
  • +
  • +

    Select and install the maven integration for eclipse

    +
  • +
  • +

    Get the source code for Neo4j Spatial using: git clone git://github.com/neo4j/neo4j-spatial.git

    +
  • +
  • +

    If you need to use the GeoTools 2.6 version of Neo4j Spatial:

    +
  • +
  • +

    Switch to the end of September version using the command: git checkout 04a0ae

    +
  • +
  • +

    If you plan to develop Neo4j Spatial code from this point, consider making a branch first by going to the newly created directory, typing 'git branch yourbranchname' followed by 'git checkout yourbranchname'

    +
  • +
  • +

    Compile and test the code using: mvn test

    +
  • +
  • +

    This should download all dependencies and run some test cases to make sure everything is OK

    +
  • +
  • +

    Get the source code for eu.udig.catalog.neo4j using: git clone git://gitorious.org/udig-community/neo4j.git eu.udig.catalog.neo4j

    +
  • +
  • +

    you can branch this as well

    +
  • +
  • +

    Start eclipse and import the two projects into the workspace

    +
  • +
  • +

    Use 'File→Import→General→Existing Projects into Workspace'

    +
  • +
  • +

    Browse to the location of your git projects and select and import the neo4j-spatial and eu.udig.catalog.neo4j projects

    +
  • +
  • +

    Create a libs project that wraps some dependent jars

    +
  • +
  • +

    Use 'New Project→Plug-in Development→Plug-in from existing JAR archives'

    +
  • +
  • +

    The files you need to add would have been installed by maven during the 'mvn test' of neo4j-spatial above (on Windows possibly in your User\Username\.m2\repository folder) but can also be downloaded separately

    +
  • +
  • +

    Select the JAR files to add to the libs project:

    +
  • +
  • +

    neo4j-kernel-1.2-1.2.jar

    +
  • +
  • +

    neo4j-index-1.2-1.2.jar

    +
  • +
  • +

    neo4j-graph-algo-0.7-1.2.jar

    +
  • +
  • +

    geronimo-jta_1.1_spec-1.1.1.jar

    +
  • +
  • +

    org.apache.servicemix.bundles.lucene-3.0.1_2.jar

    +
  • +
  • +

    json-simple-1.1.jar

    +
  • +
  • +

    Choose a name like 'org.neo4j.spatial.libs' and create the project

    +
  • +
  • +

    Open the new libs projects MANIFEST.MF file and exit the exports to include all packages in the jars

    +
  • +
+
+
+
+

Testing sample layers in uDig

+
+

When Neo4j Spatial was first installed above, you used 'mvn test' to run some test cases. This will have created a neo4j database with one or more layers, which you can use to display in uDig. However, we will take more control over this by specifically re-running one of the test cases, so we know exactly which layers will be visible.

+
+
+
    +
  • +

    Navigate to the test code for TestDynamicLayers, right click and choose 'Run as → JUnit Test'

    +
  • +
  • +

    This test case will load an OSM dataset for the city of Malmö in Sweden. It will then assign a number of 'dynamic layers', which are pre-configured filters of the dataset, designed to look like separate layers in the GIS, but in reality being views of the same connected graph in the database.

    +
  • +
  • +

    The test will also export these layers as both Shapefile and PNG images for testing purposes in neo4j-spatial\target\export. We will not need them for uDig, since we will be streaming the data directly into the view in uDig. However, you can compare these in uDig later to see the differences.

    +
  • +
  • +

    Open the run configurations dialog and look at the run configuration for uDig that was created earlier when you first ran uDig.

    +
  • +
  • +

    Check the plugins tab and make sure that the two new plugins in your workspace are selected:

    +
  • +
  • +

    org.neo4j.spatial

    +
  • +
  • +

    org.neo4j.spatial.libs

    +
  • +
  • +

    eu.udig.catalog.neo4j

    +
  • +
  • +

    Click 'Validate plugins' and optionally 'Add required plugins' to ensure that all dependencies are met (if needed edit the manifest.mf files of both eu.udig.catalog.neo4j and neo4j-spatial to mark the management dependencies optional: org.neo4j.kernel.impl.management;resolution:=optional, and org.neo4j.kernel.management;resolution:=optional)

    +
  • +
  • +

    Some errors in the projects may be due to invalid characters, such as in 'crossing_bygg_förstadsgatan'. Simply replace it with another name.

    +
  • +
  • +

    Optionally check 'clear workspace' on the main tab

    +
  • +
  • +

    Click the 'Run' button to run uDig with Neo4j support enabled

    +
  • +
  • +

    Once it has started, the eu.udig.catalog.neo4j plugin will scan your home directory for neo4j databases. In the catalog view you should see the one created by the unit test code. If you do not find one, you can import one:

    +
  • +
  • +

    Right click in the catalog view and choose 'Import→Data→Files'

    +
  • +
  • +

    Select the neostore-id file in the database directory to add this database to the catalog

    +
  • +
  • +

    Select one or more layers in the catalog and add them to the current map.

    +
  • +
  • +

    If you select the map2.osm layer, you will get a single layer containing all geometry types recognized as Geometries in the database

    +
  • +
+
+
+
+Udig map2 +
+
+
+
    +
  • +

    If you select one of the other layers, you will get a filtered view of only that data

    +
  • +
  • +

    Adding multiple layers to the map allows you to reorder the layers and modify their styling separately.

    +
  • +
  • +

    Optionally change the projection to look better for northern latitudes:

    +
  • +
  • +

    Click on the projection button below the map, which initially says 'WGS84'

    +
  • +
  • +

    Type 'RT90' into the filter, and then select 'RT90 2.5 gon V (3021)'. This is a common Swedish projection and so will work well for Malmö.

    +
  • +
+
+
+
+Udig map2 rt90 +
+
+
+
    +
  • +

    Try set the style for the map2.osm layer using the sample style file in the Neo4j Spatial source code: neo.sld.xml

    +
  • +
  • +

    Turn off all layers but map2.osm in the layers view, to keep the view simple

    +
  • +
  • +

    Right-click on the map2.osm layer in the layers view and choose 'Style'

    +
  • +
  • +

    Go to the 'XML' option, and mark all XML and delete it

    +
  • +
  • +

    Open neo.sld.xml in a text editor, select all the text and copy and paste it into the Style editor

    +
  • +
  • +

    Click apply and see the map redraw with more complex styling

    +
  • +
+
+
+
+Udig map2 styled +
+
+
+
+

Update: New automatic styles for OSM

+
+

As of the 20th October (commit 506ee4), OSM layers now publish default styles to the GIS. The initial styles are quite simple, but this does allow for nicer out the box experience. Currently, the code will only work in a development environment with certain directory structure, but we’ll make it more generic soon.

+
+
+
+Udig multi styled layers +
+
+
+
+
+
+

Neo4j Spatial Geoserver Plugin

+
+
+ + + + + +
+
Important
+
+Tested with: GeoServer 2.1.1 +
+
+
+

Building

+
+
+
mvn clean install
+
+
+
+
+

Deployment into Geoserver

+
+
    +
  • +

    unzip the target/xxxx-server-plugin.zip into $GEOSERVER_HOME/webapps/geoserver/WEB-INF/lib

    +
  • +
  • +

    restart geoserver

    +
  • +
  • +

    configure a new workspace

    +
  • +
  • +

    configure a new datasource neo4j in your workspace. Point the "The directory path of the Neo4j database:" parameter to the relative (form the GeoServer working dir) or aboslute path to a Neo4j Spatial database with layers (see Neo4j Spatial)

    +
  • +
  • +

    in Layers, do "Add new resource" and choose your Neo4j datastore to see the exisitng Neo4j Spatial layers and add them.

    +
  • +
+
+
+
+

Testing in GeoServer trunk

+
+
    +
  • +

    check out the geoserver source

    +
  • +
+
+
+
+
svn co https://svn.codehaus.org/geoserver/trunk geoserver-trunk
+
+
+
+
    +
  • +

    build the source

    +
  • +
+
+
+
+
cd geoserver-trunk
+mvn clean install
+
+
+
+ +
+
+
+
cd src/web/app
+mvn jetty:run
+
+
+
+ +
+
+
+
    <profile>
+      <id>neo4j</id>
+      <dependencies>
+        <dependency>
+          <groupId>org.neo4j</groupId>
+          <artifactId>neo4j-spatial</artifactId>
+          <version>0.7-SNAPSHOT</version>
+        </dependency>
+      </dependencies>
+    </profile>
+
+
+
+
    +
  • +

    start the GeoServer webapp again with the added neo4j profile

    +
  • +
+
+
+
+
cd $GEOSERVER_SRC/src/web/app
+mvn jetty:run -Pneo4j
+
+
+
+ +
+
+

For more info head over to Neo4j Wiki on Geoserver

+
+
+
+
+
+

Neo4j Spatial in GeoServer

+
+
+

Neo4j Spatial includes built-in support for a GeoTools data store. This means it is, in principle, directly usable inside GeoServer. This document will discuss how to get it up and running in GeoServer. If you are interested in a desktop GIS, take a look at Neo4j Spatial in uDig.

+
+
+

Installing Neo4j-Spatial in GeoServer

+
+

Installing GeoServer

+
+

First of all you need to download and install geoserver from http://geoserver.org/display/GEOS/Download. For detailed installation instructions, refer to the official GeoServer documentation athttp://docs.geoserver.org/stable/en/user/installation/index.html +Here we provide very basic instructions, with factors to consider regarding installing GeoServer with Neo4j Spatial:

+
+
+
    +
  • +

    Choose the right version for the version of Neo4j Spatial you are going to use:

    +
  • +
  • +

    Neo4j-Spatial trunk is currently coded to work with GeoTools 2.7, so this means we need to load it into GeoServer 2.1 or later. The version we tested against was geoserver-2.1-beta1

    +
  • +
  • +

    If you want to deploy on the stable release of GeoServer 2.0.2, then you can use an older Neo4j-Spatial, or modify the code to work with GeoTools 2.6 (the differences are small). The last version of Neo4j Spatial that works with the GeoServer 2.0 series, is from the end of September 2010.

    +
  • +
  • +

    If you already have a servlet container running, you can download the WAR version, otherwise download the BIN version (or the Windows installer if on Windows). Install and run using the included instructions in geoserver.

    +
  • +
  • +

    Once installed, open a web browser on http://localhost:8080/geoserver/web/ (or other location is you configured it differently) to test that geoserver is runnning correctly.

    +
  • +
+
+
+
+

Adding Neo4j Spatial

+
+

Install Neo4j-Spatial by copying the following JAR files into the in the GeoServer directory webapps/geoserver/WEB-INF/lib:

+
+
+
    +
  • +

    json-simple-1.1.jar

    +
  • +
  • +

    geronimo-jta_1.1_spec-1.1.1.jar

    +
  • +
  • +

    neo4j-kernel-1.2-1.2.M03.jar

    +
  • +
  • +

    neo4j-index-1.2-1.2.M03.jar

    +
  • +
  • +

    neo4j-spatial.jar

    +
  • +
+
+
+

Getting this last jar can be achieved by using maven to compile from source, or by simply browsing to the maven repository website at http://m2.neo4j.org/org/neo4j/neo4j-spatial/

+
+
+

At the time of writing the latest JAR was:

+
+
+ +
+
+
+
+

Visualizing Neo4j Spatial data in GeoServer

+
+

These instructions lead you through getting started with adding some test layers from Neo4j Spatial to the running GeoServer

+
+
+

Login as 'admin' with password 'geoserver', unless you have changed those in the security/users.properties file during installation

+
+
+
+Geoserver 1 logged in +
+
+
+
+

Add a data source

+
+

Go to 'Stores' and click 'Add a new Store'

+
+
+
+Geoserver 2 add new store +
+
+
+

Name the data source and add the path to the Neo4j Database you have your layers in

+
+
+
+Geoserver 3 path to neo4j db +
+
+
+
    +
  • +

    One option for the database location is a database created using the unit tests in Neo4j Spatial. The rest of this wiki assumes that you ran the TestDynamicLayers unit test which loads an OSM dataset for the city of Malmö in Sweden, and then creates a number of Dynamic Layers (or views) on this data, which we can publish in GeoServer.

    +
  • +
  • +

    If you do use the unit test for the sample database, then the location of the database will be in the target/var/neo4j-db directory of the Neo4j Source code.

    +
  • +
  • +

    Type the URL as the full path to the neostore-id file in the database directory

    +
  • +
+
+
+
+

Publish from data source

+
+

Now we will publish a layer from the data source

+
+
+

Click 'Neo4j' under 'Vector Data Sources' and then click 'Add new layer'

+
+
+
+Geoserver 5 choose new layer +
+
+
+

Choose the 'Neo4j Data Store'

+
+
+
+Geoserver 6 choose new layer2 +
+
+
+

Choose a layer and click 'Publish' +GeoServer seems to have trouble detecting the CRS and bounds, so we have to enter this manually

+
+
+
+Geoserver 6 publish layer settings +
+
+
+
    +
  • +

    Type CRS manually into the 'Declared SRS' field. For OSM data (as published by the TestDynamicLayers code) use EPSG:4326

    +
  • +
  • +

    Click 'Compute from data' to get the native bounding box

    +
  • +
  • +

    Copy and paste all these fields into the Lat/Lon bounding box (for some reason, 'Compute from native bounds' is not working)

    +
  • +
  • +

    Save the layer

    +
  • +
  • +

    Repeat this for as many layers as you want to publish

    +
  • +
+
+
+
+Geoserver 7 four layers published +
+
+
+
+

Previewing layers

+
+

Preview one of the published layers

+
+
+

Go to the layer preview page and select the layer and 'OpenLayers' or other option for preview.

+
+
+
+Geoserver 8 single layer preview +
+
+
+

Preview multiple layers

+
+
+
    +
  • +

    Add a layer group, by clicking on 'layer groups'

    +
  • +
+
+
+
+Geoserver 9 layer groups +
+
+
+
    +
  • +

    and then click 'add new layer group'.

    +
  • +
+
+
+
+Geoserver 10 layer group settings +
+
+
+
    +
  • +

    Enter the name, and copy the bounds from one of the layers you plan to add. The 'Generate Bounds' function does not seem to work.

    +
  • +
  • +

    Enter the CRS as the same as the one used in one of the layers you plan to add.

    +
  • +
  • +

    Then click 'Add Layer' and select a layer to add to the group. Repeat this for as many layers as you plan to add.

    +
  • +
  • +

    Save the group and then go to the Layer Preview and you will see the group as an option to preview.

    +
  • +
+
+
+
+Geoserver 11 layer preview list +
+
+
+
    +
  • +

    Select 'OpenLayers' to preview in a dynamic map that can be zoomed in.

    +
  • +
+
+
+
+Geoserver 12 layer group preview +
+
+
+
+

Controlling layer style

+
+

If you want to change the styles of the layers, one option is to go back to the layers list, select a layer, click the display tab and edit the styling information. This will also affect the preview in openlayers.

+
+
+
+Geoserver 13 layers preview with styles +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 29cadd6e1..257d5cee8 100644 --- a/pom.xml +++ b/pom.xml @@ -2,8 +2,8 @@ - 5.20.0 - 17 + 5.24.2 + 21 org.neo4j.maven.skins default-skin 2 @@ -20,7 +20,7 @@ 4.0.0 neo4j-spatial org.neo4j - 5.20.1-SNAPSHOT + 5.24.2-SNAPSHOT Neo4j - Spatial Components Spatial utilities and components for Neo4j https://components.neo4j.org/${project.artifactId}/${project.version} diff --git a/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java b/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java index 02f7fc2e1..f6818b8d0 100644 --- a/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java +++ b/src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java @@ -72,6 +72,7 @@ import org.neo4j.graphdb.Transaction; import org.neo4j.internal.kernel.api.procs.ProcedureSignature; import org.neo4j.internal.kernel.api.security.SecurityContext; +import org.neo4j.kernel.api.CypherScope; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.procedure.GlobalProcedures; import org.neo4j.kernel.internal.GraphDatabaseAPI; @@ -160,11 +161,12 @@ public Stream listProcedures() { GlobalProcedures procedures = ((GraphDatabaseAPI) db).getDependencyResolver() .resolveDependency(GlobalProcedures.class); Stream.Builder builder = Stream.builder(); - for (ProcedureSignature proc : procedures.getCurrentView().getAllProcedures()) { - if (proc.name().namespace()[0].equals("spatial")) { - builder.accept(new NameResult(proc.name().toString(), proc.toString())); - } - } + + procedures.getCurrentView().getAllProcedures(CypherScope.CYPHER_5) + .filter(proc -> proc.name().namespace()[0].equals("spatial")) + .map(proc -> new NameResult(proc.name().toString(), proc.toString())) + .forEach(builder::accept); + return builder.build(); }