让我们以StackOverflow问题为例。他们每个人都分配了多个标签。如何构建一个算法,根据它们有多少常见标签(按常用标签的数量排序)找到相关问题?
现在我想不出更好的事情,只需选择所有至少有一个公共标签的问题进入一个数组,然后循环遍历它们,为每个项目分配一些常用标签,然后对这个数组进行排序。
这样做有更聪明的方法吗?完美的解决方案是单个SQL查询。
让我们以StackOverflow问题为例。他们每个人都分配了多个标签。如何构建一个算法,根据它们有多少常见标签(按常用标签的数量排序)找到相关问题?
现在我想不出更好的事情,只需选择所有至少有一个公共标签的问题进入一个数组,然后循环遍历它们,为每个项目分配一些常用标签,然后对这个数组进行排序。
这样做有更聪明的方法吗?完美的解决方案是单个SQL查询。
这可能和O(n ^ 2)一样糟糕,但它有效:
create table QuestionTags (questionid int, tag int);
select q1.questionid, q2.questionid, count(*) as commontags
from QuestionTags q1 join QuestionTags q2
where q1.tag = q2.tag and q1.questionid < q2.questionid
group by q1.questionid, q2.questionid order by commontags desc;
我没有时间优化WHERE IN()子句,因为死亡很慢。我也没有同时包含索引或指定引擎或排序规则,但这应该有希望。请指出任何错误,因为我实际上没有测试过这个邋code的代码:
CREATE TABLE question (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
question MEDIUMTEXT
);
CREATE TABLE question_rel_tag (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
question_id INT(11) UNSIGNED NOT NULL,
tag_id INT(11) UNSIGNED NOT NULL
);
CREATE TABLE tag (
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL
);
SELECT question.id, question.title, question.question, count(tag.id) AS `count`
FROM question
INNER JOIN question_rel_tag ON (question.id = question_rel_tag.question_id)
INNER JOIN tag ON (question_rel_tag.tag_id = tag.id)
WHERE question.id != YOUR_QUESTION_ID_HERE
AND tag.id IN
(SELECT tag.id FROM question
INNER JOIN question_rel_tag ON (question.id = question_rel_tag.question_id)
INNER JOIN tag ON (question_rel_tag.tag_id = tag.id)
WHERE question.id = YOUR_QUESTION_ID_HERE)
GROUP BY tag.id
ORDER BY `count` DESC
假设我有以下内容:
可标记实体表:
Taggable
id, stuff
标签表:
Tag
id, tagName
哪些标记与Taggables相关联的连接表
TagInfo
taggableId tagId
然后 :
SELECT COUNT(Taggable_1.id) AS score, Taggable_1.id
FROM dbo.Taggable INNER JOIN
dbo.TagInfo ON dbo.Taggable.id = dbo.TagInfo.taggableId INNER JOIN
dbo.TagInfo TagInfo_1 ON dbo.TagInfo.tagId = TagInfo_1.tagId INNER JOIN
dbo.Taggable Taggable_1 ON TagInfo_1.taggableId = Taggable_1.id
WHERE (dbo.Taggable.id = 1) AND (Taggable_1.id <> 1)
GROUP BY Taggable_1.id
将加入tag-join表对自己(对于查询的问题id;在上面的sql中为1)并计算得分的结果。
假设一张桌子 Questions
使用主键列 Id
, 一张桌子 Tags
使用主键列 Id
,也是一个连接表 QuestionTags
使用复合主键 QuestionId
和 TagId
引用两个前表的主键,以下查询将给出所需的结果(在SQL Server 2005中)。
SELECT q1.Id AS Id1, q2.Id AS Id2,
(SELECT COUNT(*) FROM QuestionTags qt1 INNER JOIN QuestionTags qt2
ON qt1.QuestionId = q1.Id AND qt2.QuestionId = q2.Id AND qt1.TagId = qt2.TagId) AS TagCount
FROM Questions q1 INNER JOIN Questions q2 ON q1.Id < q2.Id
ORDER BY TagCount DESC
这可以改进到以下。
SELECT qt1.QuestionId AS Id1, qt2.QuestionId AS Id2, COUNT(*) AS TagCount
FROM QuestionTags qt1 INNER JOIN QuestionTags qt2
ON qt1.QuestionId < qt2.QuestionId AND qt1.TagId = qt2.TagId
GROUP BY qt1.QuestionId, qt2.QuestionId
ORDER BY TagCount DESC
select *
, count(t.*) as matched_tag_count
from questions q
join tags_to_questions t
on t.question_id = q.id
and t.tag_id in (select tag_id
from tags_to_questions
where question_id = ?)
group
by q.id
order
by matched_tag_count desc