一尘不染

MySQL查找相关文章

sql

我试图选择最多10条相关文章,其中相关文章是与其他文章具有3个或更多相同关键字的文章。

我的表结构如下:

articles[id, title, content, time]
tags[id, tag]
articles_tags[article_id, tag_id]

我可以在一个查询中选择所有相关的文章ID和标题吗?

任何帮助是极大的赞赏。


阅读 117

收藏
2021-05-05

共1个答案

一尘不染

假设标题也是唯一的

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

在何处排除“种子”文章

因为我并不在乎我匹配哪个标签,而只是在3个标签上匹配,所以我只需要tag_id并完全避免连接到标签表。因此,现在我将多对多表与其自身相连,以查找具有重叠部分的文章。

问题是该文章将100%匹配到自己,因此我们需要从结果中消除它。

您可以通过3种方式排除该记录。您可以将其从表中筛选到联接之前,可以使其脱离联接,也可以在完成后对其进行筛选。

如果在开始加入之前将其消除,则不会获得太多优势。您有成千上万的文章,而您只消除了1。我还认为,基于article_tag映射表的最佳索引,这将无用。

如果将其作为连接的一部分进行,则不等式将阻止该子句成为索引扫描的一部分,并在索引扫描之后用作过滤器。

将article_tags上的索引视为(Tag_ID,Article_ID)。如果我在tag_id =
tag_id上将索引与其自身相连,那么我将通过将索引移至我的“种子”文章所具有的每个tag_id来立即定义要处理的索引切片。如果添加子句article_id!=
article_id,则无法使用索引来定义要处理的切片。这意味着它将被用作过滤器。例如,说我的第一个标签是“蓝色”。我浏览索引以获取所有具有“蓝色”的文章。(当然是通过ID)。假设有50行。我们知道1是我的种子文章,49是匹配项。如果我不包括不等式,那么我将包括所有50条记录并继续前进。如果确实包含不等式,则必须检查50条记录中的每条记录,以查看哪些是我的种子,哪些不是我的种子。下一个标签是“木星”,它匹配20,000条。再次,我必须检查索引的该切片中的每一行以排除我的种子文章。在经历了2,5,20次(取决于该种子文章的标签)之后,我现在有了一组完全干净的文章来进行COUNT(*)和HAVING处理。如果我不将不等式作为连接的一部分,而只是将SEED
ID过滤掉,然后通过分组,那么我仅在很短的列表中执行一次该过滤器。

2021-05-05