2015-11-19 3 views
2

Я уже огляделся на этом сайте, но ни один из них не является именно тем, что я ищу. Многие из них говорят о том, как это делает Facebook, или о том, как Twitter делает это, чтобы предложить последователей, но даже тогда они не дают прямого ответа.
Все, что я нахожу, просто вычисляют взаимных друзей, используя два идентификатора пользователя.Подсказать друзей, основанных на общих друзьях

Я хочу, чтобы иметь возможность регистрировать идентификатор пользователя, проходить через своих друзей и проходить через своих друзей, чтобы рассчитать тех, у кого есть самые общие друзья с зарегистрированным пользователем, чтобы предложить людям добавить, что есть самые общие друзья.

Для этого я использую 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>"; 
    } 
    } 

и он работает, перечисляя от друзей, которые друзья друзей пользователя, но не добавил пользователь ...
ОДНАКО, я могу 't сортировать его, исходя из того, у кого самые общие друзья, что, я думаю, все в порядке (хотя я бы хотел, если бы мог),
, но это тоже не очень эффективный способ сделать это.

Кажется, что для этого потребуется много ресурсов, чтобы пройти через всех друзей пользователя, особенно если у пользователя есть ку добавлено от сотни до тысячи друзей, и у них есть пара от тысячи до тысячи и т. д.

Я не знаком с продвинутым SQL, поэтому я не уверен, как бы я это сделал.

+0

все ли дружба в списке дважды, один раз как 'friend1' и один раз как' friend2'? – Sean

+0

@Sean да, для каждой дружбы есть две строки. friend1 всегда является зарегистрированным пользователем, а friend2 всегда является другим пользователем. (Это для простоты, я понимаю, что это может быть не лучший способ сделать это с точки зрения эффективности) – Axiom

+0

@Axiom Можете ли вы увидеть мой ответ. Он возвращает всех общих друзей. Если какая-либо проблема, прокомментируйте ответ. Я помогу тебе. –

ответ

2

Это попытка сделать это с помощью 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

+0

Прохождение результатов этого в PHP немного запутанно ... Кажется, что он возвращает список общих друзей и т. Д., Но как я могу сказать, какие из них не добавляются к текущему пользователю? Вот что я пытаюсь: http://pastebin.com/JKLyP3nW - Это показывает некоторых друзей, которых я добавил, а некоторые нет. Извините, если я не делаю что-то правильно, например, я сказал, что я ноб, когда речь идет о расширенных SQL-запросах. Lol – Axiom

+0

Для лучшей справки, вот скрипка, использующая данные из фактической таблицы (она просто содержит идентификаторы пользователей, t думаю, что это будет проблемой) - http://sqlfiddle.com/#!9/c38b5c/1 - Он должен вернуть следующие идентификаторы: '24',' 25', '43',' 44', ' 138' и '139', насколько мне известно. Мой идентификатор - '1'. – Axiom

+1

Я отредактировал свой ответ с обновлением. Я забыл исключить текущих друзей зарегистрированного пользователя. Кроме того, в примере [sqlFiddle] (http://sqlfiddle.com/#!9/c38b5c/2) не отображается '24', так как у вас есть' (21,24,1) ', поэтому' pending! = 0 ', – Sean

-1

Вы можете сделать это с помощью одного запроса sql. Для этого вы должны написать внутренний запрос sub sql. Посмотрите на следующий запрос. Он возвращает идентификаторы взаимного друга, когда он регистрируется в идентификаторе пользователя.

$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. Если вы хотите знать, как писать sq-sub-запросы, вы можете узнать это, посмотрев 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>"; 
    } 
    } 
+0

О, почему это проголосовали. может somone объяснить ??? :( –

+0

Хотя я не был тем, кто его ниспровергал, он все еще не работает должным образом. Я хотел бы, чтобы JUST предлагал друзьям использовать запрос (если это возможно). должен был сделать некоторую настройку, чтобы заставить ее работать так, как ожидалось, и она по-прежнему использует 4 'foreach()' loops, чтобы заставить ее работать так же, как и моя функция выше. (И все еще не может сортировать, у кого больше всего взаимных связей) Ссылка на конечную функцию: http://pastebin.com/1qFnax4y. Однако, насколько мне известно, она работает лучше, поскольку она меньше запрашивает базу данных. Не обязательно то, что я хотел. Спасибо, однако. – Axiom

+0

Это возвращает список друзей моих друзей. Кажется, я вижу пользователей более чем один раз, используя эту точную функцию. (Переключение 'foreach ($ data-> results() как $ взаимный-> friend2)', поскольку он потянул 'friend2'). Вот скриншот о том, что я имею в виду, так как я не могу объяснить это хорошо: http://i.imgur.com/k2mSIyA.png | Вот почему я добавил дополнительные 'foreach()' циклы в пастебин. Ссылка pastebin возвращает друзей, с которыми я еще не являюсь друзьями, но имею взаимные отношения. Чтобы понять это, я не ищу список взаимных ссылок, но список пользователей, предлагающих зарегистрированному пользователю добавлять на основе того, кто имеет большинство взаимных связей. – Axiom

Смежные вопросы