Cypher:前一组的前N名成员

时间:2013-12-11 21:22:52

标签: neo4j limit cypher

我有一组文件,每组都属于一个或几个小组。

人们可以推荐这些文件

我需要为每个组提供在收到建议数量方面位置为1到N的文档,这意味着当这是一个中间结果并且N = 3时

Document   Recommendations
a          7 
b          4
c          4
d          3

它将返回a,b和c

有了这个:

Document   Recommendations
a          6 
b          5
c          4
d          4

它将返回a,b,c和d

并使用此

有了这个:

Document   Recommendations
a          6 
b          4
c          4
d          4
e          3

它将返回a,b,c和d

我如何在Cypher中做这种事情?我已经做到了这一点(计划将一个链接放到控制台但它似乎不起作用)

//Groups
create (gr1:Group {name:"First group"})
create (gr2:Group {name:"Second group"})

//Persons
create (p1:Person {name:"Jan"})
create (p2:Person {name:"Marie"})
create (p3:Person {name:"Willem"})
create (p4:Person {name:"Simone"})
create (p5:Person {name:"Henk"})
create (p6:Person {name:"Ilse"})
create (p7:Person {name:"Tom"})
create (p8:Person {name:"Detlef"})

//Content
create (ci1:Contentitem { title: "Sometitle 1"})
create (ci2:Contentitem { title: "Sometitle 2"})
create (ci3:Contentitem { title: "Sometitle 3"})
create (ci4:Contentitem { title: "Sometitle 4"})
create (ci5:Contentitem { title: "Sometitle 5"})
create (ci6:Contentitem { title: "Sometitle 6"})
create (ci7:Contentitem { title: "Sometitle 7"})
create (ci8:Contentitem { title: "Sometitle 8"})
create (ci9:Contentitem { title: "Sometitle 9"})
create (ci10:Contentitem { title: "Sometitle 10"})

//Recommendations
create (ci1)-[:IsRecommendedBy]->(p4)
create (ci8)-[:IsRecommendedBy]->(p8)
create (ci1)-[:IsRecommendedBy]->(p1)
create (ci8)-[:IsRecommendedBy]->(p7)
create (ci5)-[:IsRecommendedBy]->(p6)
create (ci1)-[:IsRecommendedBy]->(p3)
create (ci8)-[:IsRecommendedBy]->(p3)
create (ci5)-[:IsRecommendedBy]->(p4)
create (ci8)-[:IsRecommendedBy]->(p5)
create (ci5)-[:IsRecommendedBy]->(p2)
create (ci5)-[:IsRecommendedBy]->(p1)
create (ci5)-[:IsRecommendedBy]->(p8)
create (ci2)-[:IsRecommendedBy]->(p1)
create (ci2)-[:IsRecommendedBy]->(p3)
create (ci2)-[:IsRecommendedBy]->(p7)
create (ci10)-[:IsRecommendedBy]->(p8)
create (ci3)-[:IsRecommendedBy]->(p4)
create (ci10)-[:IsRecommendedBy]->(p5)
create (ci3)-[:IsRecommendedBy]->(p1)
create (ci4)-[:IsRecommendedBy]->(p5)
create (ci4)-[:IsRecommendedBy]->(p8)
create (ci6)-[:IsRecommendedBy]->(p5)
create (ci9)-[:IsRecommendedBy]->(p1)
create (ci9)-[:IsRecommendedBy]->(p2)
create (ci6)-[:IsRecommendedBy]->(p6)
create (ci6)-[:IsRecommendedBy]->(p8)

//Group membership
create (ci1)-[:BelongsToGroup]->(gr1)
create (ci1)-[:BelongsToGroup]->(gr2)
create (ci2)-[:BelongsToGroup]->(gr1)
create (ci3)-[:BelongsToGroup]->(gr1)
create (ci4)-[:BelongsToGroup]->(gr1)
create (ci4)-[:BelongsToGroup]->(gr2)
create (ci5)-[:BelongsToGroup]->(gr1)
create (ci6)-[:BelongsToGroup]->(gr1)
create (ci7)-[:BelongsToGroup]->(gr1)
create (ci8)-[:BelongsToGroup]->(gr1)
create (ci8)-[:BelongsToGroup]->(gr2)
create (ci10)-[:BelongsToGroup]->(gr1)
create (ci10)-[:BelongsToGroup]->(gr2)
;

和查询

match (gr)<-[:BelongsToGroup]-(ci:Contentitem)-[:IsRecommendedBy]->(p:Person)
return gr.name,ci.title,count(p) as Recommendations 
order by gr.name, Recommendations desc

返回

gr.name          ci.title           Recommendations
----------------------------------------------------
First group      Sometitle 5        5
First group      Sometitle 8        4
First group      Sometitle 1        3
First group      Sometitle 6        3
First group      Sometitle 2        3
First group      Sometitle 4        2
First group      Sometitle 3        2
First group      Sometitle 10       2
Second group     Sometitle 8        4
Second group     Sometitle 1        3
Second group     Sometitle 10       2
Second group     Sometitle 4        2

