建立基于共同朋友的朋友

时间:2015-11-19 04:07:04

标签: php mysql social-networking

我已经浏览了这个网站,但似乎没有一个正是我正在寻找的。他们中的很多人都在谈论Facebook如何做到这一点,或推特如何推荐追随者,但即便如此,他们也没有给出任何直截了当的回答。
我发现的所有这些只是使用两个用户ID来计算共同的朋友。

我希望能够获取登录用户的ID,浏览他们的朋友,并通过他们的朋友来计算与登录用户拥有最多共同朋友的人,建议人们添加具有最共同的朋友。

我正在使用PHP和MySQL。我似乎无法理解我是如何做到这一点的。

我的友谊表看起来像这样:

---------------------------------
| friend1 |  friend2  | pending |
---------------------------------
|    1    |     2     |    0    |
|    2    |     1     |    0    |
|    3    |     1     |    0    |
|    1    |     3     |    0    |
---------------------------------

此表显示user_id 1是2和3的朋友 和2不是3的朋友,而是1的朋友。

因此,如果用户登录到user_id 2,我希望它建议user_id 3,因为他们都是user_id 1的朋友。

到目前为止:

  public function friendList($user_id = null){
    if(!$user_id){
      $user_id = $this->_data->user_id;
    }
    $query = "SELECT friend2 FROM user_friends WHERE pending = 0 AND ((friend1 = ".$user_id.") AND (friend2 IN (SELECT user_id FROM users WHERE active = 1 AND user_id = friend2)))";
    $data = $this->_db->hardquery($query);
    return $data->results();
  }
  public function suggestUsers(){
    $user_id = $this->_data->user_id;
    $my_friends = array();
    $suggest_friends = array();
    foreach($this->friendList() as $friend){
      array_push($my_friends,$friend->friend2);
    }
    foreach($my_friends as $friend_id){
      foreach($this->friendList($friend_id) as $friendOfFriend){
        $friendOfFriend = $friendOfFriend->friend2;
        if(!in_array($friendOfFriend,$my_friends) && $friendOfFriend != $user_id){
          array_push($suggest_friends,$friendOfFriend);
        }
      }
    }
    foreach($suggest_friends as $sgf){
      $sgf = new user($sgf);
      $sgf = $sgf->data();
      echo "<a href=\"#\">".$sgf->display."</a><br>";
    }
  }

并且它有效,列出了作为用户朋友的朋友的朋友,但没有添加用户...
但是,我不能根据谁拥有最多的共同朋友来排序,我认为这是可以的(虽然我想,如果可以),但它似乎也不是一种非常有效的方式这样做..

这似乎需要花费很多资源来完成所有用户的朋友,特别是如果用户添加了几百到一千个朋友,并且他们添加了几百到一千个等等。

我对高级SQL并不熟悉,所以我不确定如何做到这一点。

2 个答案:

答案 0 :(得分:2)

这是尝试使用1个查询执行此操作。我们的想法是选择friend2列表,然后将其加入friend2friend1的选择中。使用GROUP BY,我们可以返回按友谊相关性排序的行,以及与该人成为朋友的每个人。

SELECT 
    a.friend2, 
    COUNT(*) as relevance, 
    GROUP_CONCAT(a.friend1 ORDER BY a.friend1) as mutual_friends 
FROM 
    user_friends a
JOIN 
    user_friends b
ON  (
     b.friend2 = a.friend1
     AND b.pending = 0 
     AND b.friend1 = LOGGED_IN_USER
    )
WHERE 
    a.pending = 0
AND 
    a.friend2 != LOGGED_IN_USER
GROUP BY 
    a.friend2
ORDER BY 
    relevance DESC;

A sqlFiddle example - http://sqlfiddle.com/#!9/3dbf0/3

修改

在我的原始查询中,我忘记排除任何已经与LOGGED_IN_USER成为朋友的用户。通过使用不存在友谊的LEFT JOINIS NULL,这应该返回您想要的结果。

SELECT 
    a.friend2, 
    COUNT(*) as relevance, 
    GROUP_CONCAT(a.friend1 ORDER BY a.friend1) as mutual_friends 
FROM 
    user_friends a
JOIN 
    user_friends b
ON  (
     b.friend2 = a.friend1
     AND b.pending = 0 
     AND b.friend1 = LOGGED_IN_USER
    )
LEFT JOIN
    user_friends c
ON
    (
     c.friend2 = a.friend2 
     AND c.pending = 0 
     AND c.friend1 = LOGGED_IN_USER
    )     
WHERE 
    a.pending = 0
AND
    c.friend1 IS NULL
AND 
    a.friend2 != LOGGED_IN_USER
GROUP BY 
    a.friend2
ORDER BY 
    relevance DESC;

更新sqlFiddle example - http://sqlfiddle.com/#!9/c38b5c/2

答案 1 :(得分:-1)

您可以通过单个SQL查询来实现。你应该为此编写sql内部子查询。看下面的查询。当给定登录用户ID时,它返回共同的朋友ID。

$sql= "SELECT `friend2` FROM `user_friends` WHERE `friend1` IN (SELECT `friend2` FROM `user_friends` WHERE `friend1`=$logged_in_user_id) AND `friend2` != $logged_in_user_id";

只需传递变量$logged_in_user_id的登录用户ID即可。如果您想知道如何编写sql子查询,可以通过查看Sql Sub Queries link来了解它。

以下功能将输出共同的朋友数据。

public function testSuggest(){
    $logged_in_user_id = $this->_data->user_id;
    $suggest_friends = array();
    $sql = "SELECT `friend2` FROM `user_friends` WHERE `friend1` IN (SELECT `friend2` FROM `user_friends` WHERE `friend1`=$logged_in_user_id) AND `friend2` != $logged_in_user_id AND `friend2` IN (SELECT `user_id` FROM `users` WHERE `active`=1 AND `user_id` = `friend2`)";
    $data = $this->_db->hardquery($sql);
    foreach($data->results() as $mutuals){
          array_push($suggest_friends,$mutuals);
    }
    foreach($suggest_friends as $sgf){
      $sgf_user = new user($sgf);
      $sgf_user_data = $sgf_user->data();
      echo "<a href=\"".config::get('site/url')."/u/".$sgf_user_data->username."\">".$sgf_user_data->display."</a><br>";
    }
  }