Невозможно удалить узел из пространственного индекса Neo4j
Внутри моего 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? Во всяком случае, как я могу достичь своей цели?
PS: я использую Neo4j 2.3.2 и Neo4j Spatial 0.15-neo4j-2.3.1.
Я нашел решение (обходной путь):
Уильям Лион пролил некоторый свет на ситуацию:
Когда узел добавляется к пространственному индексу с использованием пространственного интерфейса IndexProvider, он создает прокси-узел и добавляет этот узел к пространственному индексу, оставляя исходный узел отделенным от индекса RTree в графе.
Я обнаружил, что прокси-узел всегда содержит свойство "id". Это указывает на оригинальный узел. Нам даже не нужно добавлять его вручную (как было предложено Уильямом). Используя его, мы можем найти прокси-узел, чтобы удалить его вручную.
Иногда наш график может выглядеть так:
И иногда это может стать немного сложнее:
На изображениях:
- Пространственный корень (узел с меткой "ReferenceNode"), помеченный как "1"
- Прокси-узел выбран
Итак, мы можем использовать следующий 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);
}
1 ответ
Когда узел добавляется к пространственному индексу с использованием пространственного интерфейса IndexProvider, он создает прокси- узел и добавляет этот узел к пространственному индексу, оставляя исходный узел отделенным от индекса RTree в графе.
Это не согласуется с другими интерфейсами для пространственной библиотеки и вызвало некоторую путаницу. Смотрите этот пост так, чтобы получить больше информации.
Вы можете добавить свойство id к индексируемому узлу, чтобы иметь возможность найти прокси-узел, когда вы хотите удалить его из индекса, или использовать пространственный API Java для добавления / удаления узлов из пространственного слоя, чтобы избежать создания прокси узел.