Skip to content

Commit f330076

Browse files
committed
Support removeNode and removeNode procedures
1 parent 96e9193 commit f330076

File tree

2 files changed

+76
-14
lines changed

2 files changed

+76
-14
lines changed

src/main/java/org/neo4j/gis/spatial/procedures/SpatialProcedures.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,27 @@ public Stream<CountResult> addNodesToLayer(@Name("layerName") String name, @Name
517517
return Stream.of(new CountResult(layer.addAll(nodes)));
518518
}
519519

520+
@Procedure(value="spatial.removeNode", mode=WRITE)
521+
@Description("Removes the given node from the layer, returns the geometry-node")
522+
public Stream<NodeResult> removeNodeFromLayer(@Name("layerName") String name, @Name("node") Node node) {
523+
EditableLayer layer = getEditableLayerOrThrow(name);
524+
layer.removeFromIndex(node.getId());
525+
return streamNode(node);
526+
}
527+
528+
@Procedure(value="spatial.removeNodes", mode=WRITE)
529+
@Description("Removes the given nodes from the layer, returns the count of nodes removed")
530+
public Stream<CountResult> removeNodesFromLayer(@Name("layerName") String name, @Name("nodes") List<Node> nodes) {
531+
EditableLayer layer = getEditableLayerOrThrow(name);
532+
//TODO optimize bulk node removal from RTree like we have done for node additions
533+
int before = layer.getIndex().count();
534+
for (Node node : nodes) {
535+
layer.removeFromIndex(node.getId());
536+
}
537+
int after = layer.getIndex().count();
538+
return Stream.of(new CountResult(before - after));
539+
}
540+
520541
@Procedure(value="spatial.addWKT", mode=WRITE)
521542
@Description("Adds the given WKT string to the layer, returns the created geometry node")
522543
public Stream<NodeResult> addGeometryWKTToLayer(@Name("layerName") String name, @Name("geometry") String geometryWKT) throws ParseException {

src/test/java/org/neo4j/gis/spatial/procedures/SpatialProceduresTest.java

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -708,60 +708,101 @@ public void add_two_nodes_to_the_spatial_layer() throws Exception {
708708
assertEquals(false, res.hasNext());
709709
}
710710
);
711+
Result removeResult = db.execute("CALL spatial.removeNode('geom',$node) YIELD node RETURN node", map("node", node1));
712+
Assert.assertEquals(node1,removeResult.next().get("node"));
713+
removeResult.close();
714+
testResult(db, "CALL spatial.withinDistance('geom',{lon:15.0,lat:60.0},100)", res -> {
715+
assertEquals(true, res.hasNext());
716+
assertEquals(node2, res.next().get("node"));
717+
assertEquals(false, res.hasNext());
718+
}
719+
);
711720
}
712721

713722
@Test
714723
public void add_many_nodes_to_the_simple_point_layer_using_addNodes() throws Exception {
715724
// Playing with this number in both tests leads to rough benchmarking of the addNode/addNodes comparison
716725
int count = 1000;
717-
execute("CALL spatial.addLayer('poi','SimplePoint','')");
726+
execute("CALL spatial.addLayer('simple_poi','SimplePoint','')");
718727
String query = "UNWIND range(1,{count}) as i\n" +
719-
"CREATE (n:Point {latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)})\n" +
728+
"CREATE (n:Point {id:i, latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)})\n" +
720729
"WITH collect(n) as points\n" +
721-
"CALL spatial.addNodes('poi',points) YIELD count\n" +
730+
"CALL spatial.addNodes('simple_poi',points) YIELD count\n" +
722731
"RETURN count";
723732
testCountQuery("addNodes", query, count, "count", map("count", count));
733+
testRemoveNodes("simple_poi", count);
724734
}
725735

726736
@Test
727737
public void add_many_nodes_to_the_simple_point_layer_using_addNode() throws Exception {
728738
// Playing with this number in both tests leads to rough benchmarking of the addNode/addNodes comparison
729739
int count = 1000;
730-
execute("CALL spatial.addLayer('poi','SimplePoint','')");
740+
execute("CALL spatial.addLayer('simple_poi','SimplePoint','')");
731741
String query = "UNWIND range(1,{count}) as i\n" +
732-
"CREATE (n:Point {latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)})\n" +
742+
"CREATE (n:Point {id:i, latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)})\n" +
733743
"WITH n\n" +
734-
"CALL spatial.addNode('poi',n) YIELD node\n" +
744+
"CALL spatial.addNode('simple_poi',n) YIELD node\n" +
735745
"RETURN count(node)";
736746
testCountQuery("addNode", query, count, "count(node)", map("count", count));
747+
testRemoveNode("simple_poi", count);
737748
}
738749

