限制每行 MATCH 结果
由于LIMIT
适用于查询的总行数,因此它不能用于从多个节点匹配的情况,在这种情况下,限制必须在每行匹配的结果上。
以使用 Movies 数据库为例。
如果您需要一个查询来获取所有来自 The Matrix 的演员,并为每个演员获取该演员出演的 3 部电影,第一个(不正确的)尝试可能如下所示
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
MATCH (p)-[:ACTED_IN]->(m)
RETURN p, m LIMIT 3
上面的查询不会返回所需的结果。LIMIT
将改为使查询总共只返回 3 行。
以下是一些将限制应用于每行匹配结果的解决方案
在 4.1+ 中使用子查询中的 LIMIT
Neo4j 4.1 引入了相关子查询,让我们可以使用查询中存在的变量执行子查询。
由于子查询按行执行,因此我们可以在子查询中执行 MATCH 并应用 LIMIT,这为我们提供了限制每行匹配结果的最简单方法。
这需要使用WITH
作为子查询 CALL 块中的第一个子句,以便将变量导入子查询。
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
CALL {
WITH p
MATCH (p)-[:ACTED_IN]->(m)
RETURN m
LIMIT 3
}
RETURN p, m
这将正确返回矩阵中的所有演员以及他们出演的最多 3 部电影。
如果我们希望每个演员只出现一次,并附带每个演员最多 3 部电影的集合,我们可以在子查询中对限制后的电影进行收集
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
CALL {
WITH p
MATCH (p)-[:ACTED_IN]->(m)
WITH m
LIMIT 3
RETURN collect(m) as movies
}
RETURN p, movies
请注意,此WITH
导入有一些特殊的限制,这些限制通常不适用于WITH
用法
-
您只能包含来自外部查询的变量,不能包含其他变量。
-
您不能在初始
WITH
中执行计算、聚合或引入新变量。 -
您不能在初始
WITH
中为任何变量添加别名。 -
您不能在初始
WITH
之后使用WHERE
子句进行筛选。
如果您尝试执行任何这些操作,您将遇到某种错误,例如
Importing WITH should consist only of simple references to outside variables. Aliasing or expressions are not supported.
或者更隐晦地,如果您尝试在初始WITH
之后使用WHERE
子句
Variable `x` not defined
(其中变量是WITH
子句中出现的第一个变量)
您可以通过在导入的WITH
之后简单地引入另一个WITH
子句来绕过所有这些限制,如下所示
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
CALL {
WITH p
WITH p as actor
MATCH (actor)-[:ACTED_IN]->(m)
RETURN m
LIMIT 3
}
RETURN p, m
这展示了我们如何为导入的变量添加别名(或者如果需要,还可以进行筛选),但不能在初始导入WITH
本身进行。
对于早期版本,不支持原生相关子查询,因此必须使用其他变通方法。
获取集合的感兴趣部分
一种常见的解决方案是collect()
并获取感兴趣的部分
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
MATCH (p)-[:ACTED_IN]->(m)
RETURN p, collect(m)[..3] AS movies
在 Neo4j 3.1.x 及更高版本中,您可以使用模式推导作为一种简写方法
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
RETURN p, [(p)-[:ACTED_IN]->(m) | m][..3] as movies
如果只需要集合中的一个元素,可以使用head()
函数从模式推导中获取第一个元素
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
RETURN p, head([(p)-[:ACTED_IN]->(m) | m]) as movie
虽然这在每个节点的关联关系较少时有效,但它可能会在具有大量关联关系的超级节点上变得不可行,因为它必须扩展所有:ACTED_IN
关联关系才能进行收集。
使用 apoc.cypher.run() 执行受限子查询
Neo4j 目前除了模式推导之外,没有提供原生子查询支持,即使是模式推导也不支持LIMIT
。
但是,在 Neo4j 3.0.x 及更高版本中,使用 APOC 过程,您可以使用apoc.cypher.run()
执行带有LIMIT
的子查询,它会按我们想要的方式执行,因为它按行执行。
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
CALL apoc.cypher.run('
WITH {p} AS p
MATCH (p)-[:ACTED_IN]->(m)
RETURN m LIMIT 3',
{p:p}) YIELD value
RETURN p, value.m AS movie
这种方法很有效,因为通过使用LIMIT
,我们不必承担扩展所有:ACTED_IN
关联关系的成本,我们只需要扩展每行 3 个关联关系。
使用 APOC 路径扩展器,使用结束节点或终止过滤器以及 limit 参数
使用 Neo4j 3.1.3 及更高版本,以及 APOC 过程 3.1.3.6 及更高版本,您可以使用新的路径扩展器功能将扩展限制在特定节点。
limit
参数仅适用于采用配置映射的路径扩展器过程,并且仅在使用结束节点 (>
) 或终止标签过滤器 (/
) 时可用
-
apoc.path.expandConfig()
-
apoc.path.subgraphNodes()
-
apoc.path.subgraphAll()
-
apoc.path.spanningTree()
使用这种方法,查询变为
MATCH (:Movie{title:'The Matrix'})<-[:ACTED_IN]-(p:Person)
CALL apoc.path.subgraphNodes(p, {relationshipFilter:'ACTED_IN>', labelFilter:'/Movie', limit:3}) YIELD node
RETURN p, node as movie
此页面是否有帮助?