让我们以StackOverflow问题为例。他们每个人都分配了多个标签。如何构建一个算法,根据它们有多少常见标签找到相关问题(按常用标签的数量排序)?
现在我想不出更好的事情,只需选择所有至少有一个共同标记到数组中的问题,然后循环遍历它们,为每个项目分配一些常用标记,然后对这个数组进行排序。
有更聪明的方法吗?完美的解决方案是单个SQL查询。
答案 0 :(得分:8)
这可能与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;
答案 1 :(得分:2)
我没有时间优化WHERE IN()子句,因为死亡很慢。我也没有同时包含索引或指定引擎或排序规则,但这应该是有希望的。请指出任何错误,因为我实际上没有测试过这个草率的代码:
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
答案 2 :(得分: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
答案 3 :(得分:1)
假设我有以下内容:
可标记实体表:
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)并计算得分的结果。
答案 4 :(得分:1)
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