N = 3,最终结果应为

gr.name          ci.title           Recommendations
----------------------------------------------------
First group      Sometitle 5        5
First group      Sometitle 8        4
First group      Sometitle 1        3
First group      Sometitle 6        3
First group      Sometitle 2        3
Second group     Sometitle 8        4
Second group     Sometitle 1        3
Second group     Sometitle 10       2
Second group     Sometitle 4        2

N = 2,最终结果为

gr.name          ci.title           Recommendations
----------------------------------------------------
First group      Sometitle 5        5
First group      Sometitle 8        4
Second group     Sometitle 8        4
Second group     Sometitle 1        3

在以下规则中重要的是,在位置&lt; = N处开始的建议数量最少的组不会在任意位置被切断,而是完全包含在内。所以,当我们像这样截止前的情况时

gr.name          ci.title           Recommendations
----------------------------------------------------
First group      Sometitle 5        5
First group      Sometitle 8        4
First group      Sometitle 1        4
First group      Sometitle 6        3
First group      Sometitle 2        3
First group      Sometitle 4        2
First group      Sometitle 3        2
First group      Sometitle 10       2
Second group     Sometitle 8        4
Second group     Sometitle 1        4
Second group     Sometitle 10       2
Second group     Sometitle 4        2
Second group     Sometitle 7        1

N = 3的最终结果是:

gr.name          ci.title           Recommendations
----------------------------------------------------
First group      Sometitle 5        5
First group      Sometitle 8        4
First group      Sometitle 1        4
Second group     Sometitle 8        4
Second group     Sometitle 1        4
Second group     Sometitle 10       2
Second group     Sometitle 4        2

并且对于N = 2

gr.name          ci.title           Recommendations
----------------------------------------------------
First group      Sometitle 5        5
First group      Sometitle 8        4
First group      Sometitle 1        4
Second group     Sometitle 8        4
Second group     Sometitle 1        4

2 个答案:

答案 0 :(得分:3)

我认为没有一种干净的方法可以做到你想要的,但这是我最好的尝试。在找出截止值后,它需要第二场比赛。

这样的事情:

match (gr)<-[:BelongsToGroup]-(ci:Contentitem)-[:IsRecommendedBy]->(p:Person)
with gr, ci, count(p) as recommendations
order by recommendations desc
with gr, collect(recommendations) as cutoffs
// coalesce here to avoid null problems if you don't have N=3 distinct recommendations
with gr, coalesce(cutoffs[2], cutoffs[1], cutoffs[0]) as cutoff
match (gr)<-[:BelongsToGroup]-(ci:Contentitem)-[:IsRecommendedBy]->(p:Person)
with gr, ci, count(p) as recommendations, cutoff
where recommendations >= cutoff
return gr.name, ci.title, recommendations, cutoff
order by gr.name, recommendations desc;

给出:

+------------------------------------------------------------+
| gr.name        | ci.title       | recommendations | cutoff |
+------------------------------------------------------------+
| "First group"  | "Sometitle 5"  | 5               | 3      |
| "First group"  | "Sometitle 8"  | 4               | 3      |
| "First group"  | "Sometitle 1"  | 3               | 3      |
| "First group"  | "Sometitle 6"  | 3               | 3      |
| "First group"  | "Sometitle 2"  | 3               | 3      |
| "Second group" | "Sometitle 8"  | 4               | 2      |
| "Second group" | "Sometitle 1"  | 3               | 2      |
| "Second group" | "Sometitle 4"  | 2               | 2      |
| "Second group" | "Sometitle 10" | 2               | 2      |
+------------------------------------------------------------+
9 rows

更新:我想到你可能想要传递N而不是像coarthce一样编码。在这种情况下,您可以这样做:

with gr, reduce(acc=cutoffs[0], x in range(0, {N}-1)| coalesce(cutoffs[x], acc)) as cutoff

这将通过0到N-1的范围,而不需要像第一个解决方案那样硬编码。

答案 1 :(得分:2)

你已经得到了一个很好的答案(+1),但我很好奇是否可以在没有第二场比赛的情况下完成。这是我想出来的

MATCH (gr)<-[:BelongsToGroup]-(ci:Contentitem)-[r:IsRecommendedBy]->() // I dropped (p:Person) since it's not really relevant, and counted the [:IsRecommendedBy] instead
WITH gr, [ci, count(r)] AS document
ORDER BY document[1] desc
WITH gr, collect(document) as documents, collect(document[1]) as recommendations
WITH gr, documents, recommendations, 
    CASE WHEN length(recommendations) >= {n} THEN {n}-1 ELSE length(recommendations)-1 END as ix
RETURN gr.name AS group,[doc IN documents 
    WHERE doc[1]>= recommendations[ix]| [(doc[0]).title, doc[1]]] AS documents

我不知道这是否一定更好,但它有所不同,只有一个匹配CASE WHEN而不是REDUCE/COALESCE以避免索引问题,并且每个组返回一行有序收集[文件,推荐]对;也许那里有一些可用的东西。