过滤路径列表会影响列表变量的内容
Filtering on a list of paths affects the contents of the list variable
我在 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" 看起来符合预期。它 returns 具有两个路径元素的单个集合。
+------------------------------------------------------+
| pList |
+------------------------------------------------------+
| [(:B)-[:FollowedBy]->(:C), (:C)-[:FollowedBy]->(:D)] |
+------------------------------------------------------+
2) 将 pList 展开到路径后,pList 现在包含两个相同的记录,每个记录对应一个路径值 - 请有人解释为什么会这样,即为什么 "unwind of pList into path" 影响了 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 或路径导致零行。这意味着无法处理 'B' 节点?
我想我对 Cypher 如何处理变量和过滤器有一个根本性的误解,如果有人能解释我上面描述的行为,我将不胜感激。
另外,考虑到我的要求,我应该怎么做?我可以执行多个查询,但看起来我的要求很简单,我应该能够一次完成整个过程。
提前致谢。
在第 2 步中,pList
没有改变(变成 2 个相同的记录)。
在那一步,您只有 pList
和 path
作为变量。 Neo4j 会将每个可能的变量值组合表示为单独的数据行,并处理每一行。由于有一个 pList
值和 2 个 path
值,因此会产生 2 行数据,这正是您在 #2.table 中显示的内容。
此外,您没有显示完整的 Cypher 代码,因此不知道为什么整个查询没有返回任何结果。可能有一个未显示的 MATCH
子句不匹配,这将中止查询的其余部分。
cybersam 回答了您关于 #2 的问题。
至于#3 和#4,重要的是要了解 UNWIND 将为列表的每个元素提供一行,当在空列表上完成时,它将清除该行(没有元素,所以没有行) .这就是当您展开过滤器的结果时发生的事情,因为一条路径没有 :D 节点(因此该行被删除),而其余路径没有 :B 节点(并被删除)。
我们有一个 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 处理做更复杂的事情,您可以使用链接文档中的技巧在过滤列表为空时使用 CASE
UNWIND [null]
。
我在 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" 看起来符合预期。它 returns 具有两个路径元素的单个集合。
+------------------------------------------------------+
| pList |
+------------------------------------------------------+
| [(:B)-[:FollowedBy]->(:C), (:C)-[:FollowedBy]->(:D)] |
+------------------------------------------------------+
2) 将 pList 展开到路径后,pList 现在包含两个相同的记录,每个记录对应一个路径值 - 请有人解释为什么会这样,即为什么 "unwind of pList into path" 影响了 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 或路径导致零行。这意味着无法处理 'B' 节点?
我想我对 Cypher 如何处理变量和过滤器有一个根本性的误解,如果有人能解释我上面描述的行为,我将不胜感激。
另外,考虑到我的要求,我应该怎么做?我可以执行多个查询,但看起来我的要求很简单,我应该能够一次完成整个过程。
提前致谢。
在第 2 步中,pList
没有改变(变成 2 个相同的记录)。
在那一步,您只有 pList
和 path
作为变量。 Neo4j 会将每个可能的变量值组合表示为单独的数据行,并处理每一行。由于有一个 pList
值和 2 个 path
值,因此会产生 2 行数据,这正是您在 #2.table 中显示的内容。
此外,您没有显示完整的 Cypher 代码,因此不知道为什么整个查询没有返回任何结果。可能有一个未显示的 MATCH
子句不匹配,这将中止查询的其余部分。
cybersam 回答了您关于 #2 的问题。
至于#3 和#4,重要的是要了解 UNWIND 将为列表的每个元素提供一行,当在空列表上完成时,它将清除该行(没有元素,所以没有行) .这就是当您展开过滤器的结果时发生的事情,因为一条路径没有 :D 节点(因此该行被删除),而其余路径没有 :B 节点(并被删除)。
我们有一个 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 处理做更复杂的事情,您可以使用链接文档中的技巧在过滤列表为空时使用 CASE
UNWIND [null]
。