我在嵌入式 Neo4j 实例中有以下图表:
我想找到所有不被其他人打招呼的人。这很简单:MATCH (n) WHERE NOT ()-[:GREETS]->(n) RETURN n
.
但是,每当我找到不受欢迎的人时,我想从数据库中删除这些节点并重复查询,只要它匹配一个或多个节点。也就是说,从图中的图表开始,我想:
- 运行查询,返回“Alice”
- 从数据库中删除“爱丽丝”
- 运行查询,返回“Bob”
- 从数据库中删除“鲍勃”
- 运行查询,它不返回任何匹配项
- 返回名称“Alice”和“Bob”
此外,我想在不从数据库中实际删除任何节点的情况下执行该算法——即一种“逻辑删除”。
我发现的一种解决方案是不调用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
为空。