2013-05-01 2 views
2

Я пытаюсь найти пользователь с аналогичным набором интересов, со следующей схемой ..Matching интересов (ближайший сосед) в SQL

USERS - ID name etc 

Interests - ID UID PID 

где ID это уникальный идентификатор для интересов, УИС идентификатор пользователя и PID - это идентификатор продукта. Я смотрел на другие подобные вопросы в SO, но ни у одного из них не было точного ответа.

ПРИМЕР- Допустим, я заинтересован в том, чтобы пользователи с подобным интересом к Джону, и это как две таблицы выглядят как ...

ID Name 
11 John 
12 Mary 
13 Scott 
14 Tim 

ID UID PID 
3 12 123 
4 12 231 
5 12 612 
6 13 123 
7 13 612 
8 14 931 
9 14 214 
10 11 123 
11 11 231 
12 11 781 
13 11 612 

Я хотел бы результат с в таком порядке.

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

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

+0

Если «аналогичный интерес» может быть определена как количество совпадающих идентификаторов продуктов, то вам не нужно ANN ... – luksch

ответ

2

Это начинается с подсчета количества интересов, которые каждый пользователь имеет вместе с Джоном. Подход состоит в том, чтобы взять все интересы Джона, присоединиться к таблице интересов и объединить в счет общих интересов. Вот SQL для этого:

select i.uid, COUNT(*) as cnt 
from (select i.* 
     from interests i join 
      users u 
      on i.uid = i.id 
     where u.name = 'John' 
    ) ilist join 
    interests i 
    on ilist.pid = i.pid and 
     ilist.uid <> i.uid -- forget about John 
group by i.uid 

Но вы на самом деле хотите список продуктов, а не просто счет. Таким образом, вы должны присоединиться назад к интересам таблице:

select i.* 
from (select i.uid, COUNT(*) as cnt 
     from (select i.* 
      from interests i join 
       users u 
       on i.uid = i.id 
      where u.name = 'John' 
      ) ilist join 
      interests i 
      on ilist.pid = i.pid and 
       ilist.uid <> i.uid -- forget about John 
     group by i.uid 
    ) t join 
    interests i 
    on t.uid = i.uid 
group by t.cnt, i.uid 
+0

Это звучит как хорошее решение , но насколько эффективно это будет? – questions

+0

Это зависит от структуры индекса и размеров данных. Для небольших чисел в вашем вопросе запросы должны выполняться хорошо. В базе данных даже 100 * 100 операций должны быть довольно быстрыми. –

+0

Что касается индексов, идентификатор из интересов будет основным ключом и я думаю об индексе как для UID, так и для PID. Что ты предлагаешь? – questions

0

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

SELECT in2.UID FROM users u 
INNER JOIN interest in1 ON (in1.UID = u.ID) 
INNER JOIN interest in2 ON (in2.PID = in1.PID AND in2.UID <> u.ID) 
WHERE u.ID = 11 
GROUP BY in2.UID 
HAVING COUNT(in2.UID) >= 2 
ORDER BY COUNT(in2.UID) DESC 

Поручения гарантирует, что пользователи с наиболее схожими интересами заканчивается первым. HAVING COUNT (in2.UID)> = 2) гарантирует, что пользователи, которые были найдены, имеют как минимум 2 или более аналогичных интереса.

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