问题描述
如何在neo4j 中检索路径中最新节点的列表? disTINCT 运算符似乎没有做我想要的。
有一个类似这样的结构:
(n1) - [reln1 cratedAt:"1" something:"not42"] -> ( target )
(n1) - [reln2 cratedAt:"2" something:"42"] -> ( target )
(n2) - [reln3 cratedAt:"1" something:"not42"] -> ( target )
(n2) - [reln4 cratedAt:"3" something:"42"] -> ( target )
(n2) - [reln5 cratedAt:"2" something:"not42"] -> ( target )
问题在于 n1、n2 和目标之间存在未知数量的并行关系(或路径)。
尝试使查询返回具有 rel2 和 rel4 的结构,如下所示,因为 createdAt 分别是来自 n1 和 n2 的最新值。查询应返回:
(n2) - [reln4 cratedAt:"3" something:"42"] -> ( target )
(n1) - [reln2 cratedAt:"2" something:"42"] -> ( target )
在本例中,我正在寻找承载由 something:42 表示的权重的关系或节点。我错过了什么?这不能在一个查询中完成吗?如果它们是节点而不是关系会有所帮助吗?
MATCH (node)-[rel]->(target)
RETURN disTINCT node
ORDER BY rel.createdAt
LIMIT 10
要完成这项工作,我需要先按 createdAt 排序,然后选择最新的,然后每个节点返回一个。怎么样?
编辑:当在关系上创建时,似乎答案对这个结构是有效的 - 但我无法弄清楚如何使用中间节点上的 createdAt 属性将其推广到更长的路径。棘手的问题。
很难概括如下所示的结构:
(O1:Start)-[]-> (mid1:n1 cratedAt:"1" something:"not42") - [reln1 ] -> ( target )
(O1:Start)-[]-> (mid2:n1 cratedAt:"2" something:"42") - [reln2 ] -> ( target )
(O2:Start)-[]-> (mid3:n2 cratedAt:"1" something:"not42") - [reln3 ] -> ( target )
(O2:Start)-[]-> (mid4:n2 cratedAt:"3" something:"42") - [reln4 ] -> ( target )
(O2:Start)-[]-> (mid5:n2 cratedAt:"2" something:"not42") - [reln5 ] -> ( target )
查询应该返回
(O1:Start)-[]-> (mid2:n1 cratedAt:"2" something:"42") - [reln2 ] -> ( target )
(O2:Start)-[]-> (mid4:n2 cratedAt:"3" something:"42") - [reln4 ] -> ( target )
我想要的是标签 n1 和 n2 是兄弟姐妹 - 不仅仅是 rel1 rel2 rel3 等。有没有更好的方法来管理不同来源的重复项,然后查询以找到“正确”的?
解决方法
这是我的答案:
- 首先,您需要获取具有最大值的 createdAt 日期
- 然后用这个最大值匹配所有节点
- 最后返回你想要的节点
MATCH ()-[rel]->()
WITH max( rel.cratedAt ) as max_createdAt
MATCH (node)-[r]->(target) WHERE r.createdAt = max_createdAt
RETURN node LIMIT 10
Result:
╒═════════════╕
│"node" │
╞═════════════╡
│{"name":"n1"}│
├─────────────┤
│{"name":"n2"}│
└─────────────┘
编辑:根据用户评论,我更新了下面的答案。
我希望返回整个结构。
MATCH ()-[rel]->()
WITH max( rel.cratedAt ) as max_createdAt
MATCH path=(node)-[r]->(target) WHERE r.cratedAt = max_createdAt
RETURN path,type(r) as relationship_name
LIMIT 10
Result:
╒═══════════════════════════════════╤═══════════════════╕
│"path" │"relationship_name"│
╞═══════════════════════════════════╪═══════════════════╡
│[{"name":"n1"},{"cratedAt":"2"},{}]│"reln2" │
├───────────────────────────────────┼───────────────────┤
│[{"name":"n2"},{}]│"reln4" │
└───────────────────────────────────┴───────────────────┘
,
你需要做的是执行你的 MATCH,然后按 rel 的 createdAt 属性排序,然后根据节点和目标收集()关系(所以每个节点和目标,你会得到有序的关系列表),然后获取列表的 head()(它们之间最新创建的 rel)。
你真的应该使用标签,但现在我只会扩展你的密码:
MATCH (node)-[rel]->(target)
WITH node,rel,target
ORDER BY rel.createdAt
WITH node,target,collect(rel) as rels
RETURN node,head(rels) as rel
LIMIT 10
如果使用 Neo4j 4.1.x 或更高版本,那么您可以使用子查询来约束每个节点的扩展和聚合,而不必进行一次大型聚合。这将在您的堆上更容易,因此随着您的图表增长而变得更好:
MATCH (node)
CALL {
WITH node
MATCH (node)-[rel]->(target)
WITH rel,target
ORDER BY rel.createdAt
WITH target,collect(rel) as rels
RETURN target,head(rels) as rel
}
RETURN node,rel
LIMIT 10
(同样,您应该使用标签和 rel 类型,否则必须执行 AllNodesScan,随着图形的增长,性能会很差)。