|
25 | 25 | import java.util.HashMap; |
26 | 26 | import java.util.HashSet; |
27 | 27 | import java.util.Iterator; |
| 28 | +import java.util.LinkedHashSet; |
28 | 29 | import java.util.List; |
29 | 30 | import java.util.Map; |
| 31 | +import java.util.Set; |
30 | 32 | import java.util.stream.Collectors; |
31 | 33 | import java.util.stream.StreamSupport; |
32 | 34 | import javax.annotation.Nonnull; |
@@ -170,15 +172,6 @@ public void configure(Map<String, Object> config) { |
170 | 172 | }); |
171 | 173 | } |
172 | 174 |
|
173 | | - @Override |
174 | | - public void add(Transaction tx, Node geomNode) { |
175 | | - // initialize the search with root |
176 | | - Node parent = getIndexRoot(tx); |
177 | | - addBelow(tx, parent, geomNode); |
178 | | - countSaved = false; |
179 | | - totalGeometryCount++; |
180 | | - } |
181 | | - |
182 | 175 | /** |
183 | 176 | * This method will add the node somewhere below the parent. |
184 | 177 | */ |
@@ -229,29 +222,34 @@ private void insertIndexNodeOnParent(Transaction tx, Node parent, Node child) { |
229 | 222 | */ |
230 | 223 | @Override |
231 | 224 | public void add(Transaction tx, List<Node> geomNodes) { |
| 225 | + Node indexRoot = getIndexRoot(tx); |
232 | 226 |
|
233 | 227 | //If the insertion is large relative to the size of the tree, simply rebuild the whole tree. |
234 | | - if (geomNodes.size() > totalGeometryCount * 0.4) { |
235 | | - List<Node> nodesToAdd = new ArrayList<>(geomNodes.size() + totalGeometryCount); |
236 | | - for (Node n : getAllIndexedNodes(tx)) { |
237 | | - nodesToAdd.add(n); |
238 | | - } |
239 | | - nodesToAdd.addAll(geomNodes); |
240 | | - detachGeometryNodes(tx, false, getIndexRoot(tx), new NullListener()); |
241 | | - deleteTreeBelow(getIndexRoot(tx)); |
242 | | - buildRtreeFromScratch(tx, getIndexRoot(tx), decodeGeometryNodeEnvelopes(nodesToAdd), 0.7); |
| 228 | + if (totalGeometryCount > 0 |
| 229 | + && geomNodes.size() > 1 |
| 230 | + && geomNodes.size() > totalGeometryCount * 0.4 |
| 231 | + ) { |
| 232 | + Set<Node> uniqueNodes |
| 233 | + = new LinkedHashSet<>(geomNodes.size() + totalGeometryCount); |
| 234 | + getAllIndexedNodes(tx).forEach(uniqueNodes::add); |
| 235 | + uniqueNodes.addAll(geomNodes); |
| 236 | + |
| 237 | + List<Node> nodesToAdd = new ArrayList<>(uniqueNodes); |
| 238 | + detachGeometryNodes(tx, false, indexRoot, new NullListener()); |
| 239 | + deleteTreeBelow(indexRoot); |
| 240 | + buildRtreeFromScratch(tx, indexRoot, decodeGeometryNodeEnvelopes(nodesToAdd), 0.7); |
243 | 241 | countSaved = false; |
244 | 242 | totalGeometryCount = nodesToAdd.size(); |
245 | 243 | monitor.addNbrRebuilt(this, tx); |
246 | 244 | } else { |
247 | 245 |
|
248 | | - List<NodeWithEnvelope> outliers = bulkInsertion(tx, getIndexRoot(tx), getHeight(getIndexRoot(tx), 0), |
| 246 | + List<NodeWithEnvelope> outliers = bulkInsertion(tx, indexRoot, getHeight(indexRoot, 0), |
249 | 247 | decodeGeometryNodeEnvelopes(geomNodes), 0.7); |
250 | | - countSaved = false; |
251 | | - totalGeometryCount = totalGeometryCount + (geomNodes.size() - outliers.size()); |
252 | 248 | for (NodeWithEnvelope n : outliers) { |
253 | | - add(tx, n.node); |
| 249 | + addBelow(tx, indexRoot, n.node); |
254 | 250 | } |
| 251 | + totalGeometryCount += geomNodes.size(); |
| 252 | + countSaved = false; |
255 | 253 | } |
256 | 254 | } |
257 | 255 |
|
@@ -499,7 +497,11 @@ protected void mergeTwoSubtrees(Transaction tx, NodeWithEnvelope parent, List<No |
499 | 497 | disconnectedChildren.forEach(t -> t.node.delete()); |
500 | 498 |
|
501 | 499 | for (NodeWithEnvelope n : right) { |
502 | | - n.node.getSingleRelationship(RTreeRelationshipTypes.RTREE_CHILD, Direction.INCOMING); |
| 500 | + Relationship previousParent = n.node.getSingleRelationship(RTreeRelationshipTypes.RTREE_CHILD, |
| 501 | + Direction.INCOMING); |
| 502 | + if (previousParent != null) { |
| 503 | + previousParent.delete(); |
| 504 | + } |
503 | 505 | parent.node.createRelationshipTo(n.node, RTreeRelationshipTypes.RTREE_CHILD); |
504 | 506 | parent.envelope.expandToInclude(n.envelope); |
505 | 507 | } |
@@ -681,7 +683,13 @@ public boolean needsToVisit(Envelope indexNodeEnvelope) { |
681 | 683 |
|
682 | 684 | @Override |
683 | 685 | public void onIndexReference(Node geomNode) { |
684 | | - geomNode.getSingleRelationship(referenceRelationshipType, Direction.INCOMING).delete(); |
| 686 | + try (var relationships = geomNode.getRelationships(Direction.INCOMING, referenceRelationshipType)) { |
| 687 | + for (Relationship rel : relationships) { |
| 688 | + if (rel.getStartNode().equals(indexRoot)) { |
| 689 | + rel.delete(); |
| 690 | + } |
| 691 | + } |
| 692 | + } |
685 | 693 | if (deleteGeomNodes) { |
686 | 694 | deleteNode(geomNode); |
687 | 695 | } |
|
0 commit comments