У меня есть следующий график во встроенном экземпляре Neo4j:
Я хочу найти всех людей, которых никто не приветствует.Это достаточно просто: MATCH (n) WHERE NOT ()-[:GREETS]->(n) RETURN n
.
Однако всякий раз, когда я нахожу незнакомых людей, я хочу удалить эти узлы из БД и повторить запрос, если он соответствует одному или нескольким узлам.Другими словами, начиная с графика на картинке, я хочу:
- Запустить запрос, который возвращает «Алису»
- Удалить «Алису» из БД
- Запустить запрос, который возвращает «Боб»
- Удалить «Боб» из БД
- Запустить запрос, который не найдет совпадений
- Вернуть имена «Алиса»"и" Боб "
Более того, я хочу выполнить этот алгоритм без фактического удаления каких-либо узлов из базы данных - то есть, своего рода" логическое удаление ".
Одно решение, которое я нашел, это , а не вызов success()
для транзакции, так что удаление узла не передается в БД, как в следующем коде:
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import java.io.File;
import java.util.*;
public class App
{
static String dbPath = "~/neo4j/data/databases/graph.db";
private enum RelTypes implements RelationshipType { GREETS }
public static void main(String[] args) {
File graphDirectory = new File(dbPath);
GraphDatabaseService graph = new GraphDatabaseFactory().newEmbeddedDatabase(graphDirectory);
Set<String> notGreeted = new HashSet<>();
try (Transaction tx = graph.beginTx()) {
while (true) {
Node notGreetedNode = getFirstNode(graph, "MATCH (n) WHERE NOT ()-[:GREETS]->(n) RETURN n");
if (notGreetedNode == null) {
break;
}
notGreeted.add((String) notGreetedNode.getProperty("name"));
detachDeleteNode(graph, notGreetedNode);
}
// Here I do NOT call tx.success()
}
System.out.println("Non greeted people: " + String.join(", ", notGreeted));
graph.shutdown();
}
private static Node getFirstNode(GraphDatabaseService graph, String cypherQuery) {
try (Result r = graph.execute(cypherQuery)) {
if (!r.hasNext()) {
return null;
}
Collection<Object> nodes = r.next().values();
if (nodes.size() == 0) {
return null;
}
return (Node) nodes.iterator().next();
}
}
private static boolean detachDeleteNode(GraphDatabaseService graph, Node node) {
final String query = String.format("MATCH (n) WHERE ID(n) = %s DETACH DELETE n", node.getId());
try (Result r = graph.execute(query)) {
return true;
}
}
}
Этот код работает правильно и печатает «Неназванные люди: Боб, Алиса».
Мой вопрос : имеет ли этот подход (т. Е. Сохранение серии операций БД в открытой транзакции)какие-либо недостатки, которые я должен знать (например, потенциальные проблемы с памятью)?Есть ли другие подходы, которые я мог бы использовать для достижения этой цели?
Я также рассмотрел использование логического свойства на узлах, чтобы пометить их как удаленные или не удаленные.Меня беспокоит то, что само приложение, над которым я работаю, содержит тысячи узлов и различные виды отношений, а фактические запросы нетривиальны, поэтому я бы предпочел не изменять их, чтобы приспособить логическое свойство мягкого удаления (но яЯ готов сделать это, если это окажется наилучшим подходом).
Также обратите внимание, что я не просто ищу узлы, которые не находятся в цикле.Скорее, основная идея заключается в следующем.У меня есть несколько узлов, которые удовлетворяют определенному условию c
;Я хочу (логически) удалить эти узлы;это потенциально заставит новые узлы удовлетворять тому же условию c
и т. д., пока набор узлов, удовлетворяющих c
, не станет пустым.