Neo4j / Cypher:根据已排序的集合对结果进行排序

时间:2016-06-13 21:06:17

标签: neo4j cypher

这是我的查询的开始。

MATCH (person:Person)<-[:NAMES]-(name:PersonName)-[:COMES_FROM]->(source:Source)
WITH DISTINCT person, COLLECT([name, source]) AS tuples
WITH person, REDUCE(result=[], tuple in tuples | 
    ...  ) AS personName
ORDER BY personName.lastName
RETURN person

这里有一个问题:每个人都有许多名字,每个名字来自5个来源中的1个。但并非所有来源都是平等的。我希望获得来自最佳来源的名称,如果没有,那么下一个最佳,等等。 [&#34; source.best&#34;,&#34; source.very-good&#34;,&#34; source.ok&#34;,&#34; source.worst&#34;]我想要在personName集合上执行类似自定义排序的操作,将源作为谓词,并返回第一个。如果来源是数字或其他东西会更容易。

有什么建议吗?

2 个答案:

答案 0 :(得分:3)

[√]不要使用distinct和聚合

您可以使用文字地图作为排序的映射,即将字符串映射到值。 然后,当你按人聚合时,你只需抓住每个名字的第一个(头部)。

WITH {`source.best`:1, `source.very-good`:2, `source.ok`:3, `source.worst:4} as sourceSort
MATCH (person:Person)<-[:NAMES]-(name:PersonName)-[:COMES_FROM]->(source:Source)
WITH person, name ORDER BY sourceSort[source.name] 
RETURN person, HEAD(COLLECT(name.lastName)) AS name
ORDER BY name

答案 1 :(得分:0)

这非常有趣。我想出了这个想法:对每个来源进行评分并返回最佳来源,得分将是其在所有来源排名列表中的价值位置。

假设:在源节点的value属性上定义了最好的,非常好的:

WITH ["awesome","very-good","worst","best"] as ranking
MATCH (person:Person)<-[:NAMES]-(name:PersonName)-[:COMES_FROM]->(source:Source)
WITH person, name, source, 
 reduce(z = 0, x IN range(0, size(ranking)-1) | 
        z + CASE source.value WHEN ranking[x] THEN x ELSE 0 END) as score
ORDER BY person.name, score ASC
RETURN person, collect([name, source])[0] as bestTuple

注意:开头的WITH是模拟通常将其作为参数传递的技巧。

我使用这个简单的图表来测试:

CREATE (p:Person {name:"John"})<-[:NAMES]-(n:PersonName {name:"Jo"})-[:COMES_FROM]->(source:Source {v:"awesome"}),
(p)<-[:NAMES]-(n2:PersonName {name:"Jonathan"})-[:COMES_FROM]->(s:Source {v:"very-good"}),
(x:Person {name:"Xavier"})<-[:NAMES]-(n3:PersonName {name:"Xav"})-[:COMES_FROM]->(s)