Neo4j:如何在UNION cypher上实现SKIP和LIMIT?有哪些替代方案?

时间:2015-10-11 23:04:04

标签: neo4j cypher

我正在尝试跨各种关系创建活动Feed。

到目前为止,我设法做到的唯一方法是使用UNION来运行3个语句。但是,在所有工会的结果中,您不能LIMITORDER - 这似乎是Neo目前的限制。

有谁知道我怎么能写下面所以我可以订购并限制整个地段?

match (me:User {username:'bob'})-[:Owner]->(m:Message)<-[r:Likes|:Reply|:Share]-(u:User)
return m as message, u as user, lower(type(r)) as activity, r.created_on as date  
order by date skip 0 limit 25

union match (me:User {username:'bob'})<-[r:Mentions]-(m:Message)-[:Owner]-(u:User) 
return m as message, u as user, lower(type(r)) as activity, r.created_on as date
order by date skip 0 limit 25

union match (me:User {username:'bob'})<-[r:Follows]-(u:User)
return NULL as message, u as user, lower(type(r)) as activity, r.created_on as date
order by date skip 0 limit 25

我得到了这个,它返回一个包含我需要的数据作为嵌套属性的列,但是我无法确定如何订购最终的集合......

match (me:User {username:'bob'})-[:Owner]->(m:Message)<-[r:Likes|:Reply|:Share]-(u:User)
with collect({activity:lower(type(r)), user:u, message:m, date:r.created_on}) as a1

optional match (me:User {username:'bob'})<-[r:Mentions]-(m:Message)-[:Owner]-(u:User) 
with collect({activity:lower(type(r)), user:u, message:m, date:r.created_on }) as a2, a1 

optional match (me:User {username:'bob'})<-[r:Follows]-(u:User) 
with collect({activity:lower(type(r)), user:u, date:r.created_on }) as  a3, a2, a1

with a3 + a2 +a1 as all
unwind all as activity
return activity
skip 0 limit 25

任何帮助非常感谢!

更新

所以现在我有了这个......

MATCH (me:User { username:'bob' })--(u:User)
OPTIONAL MATCH (me)-[:Owner]->(m:Message)<-[r:Likes|:Reply|:Share]-(u)
WITH me, collect({ type:lower(type(r)), user:u, message:m, date:r.created_on }) AS a1
OPTIONAL MATCH (me)<-[r:Mentions]-(m:Message)<-[:Owner]-(u)
WITH me, collect({ type:lower(type(r)), user:u, message:m, date:r.created_on }) AS a2, a1
OPTIONAL MATCH (me)<-[r:Follows]-(u)
WITH collect({ type:lower(type(r)), user:u, date:r.created_on })+ a2 + a1 AS all
UNWIND all AS activity
WITH activity
WHERE  activity.type is not null
RETURN activity
ORDER BY activity.date
LIMIT 25;

任何人都可以看到这方面的任何性能问题吗?

我匹配我 - 用户在开始时确保我只查找与我有一些关系的用户。然后在最后我从OPTIONAL比赛中筛选出NUll比赛。当我手动收集一个文字对象时,如果没有匹配的话,它会获得一个带有NULL条目的对象,所以我只是在最后删除它们....

这一切都是因为你无法过滤POST UNION!

3 个答案:

答案 0 :(得分:1)

尚不支持“后UNION处理”的能力,但是“尽快”承诺(见neo4j issue 2725)。如果您希望尽快发生这种情况,可能需要为该问题添加注释。

您尝试的解决方案已接近尾声。此查询应该更好:

MATCH (me:User { username:'bob' })-[:Owner]->(m:Message)<-[r:Likes|:Reply|:Share]-(u:User)
WITH me, collect({ type:lower(type(r)), user:u, message:m, date:r.created_on }) AS a1
OPTIONAL MATCH (me)<-[r:Mentions]-(m:Message)<-[:Owner]-(u:User)
WITH me, collect({ type:lower(type(r)), user:u, message:m, date:r.created_on }) AS a2, a1
OPTIONAL MATCH (me)<-[r:Follows]-(u:User)
WITH collect({ type:lower(type(r)), user:u, date:r.created_on })+ a2 + a1 AS all
UNWIND all AS activity
RETURN activity
ORDER BY activity.date
LIMIT 25;

此查询:

  • ORDERS BY合并活动的日期,以便返回最早的25个活动。这是您的查询所需的主要更改。
  • 消除不需要的SKIP 0条款。
  • 通过前{2}个me条款WITH,以便OPTIONAL MATCH条款不必再次重新找到me

答案 1 :(得分:0)

你可以这样做:

MATCH (me:User {username:'bob'}), (user:User)
OPTIONAL MATCH (me)-[:Owner]->(m1:Message)<-[message_type:Likes|:Reply|:Share]-(user)
OPTIONAL MATCH (me)<-[mentions:Mentions]-(m2:Message)-[:Owner]-(user) 
OPTIONAL MATCH (me)<-[follows:Follows]-(user)
WITH *
WHERE message_type IS NOT NULL OR mentions IS NOT NULL OR follows IS NOT NULL
RETURN
  COALESCE(m1, m2) AS message,
  user,
  lower(COALESCE(type(message_type), type(mentions), type(follows))),
  COALESCE(message_type.date, mentions.date, follows.date) AS date
ORDER BY date
SKIP 0
LIMIT 25

这里的主要缺点(除了所有COALESCE之外;)是因为从OPTIONAL MATCHme只有user路径,你最终会匹配{{ 1}}针对每个用户,这意味着当您获得更多用户时,您的查询可能会变得更慢。这就是为什么我在me之后将WHERE放在那里的原因,因为您需要过滤掉两个用户之间没有路径的所有情况。

修改

我刚才意识到这是一个有问题的解决方案。如果您的两个或多个WITH条款匹配,那么您只会获得一个结果。你可以这样做:

OPTIONAL MATCH

但是我认为你可能会根据你的匹配方式重复值。

答案 2 :(得分:0)

我想用另一个建议来窃取你的/ cybersam的解决方案。我要去网络工作了。首先,我认为您不希望只返回始终存在user-[:Owner]->(:Message)-:Likes|:Reply|:Share]-(:User)路径的结果,因此需要选择匹配。但其次,我认为如果你只匹配最终用户变量一次会更快。像这样:

MATCH (me:User { username:'bob' }), (user:User)
OPTIONAL MATCH (me)-[:Owner]->(m:Message)<-[r:Likes|:Reply|:Share]-(user)
WITH me, collect({ type:lower(type(r)), user:user, message:m, date:r.created_on }) AS a1
OPTIONAL MATCH (me)<-[r:Mentions]-(m:Message)<-[:Owner]-(user)
WITH me, collect({ type:lower(type(r)), user:user, message:m, date:r.created_on }) AS a2, a1
OPTIONAL MATCH (me)<-[r:Follows]-(user)
WITH collect({ type:lower(type(r)), user:user, date:r.created_on }) + a2 + a1 AS all
UNWIND all AS activity
RETURN activity
ORDER BY activity.date
LIMIT 25;