我如何考虑Neo4j新闻提要中的共享帖子?
我拥有与特定我如何考虑Neo4j新闻提要中的共享帖子?,neo4j,cypher,Neo4j,Cypher,我拥有与特定用户节点的每个朋友关系相关的帖子链接列表: 用户->[:状态]->发布->[:下一个]->发布->[:下一个]->发布->[:下一个]->发布 我可以从用户朋友那里检索最近的15篇帖子,如下所示: MATCH (me:USER { userid: 'John.Smith' })-[rels:FRIEND*0..1]-(myfriend) MATCH (myfriend)-[:STATUS]-(latestupdate)-[:NEXT*0..15]-(s
用户
节点的每个朋友
关系相关的帖子
链接列表:
用户->[:状态]->发布->[:下一个]->发布->[:下一个]->发布->[:下一个]->发布
我可以从用户朋友那里检索最近的15篇帖子,如下所示:
MATCH (me:USER { userid: 'John.Smith' })-[rels:FRIEND*0..1]-(myfriend)
MATCH (myfriend)-[:STATUS]-(latestupdate)-[:NEXT*0..15]-(statusupdates)
RETURN statusupdates, myfriend
ORDER BY statusupdates.time DESC SKIP 0 LIMIT 15
现在,其中一些帖子“可能”是其他帖子的共享,这些帖子存储在图中的其他地方。为了保持提要检索的简单性,我们正在进行一些非规范化,并将共享帖子的post\u id
存储在这些链接列表中新的post
上
因此,偶尔一个用户的朋友会共享同一个帖子,导致返回的几个statusupdates
具有相同的share
id/属性。这样的结果会在应用程序级别汇总(John、Jane和Sarah分享了这篇文章)
但这当然意味着有时检索15个结果不会产生15个实际的新闻提要条目。因为多个项目最终聚合到一个项目中
我的第一反应是简单地确保上述查询中的LIMIT
子句增加结果集中找到的共享属性的数量,以便在足够可用时,我们仍然会得到15个单独的新闻提要项目(应用程序级聚合后)
例如:
如果我们有4篇文章都具有相同的share
id,另外2篇文章具有另一个share
id,并且所有其他文章都没有share属性,那么我们需要在LIMIT
子句中添加add(4+2)或6
不幸的是,LIMIT
子句似乎不能使用变量,因此简单地计算share
属性的出现次数并增加LIMIT
是不可能的
我怎样才能最好地处理这件事
在限制结果之前,Neo4J可以进行这种聚合吗?如果是这样,那么如何?< p>您可能想从任何共享帖子到原始帖子中考虑[O:Orth]关系。这可以让您对原始帖子执行聚合,并收集共享/发布帖子的人的朋友。类似这样的内容(未测试):
如果是朋友的原始帖子,则来源将与statusupdate相同(没有来源关系,因此statusupdate本身返回为来源),并且集合中只有一个朋友
如果它是由几个朋友共享的帖子,则来源将是原始帖子,朋友集合将包括共享该帖子的所有朋友
如果一个朋友发布了原文,而另一个朋友共享了原文,那么了解发布原文的人会很有用。这是您可以轻松添加到查询中的内容,或者您可以简单地返回原始海报id并在应用程序层中查找匹配项。这似乎是您想要的:
MATCH (me:USER { userid: 'John.Smith' })-[rels:FRIEND]-(myfriend)
MATCH (myfriend)-[:STATUS|NEXT*..16]-(statusupdates)
WITH statusupdates, myfriend
ORDER BY statusupdates.time DESC
WITH REDUCE(s = {ids:[], res:[]}, x IN COLLECT({statusupdates: statusupdates, myfriend: myfriend}) |
CASE
WHEN SIZE(s.ids) < 15 THEN
CASE
WHEN x.statusupdates.post_id IS NULL THEN
CASE
WHEN x.statusupdates.id IN s.ids THEN
{ids: s.ids, res: s.res + x}
ELSE {ids: s.ids + x.statusupdates.id, res: s.res + x}
END
WHEN x.statusupdates.post_id IN s.ids THEN
{ids: s.ids, res: s.res + x}
ELSE {ids: s.ids + x.statusupdates.post_id, res: s.res + x}
END
ELSE s
END) AS out
UNWIND out.res AS result
RETURN result;
MATCH(me:USER{userid:'John.Smith'})-[rels:FRIEND]-(myfriend)
匹配(myfriend)-[:状态|下一步*.16](状态更新)
有状态更新,我的朋友
按状态更新订购。时间描述
在COLLECT中使用REDUCE(s={ids:[],res:[]},x({statusupdates:statusupdates,myfriend:myfriend})|
案例
当尺寸(s.ID)<15时
案例
当x.statusupdates.post_id为空时
案例
当x.statusupdates.id位于s.ids中时
{ids:s.ids,res:s.res+x}
ELSE{ids:s.ids+x.statusupdates.id,res:s.res+x}
结束
当x.statusupdates.post_id出现在s.ids中时
{ids:s.ids,res:s.res+x}
ELSE{ids:s.ids+x.statusupdates.post_id,res:s.res+x}
结束
其他
结束)作为输出
因此,请释放出.res
返回结果;
该逻辑最多返回15个唯一的更新id,允许多次引用同一id。它假定所有更新都有一个唯一的id
属性和一个可选的post\u id
属性,该属性引用另一个更新。REDUCE
子句只会将更新的id
放入ids
集合,如果它没有post\u id
属性(并且它不在集合中),否则它会将post\u id
值放入集合中(如果它不在集合中)。只要ids
集合的大小小于15,它就会将每个update/myfriend对添加到res
集合中;达到最大大小后,集合将保持不变
请注意,原始查询中的[rels:FRIEND*0..1]
语法也将通过me
返回帖子,这似乎与您所说的不一致。如果你真的只是想要朋友的帖子,请使用[rels:FRIEND]
,就像我在查询中所做的那样。谢谢。这种方法与我们当前的方法相比,性能如何?请记住,我们还将在这个查询中检查like等,并需要在scale中实时查询它。只是为了解释一下,我们试图利用这样一个事实,即出于其他原因,我们只在Neo4j中存储关系,所有实际的post数据都存储在DynamoDB中。我们收集所有帖子id和共享id,并在DynamoDB中进行快速查找以获取数据,然后将其聚合并粘贴在一起。其目的是将新闻提要读取期间的遍历保持在绝对最小。我们仍然打算用[:ORIGIN]关系链接post节点,只是在查询过程中不使用它。为了获得最佳结果,您需要在这个节点上进行您自己的配置文件测试(如果已经计划了:ORIGIN关系,那么这很容易),但我不希望更改会对速度产生太大影响,因为它只是每个statusupdate的一次额外遍历,并且不会发出任何额外的行。您说它只是一次
MATCH (me:USER { userid: 'John.Smith' })-[rels:FRIEND]-(myfriend)
MATCH (myfriend)-[:STATUS|NEXT*..16]-(statusupdates)
WITH statusupdates, myfriend
ORDER BY statusupdates.time DESC
WITH REDUCE(s = {ids:[], res:[]}, x IN COLLECT({statusupdates: statusupdates, myfriend: myfriend}) |
CASE
WHEN SIZE(s.ids) < 15 THEN
CASE
WHEN x.statusupdates.post_id IS NULL THEN
CASE
WHEN x.statusupdates.id IN s.ids THEN
{ids: s.ids, res: s.res + x}
ELSE {ids: s.ids + x.statusupdates.id, res: s.res + x}
END
WHEN x.statusupdates.post_id IN s.ids THEN
{ids: s.ids, res: s.res + x}
ELSE {ids: s.ids + x.statusupdates.post_id, res: s.res + x}
END
ELSE s
END) AS out
UNWIND out.res AS result
RETURN result;