Inside my TransactionEventHandler.beforeCommit()
I'm trying to remove a node from the spatial index, after it was successfully added. But the node remains in the index and I still able to find it using spatial Cypher query.
This is an excerpt from my code:
Index<Node> index = getGraphDatabaseService().index().forNodes("locations", SpatialIndexProvider.SIMPLE_POINT_CONFIG);
if (node.hasProperty("lat") && node.hasProperty("lon")) {
index.add(node, null, null); // it works perfectly
} else {
index.remove(node); // it doesn't work
}
Is this a known bug in the Neo4j Spatial? Anyway, how can I achieve my objective?
PS: I use Neo4j 2.3.2 and Neo4j Spatial 0.15-neo4j-2.3.1.
I found a solution (workaround):
William Lyon has shed some light on the situation:
When a node is added to the spatial index using the spatial IndexProvider interface it creates a proxy node and adds that node to the spatial index, keeping the original node separate from the in-graph RTree index.
I found, that the proxy node always contains an "id" property. It points to the original node. We even don't need to add it manually (as was proposed by William). Using it we can find the proxy node in order to delete it manually.
Sometimes our graph may look like this:
And sometimes it may become a bit more complicated:
On the images:
- The spatial root (a node with "ReferenceNode" label) marked as "1"
- The proxy node is selected
So, we can use the following Cypher query in order to find and delete the proxy node:
MATCH (:ReferenceNode)-[:LAYER]-()-[:RTREE_ROOT]-()-[*..]-(n {id:{id}}) MATCH (n)-[r:RTREE_REFERENCE]-() DELETE r, n
And here is a complete solution which I currently use inside my TransactionEventHandler
:
private static final String INDEX_NAME = "locations";
private static final Map<String, String> CONFIG = SpatialIndexProvider.SIMPLE_POINT_CONFIG;
private static final String LAT = CONFIG.get(LayerNodeIndex.LAT_PROPERTY_KEY);
private static final String LON = CONFIG.get(LayerNodeIndex.LON_PROPERTY_KEY);
@Override
public Void beforeCommit(TransactionData data) throws Exception {
Index<Node> index = getGraphDatabaseService().index().forNodes(INDEX_NAME, CONFIG);
Node originalNode = <...>;
if (originalNode.hasProperty(LAT) && originalNode.hasProperty(LON)) {
index.add(originalNode, null, null);
} else {
deleteProxyNode(originalNode.getId());
}
return null;
}
private void deleteIndexedProxyNode(long originalNodeId) {
String query = "" +
"MATCH (:ReferenceNode)-[:LAYER]-()-[:RTREE_ROOT]-()-[*..]-(n {id:{id}}) " +
"MATCH (n)-[r:RTREE_REFERENCE]-() " +
"DELETE r, n";
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", originalNodeId);
getGraphDatabaseService().execute(query, parameters);
}
INDEX_NAME
andCONFIG
? – William Lyonindex.add(node, null, null);
INDEX_NAME
is simply a string "locations"; andCONFIG
is simplySpatialIndexProvider.SIMPLE_POINT_CONFIG
. – Victor Dombrovsky