根据共同的朋友推荐朋友
Posted
技术标签:
【中文标题】根据共同的朋友推荐朋友【英文标题】:Suggest friends based off of mutual friends 【发布时间】:2015-11-19 04:07:04 【问题描述】:我已经在这个网站上四处看了看,但似乎没有一个是我正在寻找的。他们中的很多人都在谈论 Facebook 是如何做到的,或者 Twitter 是如何推荐关注者的,但即便如此,他们也没有给出任何直截了当的答案。 我发现的所有这些都只是使用两个用户 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 不太熟悉,所以我不知道该怎么做。
【问题讨论】:
所有好友都列出了两次,一次是friend1
,一次是friend2
?
@Sean 是的,对于每个友谊,有两行。 friend1 始终是登录用户,而friend2 始终是其他用户。 (这是为了简单起见,我意识到这可能不是提高效率的最佳方法)
@Axiom 你能看到我的回答吗?它返回所有共同的朋友。如果有任何问题,请评论答案。我会帮你的。
【参考方案1】:
这里尝试使用 1 个查询来执行此操作。这个想法是选择friend2
列表,并将其加入到friend2
为friend1
的选择中。使用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;
一个sqlFiddle example - http://sqlfiddle.com/#!9/3dbf0/3
编辑
在我的原始查询中,我忘记排除任何已经与LOGGED_IN_USER
成为朋友的用户。通过使用不存在友谊的LEFT JOIN
和IS 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
【讨论】:
在 PHP 中查看这个结果有点令人困惑......似乎它正在返回一个共同朋友的列表等,但我怎么知道哪些没有添加与当前用户?这是我正在尝试的:pastebin.com/JKLyP3nW - 这显示了我添加的一些朋友,而一些我没有。对不起,如果我没有正确地做某事,就像我说我在高级 SQL 查询方面是个菜鸟.. 哈哈 为了更好地参考,这里有一个使用来自实际表的数据的小提琴(它只包含用户 ID,我认为这不是问题) - sqlfiddle.com/#!9/c38b5c/1 - 它应该返回以下 ID:据我所知,24
、25
、43
、44
、138
和 139
。我的 ID 是 1
。
我已通过更新编辑了我的答案。我忘了排除登录用户的当前朋友。此外,sqlFiddle example 不显示24
,因为您有(21,24,1)
,所以pending != 0
,
你是对的,我没有意识到这一点。非常感谢,效果很好!【参考方案2】:
您可以通过单个 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>";
【讨论】:
虽然我不是反对它的人,但它仍然无法按预期工作。我希望能够使用查询(如果可能)获得建议的朋友。我必须做一些调整才能让它按预期工作,它仍然使用 4 个foreach()
循环来让它与我上面的函数一样工作。 (并且仍然无法按谁拥有最多的相互关系) - 链接到最终功能:pastebin.com/1qFnax4y - 但是据我所知,它似乎工作得更好,因为它从数据库中查询的次数更少。只是不一定是我想要的。不过,谢谢。
这似乎返回了我朋友的朋友列表。我不止一次看到用户使用这个确切的功能。 (切换foreach($data->results() as $mutuals->friend2)
,因为它正在拉动friend2
)。这是我的意思的截图,因为我不能很好地解释它:i.imgur.com/k2mSIyA.png |这就是为什么我在 pastebin 链接中添加了额外的 foreach()
循环。 pastebin 链接返回的朋友我还不是朋友,但有共同点。为了清楚起见,我不是在寻找共同点列表,而是根据谁建议登录用户添加的用户列表有最多的互惠生。以上是关于根据共同的朋友推荐朋友的主要内容,如果未能解决你的问题,请参考以下文章