【问题标题】:Friend of a friend in PHP/MySQL?PHP/MySQL 的朋友的朋友?
【发布时间】:2009-12-30 01:07:48
【问题描述】:

我有一个类似于 myspace/facebook 的社交网络。在我的代码中,你要么是一个人的朋友,要么不是朋友,所以我会展示你是朋友的人的所有动作(在这篇文章中,我将把动作单独称为公告帖子,以便更容易可视化。

因此,每当有人发布公告时,它都会显示给在那里的任何人朋友。

在 mysql 中,你可以通过这样的方式得到一个好友列表,

SELECT user_id FROM friends WHERE friend_id = 1 (user ID)

我想知道像 facebook 和其他网站这样的网站如何显示您朋友和您朋友的朋友的所有公告帖子?

如果有人有想法,请显示一些代码,比如什么样的 mysql 查询?

【问题讨论】:

    标签: php mysql facebook


    【解决方案1】:

    答案是他们没有在朋友表上进行选择,他们很可能使用非规范化的新闻事件表。我们在 DoInk.com 上实现了一个类似于 Facebook 的新闻提要,我们是这样做的:

    有一个“NewsEvent”的概念,它有一个类型、一个发起者(一个用户 ID)和一个目标用户(也是一个用户 ID)。 (您还可以为与活动相关的其他属性添加额外的列,或将它们加入)

    当一个用户在另一个用户墙上发布内容时,我们会生成这样的事件:

    INSERT INTO events VALUES (wall_post_event, user1, user1)
    

    查看 user1 的配置文件时,您会选择 user1 是发起者或目标的所有事件。这就是您显示配置文件提要的方式。 (您可以根据您的隐私模型获得幻想并过滤掉事件。出于性能原因,您可以考虑在内存中执行此操作)

    例子:

    SELECT * FROM events WHERE initiator = user1 or target = user1 //to see their profile feed
    
    SELECT * FROM events WHERE initiator IN (your set of friend ids) //to see your newsfeed
    

    当您想查看与您的朋友相关的所有事件的新闻源时,您可以执行查询,选择发起者在您的朋友集中的所有事件。

    避免使用子选择的实现,根据复杂性,它们不会扩展。

    【讨论】:

      【解决方案2】:

      你做一个子查询:

      SELECT DISTINCT user_id FROM friends WHERE friend_id IN (SELECT user_id FROM friends WHERE friend_id = 1)

      【讨论】:

      • 提醒你,我确信这不是 facebook 的做法,他们做了很多优化,而且他们当然不使用现成的关系数据库。
      • 可能应该区别于这一点,因此您只能获得一次 user_id,即使他们看起来是 很多 人的朋友。
      • @cletus -- 我看过他们的一些技术讲座,但我不能说我看过他们的数据库。你确定他们使用 MySQL 吗? (如果是这样的话......大声笑)
      • 他们使用自定义修改的mysql
      【解决方案3】:

      测试这两个的性能:

      SELECT DISTINCT user_id
      FROM friends f1
      JOIN friends f2 ON f1.friend_id = f2.user_id
      WHERE f2.friend_id = 1
      

      SELECT DISTINCT user_id
      FROM friends
      WHERE friend_id IN (SELECT user_id FROM friends WHERE friend_id = 1)
      

      通常它们是相同的,但有时它们不是。

      确保friend_id 和user_id 已编入索引。

      【讨论】:

        【解决方案4】:

        简单的方法是做一些简单的嵌套子句。所以假设你有一个包含帖子和海报 id 的表,还有一个朋友表,第一层是

        SELECT post FROM posts JOIN friends 
          on post.userid = friends.friend_id 
          WHERE friend.id = 1 (user ID)
        

        然后去交朋友的朋友

        SELECT post FROM posts JOIN
           (SELECT DISTINCT friends_2.friend_id FROM friends AS friends_1 
                JOIN friends as friends_2 
                on friends_1.friend_id = friends_2.id where friends_1.id = 1) 
        AS friends 
        wHERE post.userid = friends.friend_id AND mainid = 1 (user ID)
        

        您可以在每次想要添加另一层朋友抽象时重复此嵌套。这种方法的问题是执行需要很长时间。每次添加朋友抽象层时,复杂性都会增加 n 次方(其中 n 是表中的行数)。

        他们更有可能将可查看的朋友保存在某个表格中,所以让我们创建一个名为 friends_web 的新表格

        user_id, friend_id, level
        

        当用户与某人成为朋友时,它会将新朋友添加到 Friends_web 中,级别为 0(因为该朋友没有人离开),然后将该朋友的朋友添加到级别 1(因为它的 1 个朋友离开)。为了保持表的完整性,您还需要添加倒排记录。为了澄清 A 是否将 B 添加为好友,而 C 是 B 的好友,以下两条记录将被添加到我们的新表中

        A, C, 1
        C, A, 1
        

        因为现在A可以看到C,C也可以看到A。

        现在当我们想要查询时,我们就去做

         SELECT post FROM posts 
          JOIN friends_web ON post.user_id = friends_web.friend_id 
          WHERE friends_web.user_id = user_id AND friends_web.level < 2 (or however deep you want to look)
        

        通过这样做,您在进行帖子查找时最大程度地降低了查询的复杂性,同时能够深入查看超过 1 层的朋友网络。

        抱歉,回答冗长。

        【讨论】:

          【解决方案5】:

          这应该会拉出所有用户朋友的帖子。

          SELECT * FROM posts WHERE uid IN (SELECT friend_uid FROM friends WHERE uid=1) ORDER BY post_id DESC

          这应该会删除您朋友的朋友的所有帖子。

          SELECT * FROM posts WHERE uid IN (SELECT friend_uid FROM friends WHERE uid IN (SELECT friend_uid FROM friends WHERE uid=1)) ORDER BY post_id DESC

          【讨论】:

            猜你喜欢
            • 2015-10-21
            • 1970-01-01
            • 1970-01-01
            • 2011-08-10
            • 2013-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多