2012-04-29 2 views
3

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

У меня есть таблица «как», которая имеет 2 столбца «id_user», «id_artist». Вот пример того, как я хотел бы, чтобы работать:

User 1 likes: 
1, 12 
1, 13 
1, 14 
1, 26 
1, 42 
1, 44 

User 2 likes: 
2, 13 
2, 14 
2, 15 
2, 26 
2, 42 
2, 56 

Эти 2 пользователи имеют 4 художников общего. Есть ли способ сравнить эти 2 набора результатов, чтобы найти наиболее похожих людей в базе данных?

Моя первая идея заключалась в том, чтобы соединить симпатии таким образом: «12,13,14,26,42,44» в строке и использовать оценки mysql FULLTEXT для сравнения разных строк. Это не сработало ... не знаю почему, но mysql fulltext работает только с текстом ... не с номерами ...

Любая идея или любая подсказка были бы высоко оценены.

ответ

2

Что-то вроде этого:

SELECT first_user.id_user, second_user.id_user, COUNT(first_user.id_user) AS total_matches 

FROM likes AS first_user 

JOIN likes AS second_user 
ON second_user.id_artist = first_user.id_artist 
AND second_user.id_user != first_user.id_user 

GROUP BY first_user.id_user, second_user.id_user 

ORDER BY total_matches DESC 

LIMIT 1 

Обратите внимание, что это не очень эффективно. Один из способов обойти это - сделать «таблицу кеша», содержащую вывод этого запроса, с удаленной частью LIMIT 1. Добавьте некоторые соответствующие индексы и выполните запрос к этой таблице кеша. Вы можете установить задание cron для периодической обновления этой таблицы.

Пример:

CREATE TABLE IF NOT EXISTS `likes` (
    `id_user` varchar(50) DEFAULT NULL, 
    `id_artist` varchar(50) DEFAULT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

INSERT INTO `likes` (`id_user`, `id_artist`) VALUES ('8', '39'), ('8', '37'), ('4', '37'), ('8', '24'), ('8', '7'), ('4', '28'), ('8', '28'), ('4', '27'), ('4', '11'), ('8', '49'), ('4', '7'), ('4', '40'), ('4', '29'), ('8', '22'), ('4', '29'), ('8', '11'), ('8', '28'), ('4', '7'), ('4', '31'), ('8', '42'), ('8', '25'), ('4', '25'), ('4', '17'), ('4', '32'), ('4', '46'), ('4', '19'), ('8', '34'), ('3', '32'), ('4', '21') 

+---------+---------+---------------+ 
| id_user | id_user | total_matches | 
+---------+---------+---------------+ 
| 8  | 4  |    7 | 
+---------+---------+---------------+ 
+0

Спасибо за помощь, ваш запрос работает как chram :) – MonsieurNinja

+0

@sikko рад помочь! Удачи вам в вашем проекте :) –

0

Можно присоединиться к столу, к самому себе. (Вам нужно указать псевдоним по крайней мере для одной из двух «копий» таблицы, так что ваш запрос не является неоднозначным.)

Таким образом, для двух пользователей вы можете найти «понравившиеся» у них общие сделав соединение таблицы like. Вы также можете найти, какая доля предпочтений пользователя 1 используется Пользователем 2, делая левое соединение и подсчитывая как количество результатов, так и количество нулевых значений. Обратите внимание, что это не симметричная операция, и вам нужно будет решить случай, когда один или оба числа равны 0.

Когда вы говорите, что хотите «найти наиболее похожих людей в базе данных»: вы могли бы сделайте это для каждой пары пользователей, но обратите внимание, что если у вас есть n пользователей, то это включает в себя выполнение n*(n-1)/2 сравнения, которые стоят n в квадрате. Это может быть довольно много работы для вашей базы данных, если у вас много пользователей.

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