我如何考虑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;