我正在Windows上使用neo4j Community Edition,版本3.4.0。
我有一个简单的用例,我希望收集许多路径结果,将它们组合成一个列表,然后处理该列表的内容。 我希望过滤特定节点属性的公共列表,并根据过滤器的类别处理那些节点。 然后,我希望将更多过滤器应用于公用列表,并以类似方式处理结果节点。 某些节点可能会被多个过滤器选中,因此重要的是,一个过滤器不要从公共列表中删除任何节点。
我遇到的问题是,在第一个过滤器之后,公共列表的内容将减少为仅包含与该过滤器匹配的节点的那些路径。 看来过滤器正在影响它正在解析的列表的内容,而不仅仅是返回符合过滤条件的新节点列表。
以下查询是人为设计的,但它们说明了我面临的问题:
创建测试数据:
CREATE (b:B)-[:FollowedBy]->(c:C)-[:FollowedBy]->(d:D)
RETURN b, c, d;
查询:
// Establish two related paths
MATCH p1 = (:B)-[:FollowedBy]->(c)
MATCH p2 = (c)-[:FollowedBy]->()
// Join the two paths to create a single list
WITH collect(p1) + collect(p2) AS pList
// Unwind the common list so that it can be filtered for specific categories
UNWIND pList AS path
// Filter for nodes in the 'D' category
WITH filter(n1 IN nodes(path) WHERE 'D' IN labels(n1)) AS dNodes, pList, path
// Unwind the filtered set of 'D' nodes so that they can be processed
UNWIND dNodes AS dNode
// ... do some dNode stuff
// Filter for nodes in the 'B' category
WITH filter(n2 IN nodes(path) WHERE 'B' IN labels(n2)) AS bNodes, pList, path
// Unwind the filtered set of 'B' nodes so that they can be processed
UNWIND bNodes AS bNode
// ... do some bNode stuff
RETURN path, pList;
如果我运行此查询,将返回0行。
实际发生的是:
1)收集并连接了两个路径后,公用列表“ pList”看起来像预期的那样。它返回具有两个路径元素的单个集合。
+------------------------------------------------------+
| pList |
+------------------------------------------------------+
| [(:B)-[:FollowedBy]->(:C), (:C)-[:FollowedBy]->(:D)] |
+------------------------------------------------------+
2)将pList展开到路径后,pList现在包含两个相同的记录,每个路径值对应一个记录-请有人解释为什么是这种情况,即为什么“将pList展开到路径”会影响pList本身?:
+---------------------------------------------------------------------------------+
| pList | path |
+---------------------------------------------------------------------------------+
| [(:B)-[:FollowedBy]->(:C), (:C)-[:FollowedBy]->(:D)] | (:B)-[:FollowedBy]->(:C) |
| [(:B)-[:FollowedBy]->(:C), (:C)-[:FollowedBy]->(:D)] | (:C)-[:FollowedBy]->(:D) |
+---------------------------------------------------------------------------------+
3)在过滤了“ D”类中的节点并展开结果列表“ dNodes”之后,pList的内容是单个记录,并且路径现在仅包含与过滤后的节点相对应的路径?
+---------------------------------------------------------------------------------+
| pList | path |
+---------------------------------------------------------------------------------+
| [(:B)-[:FollowedBy]->(:C), (:C)-[:FollowedBy]->(:D)] | (:C)-[:FollowedBy]->(:D) |
+---------------------------------------------------------------------------------+
4)在过滤了“ B”类中的节点并展开结果列表“ bNodes”之后,返回pList或path导致零行。这意味着不可能处理“ B”节点?
我想我对Cypher如何处理变量和过滤器有一个基本的误解,如果有人能解释我上面描述的行为,我将不胜感激。
另外,考虑到我的要求,我应该怎么做?我可以执行多个查询,但是看来我的要求很简单,因此我应该能够一次完成整个过程。
谢谢。
答案 0 :(得分:1)
在步骤2中,pList
尚未更改(进入2条相同的记录)。
在那一步,您只有pList
和path
作为变量。 Neo4j会将每种可能的变量值组合表示为单独的数据行,并处理每一行。由于只有一个pList
值和2个path
值,因此将导致两行数据,这正是您在#2的表中显示的。
此外,您没有显示完整的Cypher代码,因此未知为什么整个查询什么都不返回。可能有一个未显示的MATCH
子句不匹配,这将中止查询的其余部分。
答案 1 :(得分:1)
cybersam回答了您的#2问题。
对于#3和#4,重要的是要了解UNWIND将为列表的每个元素提供一行,并且在处理空列表时,它将擦除该行(没有元素,因此没有行)。这是您取消过滤器的结果时发生的事情,因为一个路径没有:D节点(因此该行被删除了),而其余路径没有:B节点(并且被删除了)。 / p>
我们有一个entry describing this in the documentation,以及一个变通方法,以防您希望在列表为空的情况下使行保持null
结果。
对于您而言,最好使用FOREACH
处理过滤的节点列表(前提是您仅使用SET,CREATE,MERGE,REMOVE或DELETE):
MATCH p1 = (:B)-[:FollowedBy]->(c)
MATCH p2 = (c)-[:FollowedBy]->()
WITH collect(p1) + collect(p2) AS pList
UNWIND pList AS path
FOREACH(dNode in [n in nodes(path) WHERE n:D] |
// ... do some dNode stuff
)
FOREACH(bNode in [n in nodes(path) WHERE n:B] |
// ... do some bNode stuff
)
RETURN path, pList;
否则,如果要处理dNode和bNode的事情比较复杂,可以在链接文档中使用技巧,在过滤列表为空时使用UNWIND [null]
来CASE
。