2009-09-02 2 views
1

В mysql я использую «join tables» для назначения меток элементам. Я хотел бы видеть, какие элементы имеют самые похожие теги для просматриваемого элемента.сравнить наборы данных и вернуть наилучшее соответствие

Например, элемент, представляющий интерес, был помечен как «cool», «cars» и «red». Я хотел бы искать другие элементы с этими тегами. Я хочу видеть элементы, которые были помечены как «автомобили», но я хочу, чтобы предметы, помеченные как «автомобили» и «красный», были выше элемента, который был отмечен только «машинами». Я хочу, чтобы элементы с одинаковыми тегами находились в верхней части результатов.

Есть ли способ сравнить набор данных (подзапрос) с другим набором данных (подзапросом) с использованием IN? В качестве альтернативы, есть ли какой-то трюк, который я могу использовать для оценки их как разделенных запятыми списков с помощью GROUP BY и GROUP_CONCAT()?

ответ

1

Это поможет, если вы покажете нам свои структуры таблиц, поэтому я могу быть более конкретным.

Я предполагаю, что у вас есть структура, которая напоминает это:

Table item: (id, itemname) 
1 item1 
2 item2 
3 item3 
4 item4 
5 item5 

Table tag: (id, tagname) 
1 cool 
2 red 
3 car 

Table itemtag: (id, itemid, tagid) 
1 1 2 (=item1, red) 
2 2 1 (=item2, cool) 
3 2 3 (=item2, car) 
4 3 1 (=item3, cool) 
5 3 2 (=item3, red) 
6 3 3 (=item3, car) 
7 4 3 (=item3, car) 
8 5 3 (=item3, car) 

В общем мой подход был бы начать путем подсчета каждого отдельного тега.

-- make a list of how often a tag was used: 
select tagid, count(*) as `tagscore` from itemtag group by tagid 

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

В нашем примере это будет:

tag tagscore 
1 2   (cool, 2x) 
2 2   (red, 2x) 
3 4   (car, 4x) 


set @ItemOfInterest=2; 

select 
    itemname, 
    sum(tagscore) as `totaltagscore`, 
    GROUP_CONCAT(tags) as `tags` 
from 
    itemtag 
join item on itemtag.itemid=item.id 

join 
    /* join the query from above (scores per tag) */ 
    (select tagid, count(*) as `tagscore` from itemtag group by tagid) as `TagScores` 
    on `TagScores`.tagid=itemtag.tagid 
where 
    itemid<>@ItemOfInterest and 
    /* get the taglist of the current item */ 
    tagid in (select distinct tagid from itemtag where [email protected]) 
group by 
    itemid 
order by 
    2 desc 

Объяснение: Запрос имеет 2 подзапросов: Один из них, чтобы получить теги список из пункта интереса. Мы только хотим работать с ними. Другой подзапрос генерирует список оценок для каждого тега.

Итак, в конце каждого элемента базы данных есть список оценок тегов. Эти оценки складываются с sum(tagscore), и этот номер используется для заказа результата (самые высокие оценки сверху).

Чтобы показать список доступных тегов, я использовал GROUP_CONCAT.

Запрос приведет к чему-то вроде этого (я сделал фактические данные здесь):

Item TagsScore Tags 
item3 15   red,cool,car 
item4 7   red,car 
item5 7   red 
item1 5   car 
item6 5   car 
+0

оба этих ответа были на правильном пути и привели меня к краткосрочному решению. С точки зрения того, как масштабировать эту рутину, я все еще ищу! – seans

2

Как об этом:

SELECT post, SUM(IF(tag IN ('cool', 'cars', 'red'), 1, 0)) AS number_matching 
FROM tags 
GROUP BY post 
ORDER BY number_matching DESC 

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

+0

Что бы разобраться в работе, за исключением того, что вам придется динамически генерировать этот запрос, потому что каждый пункт может иметь различный набор тегов. Жесткокодированный список можно заменить подзапросом, чтобы решить эту проблему. –

+0

Вот что я имел в виду. Отредактировано для уточнения. – VoteyDisciple

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