用于活动流的智能MySQL GROUP BY

Chr*_*ens 28 php mysql social-networking

我正在为我们的网站构建一个活动流,并且已经取得了相当不错的进展.

它由两个表提供支持:

:

  • id - 唯一的流项目ID
  • user_id - 创建流项目的用户的ID
  • object_type - 对象类型(当前为'卖方'或'产品')
  • object_id - 对象的内部ID(当前是卖家ID或产品ID)
  • action_name - 针对对象采取的行动(目前是'买'或'心')
  • stream_date - 创建操作的时间戳.
  • hidden - 用户是否已选择隐藏项目的布尔值.

如下:

  • id - 独特的关注ID
  • user_id - 启动"关注"操作的用户的ID.
  • following_user - 正在关注的用户的ID.
  • followed - 执行跟随操作的时间戳.

目前我正在使用以下查询从数据库中提取内容:

查询:

SELECT stream.*,
   COUNT(stream.id) AS rows_in_group,
   GROUP_CONCAT(stream.id) AS in_collection
FROM stream
INNER JOIN follows ON stream.user_id = follows.following_user
WHERE follows.user_id = '1'
  AND stream.hidden = '0'
GROUP BY stream.user_id,
     stream.action_name,
     stream.object_type,
     date(stream.stream_date)
ORDER BY stream.stream_date DESC;
Run Code Online (Sandbox Code Playgroud)

这个查询实际上运行得很好,并且使用一点点PHP来解析MySQL返回的数据我们可以创建一个很好的活动流,如果行为之间的时间不是太大,同一个用户被分组在一起的行为相同(见下面的例子).

当前流输出示例

我的问题是,我如何让这更聪明?目前,它通过一个轴"用户"活动进行分组,当特定用户在特定时间范围内有多个项目时,MySQL知道将它们分组.

我怎样才能使这个更智能,并按另一个轴分组,例如"object_id",所以如果同一个对象按顺序有多个动作,则这些项被分组,但保持我们当前用于按用户分组动作/对象的分组逻辑.并实现这一点,没有数据重复?

按顺序出现的多个对象的示例:

多个对象按顺序出现

我理解像这样的问题的解决方案可以变得非常复杂,非常快,但我想知道是否有一个优雅的,相当简单的解决方案(希望)在MySQL中.

O. *_*nes 18

关于您期望的结果的一些观察:

一些项目是汇总的(杰克斯普拉特心灵七个卖家)和其他项目(尼尔森勋爵特许黄金后市).您可能需要在查询中使用UNION,它将来自两个单独子查询的这两类项目合并在一起.

您可以使用一个相当原始的时间戳,贴近功能组的项目...... DATE().你可能想要使用更复杂和可调整的方案......也许这样

  GROUP BY TIMESTAMPDIFF(HOUR,CURRENT_TIME(),stream_date) DIV hourchunk
Run Code Online (Sandbox Code Playgroud)

这将允许您按年龄块分组.例如,如果您使用48,则hourchunk可以将0-48小时前的内容组合在一起.在向系统添加流量和操作时,您可能希望降低该hourchunk值.


boi*_*ert 14

我的印象是你需要像用户一样按用户分组,而且在分组之后,还需要按行动进行分组.

它看起来像你需要这样的子查询:

SELECT *, -- or whatever columns
   SUM(actions_in_group) AS total_rows_in_group,
   GROUP_CONCAT(in_collection) AS complete_collection
   FROM
     ( SELECT stream.*, -- or whatever columns
          COUNT(stream.id) AS actions_in_user_group,
          GROUP_CONCAT(stream.id) AS actions_in_user_collection
       FROM stream
       INNER JOIN follows
       ON stream.user_id = follows.following_user
       WHERE follows.user_id = '1'
         AND stream.hidden = '0'
       GROUP BY stream.user_id,
            date(stream.stream_date)
     )
   GROUP BY object_id,
            date(stream.stream_date)
   ORDER BY stream.stream_date DESC;
Run Code Online (Sandbox Code Playgroud)

您的初始查询(现在是内部查询)按用户分组,但随后用相同的操作重新组合用户组 - 也就是说,购买的相同产品或来自一个卖方的销售将被放在一起.


Thi*_*rry 6

在Fashiolista,我们开放了构建饲料系统的方法. https://github.com/tschellenbach/Feedly 它是目前最大的开源库,旨在解决这个问题.(但用Python编写)

构建Feedly的同一团队还提供托管API,可以为您处理复杂性.看看getstream.io有PHP,Node,Ruby和Python的客户端. https://github.com/tbarbugli/stream-php 它还支持您正在寻找的自定义聚合.

另外看看这个高可扩展性的帖子,我们解释了一些涉及的设计决策:http: //highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic- feeds.html

本教程将帮助您使用Redis设置Pinterest的Feed这样的系统.开始使用非常简单.

要了解有关Feed设计的更多信息,我强烈建议您阅读我们基于Feedly的一些文章:


Nik*_*ica 6

我们通过使用"物化视图"方法解决了类似问题 - 我们正在使用专用表来更新插入/更新/删除事件.所有用户活动都记录在此表中,并为预先准备好进行简单的选择和渲染.

好处是简单快速的选择,缺点是插入/更新/删除有点慢,因为日志表也必须更新.

如果这个系统设计得很好 - 这是一个很好的解决方案.

如果您使用带有插入/更新/删除事件的ORM(如Doctrine),这很容易实现