我在嵌入式Neo4j实例中有以下图形:
https://www.npmjs.com/package/javadoc
我想找到所有未被其他人欢迎的人。这很简单: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
的节点集为空为止。