知识库

执行匹配交集

匹配交集是一个常见的用例,您需要查找与一组所有输入节点都有关系的节点。

本文的其余部分将使用内置的电影图谱进行演示。示例用例如下:

给定演员姓名列表,找出包含所有给定演员的电影。

一个常见的首次尝试(且错误)的方法是这样的:

WITH ['Keanu Reeves', 'Hugo Weaving', 'Emil Eifrem'] as names
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name in names
RETURN m

上述查询返回的是包含至少一位给定演员的电影,而不是包含所有给定演员的电影。

我们需要其他方法来获取正确的结果。

通过匹配中输入节点的数量来过滤公共节点

我们可以对上述查询进行一些更改,以获取相关的 :Movie 节点集。

这里的想法是,在我们的匹配中,我们想要的 :Movie 节点将具有与输入集合大小相同数量的唯一匹配演员。

WITH ['Keanu Reeves', 'Hugo Weaving', 'Emil Eifrem'] as names
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name in names
WITH m, size(names) as inputCnt, count(DISTINCT p) as cnt
WHERE cnt = inputCnt
RETURN m

通过根据匹配到的唯一节点进行过滤,即使匹配中的节点之间存在多个相同类型的关系,我们也能够得到正确的结果。

这通常是查找匹配交集最有效的方法,但它要求输入列表中的所有输入都是唯一的。

使用 WHERE ALL() 确保列表中所有节点都与其他节点存在关系

另一种(但通常效率较低的)方法是收集输入节点,并使用 WHERE ALL() 谓词来确保所有收集到的节点都与公共节点存在关系。

WITH ['Keanu Reeves', 'Hugo Weaving', 'Emil Eifrem'] as names
MATCH (p:Person)
WHERE p.name in names
WITH collect(p) as persons
MATCH (m:Movie)
WHERE ALL(p in persons WHERE (p)-[:ACTED_IN]->(m))
RETURN m

这种方法的问题在于,它会导致与 :Movie 节点数量成比例的性能损失,因为最后的 MATCH 是从所有 :Movie 节点开始的。

我们可以通过从我们一个输入节点匹配到的 :Movie 节点开始,来稍微改进这个查询,尽管这会增加查询的复杂性。

WITH ['Keanu Reeves', 'Hugo Weaving', 'Emil Eifrem'] as names
MATCH (p:Person)
WHERE p.name in names
WITH collect(p) as persons
WITH head(persons) as head, tail(persons) as persons
MATCH (head)-[:ACTED_IN]->(m:Movie)
WHERE ALL(p in persons WHERE (p)-[:ACTED_IN]->(m))
RETURN m

使用 APOC 交集结果列表

某些用例可能会引入额外的复杂性。例如,我们可能希望结果节点与另一个匹配模式的结果相交,或与不同的结果集合相交。在这些情况下,我们可以简单地使用 WHERE 子句来强制执行附加模式或列表成员关系。

但是当有多个列表需要交集时,仅凭 Cypher 执行起来可能会变得更困难。

使用 Neo4j 3.0.x 或更高版本时,结合 reduce() 函数和来自 APOC Procedures 的交集函数,我们可以对多个列表执行交集操作。

WITH ['Keanu Reeves', 'Hugo Weaving', 'Emil Eifrem'] as names
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name in names
WITH p, collect(m) as moviesPerActor
WITH collect(moviesPerActor) as movies
WITH reduce(commonMovies = head(movies), movie in tail(movies) |
 apoc.coll.intersection(commonMovies, movie)) as commonMovies
RETURN commonMovies
© . All rights reserved.