MySQL查找相关文章

MySQL查找相关文章,sql,mysql,Sql,Mysql,我尝试选择最多10篇相关文章,其中一篇相关文章是一篇与另一篇文章具有3个或更多相同关键字的文章 我的表格结构如下: articles[id, title, content, time] tags[id, tag] articles_tags[article_id, tag_id] 我可以在一次查询中选择相关文章id和标题吗 非常感谢您的帮助。如果您可以编写一个查询来获取具有匹配项的记录的ID,那么您当然可以使用相同的查询返回标题。如果您真正的问题是“如何编写查询以返回匹配项?”,那么请这样说,

我尝试选择最多10篇相关文章,其中一篇相关文章是一篇与另一篇文章具有3个或更多相同关键字的文章

我的表格结构如下:

articles[id, title, content, time]
tags[id, tag]
articles_tags[article_id, tag_id]
我可以在一次查询中选择相关文章id和标题吗


非常感谢您的帮助。

如果您可以编写一个查询来获取具有匹配项的记录的ID,那么您当然可以使用相同的查询返回标题。如果您真正的问题是“如何编写查询以返回匹配项?”,那么请这样说,我将编辑此答案,并提供这些内容的更多详细信息。

如果您可以编写查询以获取具有匹配项的记录的ID,那么您当然可以使用相同的查询返回标题。如果您真正的问题是“如何编写查询以返回匹配项?”,那么请这样说,我将编辑此答案,并提供这些内容的更多详细信息。

@已更新以排除搜索的文章本身

类似这样的东西

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

@已更新以排除搜索的文章本身

类似这样的东西

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

假设标题也是唯一的

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,并完全避免连接到tags表。所以现在我将多对多表连接到它自己,以查找有重叠的文章

问题是文章本身会100%匹配,所以我们需要从结果中消除这一点

您可以通过3种方式排除该记录。您可以在加入前将其从表中筛选到,也可以将其从加入中删除,或者在完成后对其进行筛选

如果在开始加入之前将其消除,则不会获得多少优势。你有数千或数百万篇文章,而你只删除了1篇。我还认为,基于article_标记映射表的最佳索引,这将不会有用

如果将其作为联接的一部分,则不等式将阻止该子句成为索引扫描的一部分,并在索引扫描后作为筛选器应用


将article_标记上的索引视为Tag_ID,article_ID。如果我在Tag_ID=Tag_ID上将索引加入到自身,那么我将通过将索引遍历到我的“种子”文章所具有的每个Tag_ID,立即定义要处理的索引切片。如果我添加子句article_id!=无法使用索引定义要处理的切片的项目id。这意味着它将作为过滤器应用。e、 说我的第一个标签是蓝色的。我遍历索引以获得所有带有蓝色的文章。当然是凭身份证。假设有50排。我们知道1是我的种子文章,49是匹配的。如果我不包括不平等性,我将包括所有50条记录,然后继续。如果我确实包含了不平等性,那么我必须检查50条记录中的每一条,看看哪些是我的种子,哪些不是。下一个标签是Jupiter,它匹配20000篇文章。我必须再次检查索引切片中的每一行,以排除我的种子文章。在我看了2,5,20遍种子文章的标签之后,我现在有了一套完全干净的文章来进行计数*并继续。如果我没有将不平等性作为我的联接的一部分,而只是在group by之后过滤出种子ID,然后在一个非常短的列表中只执行一次文件管理器。

假设标题也是唯一的

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,并完全避免连接到tags表。所以现在我将多对多表连接到它自己,以查找有重叠的文章

问题是文章本身会100%匹配,所以我们需要从结果中消除这一点

您可以通过3种方式排除该记录。您可以在加入前将其从表中筛选到,也可以将其从加入中删除,或者在完成后对其进行筛选

如果在开始加入之前将其消除,则不会获得多少优势。你有数千或数百万篇文章,而你只删除了1篇。我还认为,基于article_标记映射表的最佳索引,这将不会有用

如果将其作为联接的一部分,则不等式将阻止该子句成为索引扫描的一部分,并在索引扫描后作为筛选器应用

将article_标记上的索引视为Tag_ID,article_ID。如果我在Tag_ID=Tag_ID上将索引加入到自身,那么我将通过将索引遍历到我的“种子”文章所具有的每个Tag_ID,立即定义要处理的索引切片。如果我添加子句article_id!=无法使用索引定义要处理的切片的项目id。这意味着它将作为过滤器应用。e、 说我的第一个标签是蓝色的。我遍历索引以获得所有带有蓝色的文章。当然是凭身份证。假设有50排。我们知道1是我的种子文章
49是比赛。如果我不包括不平等性,我将包括所有50条记录,然后继续。如果我确实包含了不平等性,那么我必须检查50条记录中的每一条,看看哪些是我的种子,哪些不是。下一个标签是Jupiter,它匹配20000篇文章。我必须再次检查索引切片中的每一行,以排除我的种子文章。在我看了2,5,20遍种子文章的标签之后,我现在有了一套完全干净的文章来进行计数*并继续。如果我没有将不平等性作为我的联接的一部分,而只是在group by之后过滤出种子ID,然后在很短的列表中只执行一次文件管理器操作。

通过以下方法解决了问题:选择文章。*,B.article\u ID,将*计数为文章的cnt\u标记A加入文章\u标记B使用标记\u id左加入文章B.article\u id=articles.id,其中A.article\u id=1和B.article\u id=1按B.article_id顺序按cnt DESC限制0,30我不认为您的查询中只包含至少3个常用标记的组。。。在某个地方,你需要一个count*>=3是的,我会使用HAVING子句,假设mySql有HAVING,我的背景主要是MS SQL。解决问题的方法是:选择文章。*,B.article\u id,将*计数为文章的cnt\u标记A加入文章\u标记B使用标记\u id左加入文章B.article\u id=articles.id,其中A.article\u id=1和B.article\u id=1按B.article_id顺序按cnt DESC限制0,30我不认为您的查询中只包含至少3个常用标记的组。。。某个地方你需要一个count*>=3是的,我会使用HAVING子句,假设mySql有HAVING,我的背景主要是MS SQL。你是从一篇已知的文章开始,还是只想返回任何10篇与上述内容相关的文章?你是从一篇已知的文章开始,或者你只想退回与上述内容相关的10篇文章吗?是的,这就是我要写的内容问得好+1是的,我本来会写的就是这样问得好+1同意@Stephanie。问得好,@Cyberkiwi!使用此选项,我将如何排除我们正在查找匹配项的文章?编辑添加:和at2.article\u id=1我已更新我的查询,将搜索的文章从匹配项中排除@猕猴桃,我认为如果你把它作为加入的一部分,它会比在一个地方更昂贵。在我编辑的答案中解释。同意@Stephanie。问得好,@Cyberkiwi!使用此选项,我将如何排除我们正在查找匹配项的文章?编辑添加:和at2.article\u id=1我已更新我的查询,将搜索的文章从匹配项中排除@猕猴桃,我认为如果你把它作为加入的一部分,它会比在一个地方更昂贵。在我编辑的答案中解释。