Логическое удаление узла в Neo4j встроено - PullRequest
2 голосов
/ 10 июля 2019

У меня есть следующий график во встроенном экземпляре Neo4j:

enter image description here

Я хочу найти всех людей, которых никто не приветствует.Это достаточно просто: MATCH (n) WHERE NOT ()-[:GREETS]->(n) RETURN n.

Однако всякий раз, когда я нахожу незнакомых людей, я хочу удалить эти узлы из БД и повторить запрос, если он соответствует одному или нескольким узлам.Другими словами, начиная с графика на картинке, я хочу:

  1. Запустить запрос, который возвращает «Алису»
  2. Удалить «Алису» из БД
  3. Запустить запрос, который возвращает «Боб»
  4. Удалить «Боб» из БД
  5. Запустить запрос, который не найдет совпадений
  6. Вернуть имена «Алиса»"и" Боб "

Более того, я хочу выполнить этот алгоритм без фактического удаления каких-либо узлов из базы данных - то есть, своего рода" логическое удаление ".

Одно решение, которое я нашел, это , а не вызов 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, не станет пустым.

...