无法从 Neo4j 空间索引中删除节点

Unable to remove a node from Neo4j Spatial index

在我的 TransactionEventHandler.beforeCommit() 中,我试图在成功添加节点后从空间索引中删除该节点。但该节点仍保留在索引中,我仍然能够使用空间 Cypher 查询找到它。

这是我的代码的摘录:

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
}

这是 Neo4j Spatial 中的已知错误吗?无论如何,我怎样才能实现我的 objective?

PS:我使用 Neo4j 2.3.2 和 Neo4j Spatial 0.15-neo4j-2.3.1。

我找到了解决方案(解决方法):

William Lyon 阐明了一些情况:

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.

我发现代理节点总是包含一个"id" 属性。它指向原始节点。我们甚至不需要手动添加它(正如 William 所建议的)。使用它我们可以找到代理节点以便手动删除它。

有时我们的图表可能是这样的:

有时它可能会变得有点复杂:

图片上:

  1. 标记为“1”的空间根(带有"ReferenceNode"标签的节点)
  2. 选择代理节点

因此,我们可以使用以下 Cypher 查询来查找和删除代理节点:

MATCH (:ReferenceNode)-[:LAYER]-()-[:RTREE_ROOT]-()-[*..]-(n {id:{id}}) MATCH (n)-[r:RTREE_REFERENCE]-() DELETE r, n

这是我目前在 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);
}

当使用空间 IndexProvider 接口将节点添加到空间索引时,它会创建一个 proxy 节点并将 that 节点添加到空间索引,使原始节点与图中 RTree 索引分开。

这与空间库的其他界面不一致,造成了一些混乱。有关详细信息,请参阅 this SO post

您可以将一个 id 属性 添加到您正在索引的节点,以便在您要从索引中删除它时能够找到代理节点,或者使用空间 Java API 到空间层中的 add/remove 个节点,以避免创建代理节点。