2016-03-04 66 views
2

我想要一个查询来查找边上属性的最小值和最大值以及连接到给定节点的边的值。Cypher:聚合和单个选择

考虑这个样本数据库:

Simple graph database

我们有一个Game节点(红色)和三个Person节点(图中蓝色)。 GamePerson节点都具有name属性,因为此示例假设名称是唯一的。 PersonGame节点通过BEST_SCORE边缘连接,其边缘具有score属性,每个人只能有一条边将它们连接到游戏。

到目前为止,我想出了这一点:

MATCH (g:Game)<-[s:BEST_SCORE]-(p:Person) 
WHERE g.name='Pacman' 
WITH MAX(s.score) AS max, MIN(s.score) AS min 
MATCH (g:Game)<-[s:BEST_SCORE]-(p:Person) WHERE g.name='Pacman' AND p.name='Tom' 
RETURN min, max, s.score 

给这些结果:

Cypher results

这也正是我想要的结果,但我不禁觉得必须有一个更好的方式来做到这一点?我觉得必须有比将Game节点及其与Person节点的连接两次匹配的更好的方法,一次用于聚合,一次用于单个分数?也许这是最好的方法?

回答

2

如果你正在寻找的效率,而不是计算minmax要返回一个球员得分每一次,你可以在聚集定期重新计算,并存储在游戏节点上。一段时间后,最小和最大值将会经常停止变化。

MATCH (g:Game {name:'Pacman'})<-[s:BEST_SCORE]-(p:Person) 
WITH MAX(s.score) as max_score, MIN(s.score) as min_score, g 
SET g.max_score = max_score, g.min_score = min_score 

然后,你可以抓住他们,当你正在寻找一名球员的得分。

MATCH (g:Game)<-[s:BEST_SCORE]-(p:Person) 
WHERE g.name='Pacman' 
AND p.name='Tom' 
RETURN g.min_score, g.max_score, s.score 
+0

好主意。我实际上最终使用了这种变化。我不喜欢存储什么是有效重复的数据,并不得不维护它,但在我的情况下,这个查询是作为脚本的一部分执行的。我找到了最小和最大一次,并将它们的值存储在脚本中,查看每个人的分数,并在需要时重新计算分钟和最大值。我意识到这不会普遍解决问题,但它对我有用。我仍然很想看看它是否可以在一个简洁的查询中完成。 – Phil

0

首先,对于详细问题的荣誉,+1!

可以通过管道将收集与最小值,最大值沿的关系,然后展开这集:

MATCH (a:Game { name:'Pacman' })<-[r:BEST_SCORE]-(person) 
WITH collect(r) AS rels, max(r.score) AS max, min(r.score) AS min 
UNWIND rels AS r 
RETURN r.score AS score, min, max 


score min max 
12.5 5 23.2 
23.2 5 23.2 
5  5 23.2 
+0

谢谢。这种解决方法有一半是可以修改的,它只能给我一行给予一个给定的人(但最大和最小仍然是整个集合)?添加'WHERE person.name ='Tom''会从最小和最大值中排除其他值。 – Phil