比较数据集并返回最佳匹配

时间:2009-09-02 22:53:07

标签: mysql

在mysql中,我使用“连接表”为项目分配标签。我想看看哪些项目与正在查看的项目具有最相似的标签。

例如,假设感兴趣的项目已被标记为“酷”,“汽车”和“红色”。我想搜索带有这些标签的其他项目。我希望看到标记为“汽车”的物品,但我希望标记为“汽车”和“红色”的物品位于仅标记为“汽车”的物品上方。我希望具有相同标签的项目位于结果的顶部。

有没有办法使用IN将数据集(子查询)与另一个数据集(子查询)进行比较?或者,是否有一些技巧我可以使用GROUP BY和GROUP_CONCAT()将它们作为逗号分隔列表进行评估?

2 个答案:

答案 0 :(得分: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中,如果你已经很方便,或者可以从子查询中生成。

答案 1 :(得分: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 itemid=@ItemOfInterest)
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