739750
@Test
740751
public void add_many_nodes_to_the_native_point_layer_using_addNodes() throws Exception {
741752
// Playing with this number in both tests leads to rough benchmarking of the addNode/addNodes comparison
742753
int count = 1000;
743-
execute("CALL spatial.addLayer('poi','NativePoint','')");
754+
execute("CALL spatial.addLayer('native_poi','NativePoint','')");
744755
String query = "UNWIND range(1,{count}) as i\n" +
745-
"WITH Point({latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)}) AS location\n" +
746-
"CREATE (n:Point {location:location})\n" +
756+
"WITH i, Point({latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)}) AS location\n" +
757+
"CREATE (n:Point {id: i, location:location})\n" +
747758
"WITH collect(n) as points\n" +
748-
"CALL spatial.addNodes('poi',points) YIELD count\n" +
759+
"CALL spatial.addNodes('native_poi',points) YIELD count\n" +
749760
"RETURN count";
750761
testCountQuery("addNodes", query, count, "count", map("count", count));
762+
testRemoveNodes("native_poi", count);
751763
}
752764

753765
@Test
754766
public void add_many_nodes_to_the_native_point_layer_using_addNode() throws Exception {
755767
// Playing with this number in both tests leads to rough benchmarking of the addNode/addNodes comparison
756768
int count = 1000;
757-
execute("CALL spatial.addLayer('poi','NativePoint','')");
769+
execute("CALL spatial.addLayer('native_poi','NativePoint','')");
758770
String query = "UNWIND range(1,{count}) as i\n" +
759-
"WITH Point({latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)}) AS location\n" +
760-
"CREATE (n:Point {location:location})\n" +
771+
"WITH i, Point({latitude:(56.0+toFloat(i)/100.0),longitude:(12.0+toFloat(i)/100.0)}) AS location\n" +
772+
"CREATE (n:Point {id: i, location:location})\n" +
761773
"WITH n\n" +
762-
"CALL spatial.addNode('poi',n) YIELD node\n" +
774+
"CALL spatial.addNode('native_poi',n) YIELD node\n" +
763775
"RETURN count(node)";
764776
testCountQuery("addNode", query, count, "count(node)", map("count", count));
777+
testRemoveNode("native_poi", count);
778+
}
779+
780+
private void testRemoveNode(String layer, int count) {
781+
// Check all nodes are there
782+
testCountQuery("withinDistance", "CALL spatial.withinDistance('" + layer + "',{lon:15.0,lat:60.0},1000) YIELD node RETURN count(node)", count, "count(node)", null);
783+
// Now remove half the points
784+
String remove = "UNWIND range(1,{count}) as i\n" +
785+
"MATCH (n:Point {id:i})\n" +
786+
"WITH n\n" +
787+
"CALL spatial.removeNode('" + layer + "',n) YIELD node\n" +
788+
"RETURN count(node)";
789+
testCountQuery("removeNode", remove, count / 2, "count(node)", map("count", count / 2));
790+
// Check that only half remain
791+
testCountQuery("withinDistance", "CALL spatial.withinDistance('" + layer + "',{lon:15.0,lat:60.0},1000) YIELD node RETURN count(node)", count / 2, "count(node)", null);
792+
}
793+
794+
private void testRemoveNodes(String layer, int count) {
795+
// Check all nodes are there
796+
testCountQuery("withinDistance", "CALL spatial.withinDistance('" + layer + "',{lon:15.0,lat:60.0},1000) YIELD node RETURN count(node)", count, "count(node)", null);
797+
// Now remove half the points
798+
String remove = "UNWIND range(1,{count}) as i\n" +
799+
"MATCH (n:Point {id:i})\n" +
800+
"WITH collect(n) as points\n" +
801+
"CALL spatial.removeNodes('" + layer + "',points) YIELD count\n" +
802+
"RETURN count";
803+
testCountQuery("removeNodes", remove, count / 2, "count", map("count", count / 2));
804+
// Check that only half remain
805+
testCountQuery("withinDistance", "CALL spatial.withinDistance('" + layer + "',{lon:15.0,lat:60.0},1000) YIELD node RETURN count(node)", count / 2, "count(node)", null);
765806
}
766807

767808
@Test

0 commit comments

Comments
 (0)