0
votes

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:

enter image description here

And sometimes it may become a bit more complicated:

enter image description here

On the images:

  1. The spatial root (a node with "ReferenceNode" label) marked as "1"
  2. 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);
}
1
Can you share the code you are using to add the node to the index? As well as the values for INDEX_NAME and CONFIG?William Lyon
@WilliamLyon You already are looking at this code: I'm adding the node to the index in the following line: index.add(node, null, null); INDEX_NAME is simply a string "locations"; and CONFIG is simply SpatialIndexProvider.SIMPLE_POINT_CONFIG.Victor Dombrovsky
@WilliamLyon I added information into the question. Please, take a look at it. I believe, it may help to understand my situation better. Thanks in advance.Victor Dombrovsky
Now solution (workaround) is found. It is described under my question.Victor Dombrovsky

1 Answers

1
votes

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.

This is inconsistent with other interfaces for the spatial library and has caused some confusion. See this SO post for a bit more information.

You could add an id property to the node you are indexing to be able to find the proxy node when you want to remove it from the index, or use the spatial Java API to add/remove nodes from the spatial layer to avoid creating the proxy node.