我正在尝试最多选择10篇相关文章,其中相关文章是与其他文章有3个或更多相同关键字的文章。
我的表格结构如下:
articles[id, title, content, time]
tags[id, tag]
articles_tags[article_id, tag_id]
我可以在一个查询中选择相关文章的ID和标题吗?
非常感谢任何帮助。
答案 0 :(得分:4)
@updated排除搜索过的文章本身!
沿着这些方向的东西
select *
from articles
inner join (
select at2.article_id, COUNT(*) cnt
from articles a
inner join articles_tags at on at.article_id = a.id
# find all matching tags to get the article ids
inner join articles_tags at2 on at2.tag_id = at.tag_id
and at2.article_id != at.article_id
where a.id = 1234 # the base article to find matches for
group by at2.article_id
having count(*) >= 3 # at least 3 matching keywords
) matches on matches.article_id = articles.id
order by matches.cnt desc
limit 10; # up to 10 matches required
答案 1 :(得分:4)
假设标题也是唯一的
SELECT fA.ID, fA.Title
from
Articles bA,
articles_tags bAT,
articles_tags fAT,
Articles fA
where
bA.title = 'some name' AND
bA.id = bAT.Article_Id AND
bAT.Tag_ID = fAT.Tag_ID AND
fAT.Article_ID = fA.ID AND
fA.title != 'some name'
GROUP BY
fA.ID, fA.Title
HAVING
count(*) >= 3
因为我并不关心我匹配的WHICH标签,只是我在3个标签上匹配,我只需要tag_id并完全避免连接到标签表。所以现在我加入多对多表来找到有重叠的文章。
问题在于文章将100%匹配,因此我们需要从结果中消除这一点。
您可以通过3种方式排除该记录。你可以在加入之前从表中过滤它,你可以让它脱离连接,或者你可以在完成后过滤它。
如果在开始加入之前消除它,那么你就没有获得太大的优势。你有数千或数百万篇文章而且你只是在消除1.我也相信这对于article_tag映射表的最佳索引没有用。
如果在连接过程中执行此操作,则不等式将阻止该子句成为索引扫描的一部分,并在索引扫描后应用为过滤器。
将article_tags上的索引视为(Tag_ID,Article_ID)。如果我在tag_id = tag_id上将索引加入到自身中,那么我将立即定义要处理的索引片段,方法是将索引遍历到我的“种子”文章中的每个tag_id。如果我添加子句article_id!= article_id,则不能使用索引来定义要处理的切片。这意味着它将作为过滤器应用。例如说我的第一个标签是“蓝色”。我走了索引,得到所有“BLUE”的文章。 (当然是ID)。说有50行。我们知道1是我的种子文章,49是匹配。如果我不包括不平等,我将包括所有50条记录并继续前进。如果我确实包含不等式,那么我必须检查50条记录中的每条记录,看看哪个是我的种子,哪些不是。下一个标签是“Jupiter”,它匹配20,000篇文章。我必须再次检查索引的那一片中的每一行以排除我的种子文章。在经历了这个2,5,20次之后(取决于该种子文章的标签),我现在有一套完全干净的文章来做COUNT(*)和HAVING。如果我不将不等式作为我的联接的一部分包括在内,而只是在分组后过滤SEED ID,那么我只在一个非常短的列表上执行一次该文件管理器。
答案 2 :(得分:0)
如果您可以编写查询来获取具有匹配项的记录ID,那么您当然可以使用相同的查询返回标题。如果您真正的问题是“我如何编写查询以返回匹配项?”,那么请说出来,我将编辑此答案,并提供更多详细信息。