Neo4j图形回溯算法

3
我是一名有用的助手,可以为您翻译文本。

我有一个关于Neo4j和Traversal能做什么的复杂问题。

想象一下您拥有以下的Neo4j图形

Graph

我的想法是遍历整个图形,如果我找到一个“false”节点,则将此状态扩展到其邻居等,最终在此示例中,我们将具有所有带有“false”状态的节点。(在现实生活中,我在遍历时有更多条件来设置此状态为true或false,但我为了问题而简化了它
我认为我需要一些回溯算法来做到这一点,但在Neo4j中我不知道如何做到这一点,或者是否可能。此外,此图可以是非常庞大的图。
您会如何使用Java和Neo4j完成此操作?
谢谢。

1
是否只需匹配任何具有“false”所需属性的节点,然后将从该节点可达的所有连接节点也更改为false? - InverseFalcon
2个回答

2

为了高效地匹配可达节点,有两个选项通常表现得很好。

在Neo4j 3.2.x中,通过变量关系匹配加上DISTINCT的使用,有一种有效的方法可以匹配到所有不同的可达节点,但需要对变长关系设置一个上限。使用适当高的数字应该就可以了。例如:

MATCH (:SomeLabel{someProperty:false})-[*..999999]->(x)
WITH distinct x
SET x.someProperty = false

否则,APOC Procedures 提供了 apoc.path.subgraphNodes(),它还可以有效地匹配子图中可达节点。
MATCH (start:SomeLabel{someProperty:false})
CALL apoc.path.subgraphNodes(start, {}) YIELD node
SET node.someProperty = false;

编辑

为了对第一个选项(为什么不使用*,而是使用DISTINCT)添加更多细节,请记住,当我们使用*时,默认情况下,Cypher将匹配到所有可能的路径,即使这些路径以前已经在同一节点处结束。如果图形连接得足够复杂(当我们没有合理的上限并且我们没有使用LIMIT时),这可能会变得效率低下,有可能导致堆溢出或无限期挂起。

当我们不仅仅关心所有可能的路径,而只关心所有可达节点时,应该避免这种情况。

在Neo4j 3.2中引入了一种优化,称为修剪-var expand,在以下所有情况均为真时更改遍历逻辑:

  1. 我们有一个var-length扩展
  2. 我们没有以任何方式引用该路径(例如通过将路径变量设置为匹配模式或在var-length关系上设置变量)
  3. 我们对var-length扩展设置了上限
  4. 我们要求DISTINCT节点或从扩展获得的值

基本上,当查询明确表明我们希望从var-length扩展获得不同节点(或来自不同节点的值)并且不关心路径时,会使用修剪var expand(您可以通过从EXPLAIN或PROFILE中检查查询计划来确认)高效地匹配可达节点。

计划者将使用修剪var expand,以便有效匹配到可达节点。


只有使用 * 才能起作用(Bruno Peres的回答和此答案)。 为什么要使用DISTINCT? - jpadilladev
增加了一些有关在较大的图形上使用 * 以及修剪变量扩展优化的限制的详细信息。 - InverseFalcon
太棒了的解释! - Bruno Peres
如果在遍历过程中方向不重要,那么可以简单地省略箭头。这将遍历所有的入站和出站关系。 - InverseFalcon
@jpadilladev 我也可以复制挂起的情况。我会向工程部门提出问题。在这种情况下,请尝试使用 APOC 解决方案。首先只返回不同节点的计数,以查看其性能如何,以及您将要写入多少个节点。 - InverseFalcon
显示剩余2条评论

0

我不确定我完全理解了你的问题,但我相信一个简单的Cypher查询就足够了。类似这样:

MATCH ({someProperty : false})-[*]-(neighbours)
SET neighbours.someProperty = false

这将在任何深度上扩展false属性,所以我认为它会起作用。我需要在扩展时添加一些条件,但我会尝试一下。在我的问题中,我要求使用Java来完成这个任务(如果我没有解释清楚,对不起,但我想使用TraversalDescription、Expanders等来完成这个任务)。为什么使用Cypher?这更容易吗?谢谢。 - jpadilladev
@jpadilladev 当使用Neo4j时,Cypher是“自然”的选择,因为它是处理此数据库的查询语言。是的,与Java API相比,Cypher更容易使用。但是,Java API提供了更多的灵活性和较少的抽象。如果我完全理解您的要求,您正在尝试在遍历过程中动态添加条件...在这种情况下,我认为您需要使用Java API。 - Bruno Peres

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接