与相关的MySQL相关标签

时间:2012-09-29 05:12:04

标签: php mysql join

所以,我有一个名为artcles的数据库,还有一个名为article标签的表。当用户查看文章时,我想查询最多五篇文章,这些文章的标签与正在查看的标签类似。这是我的两张桌子:

CREATE TABLE `articles` (
  `article_id` int(15) NOT NULL AUTO_INCREMENT,
  `parent_id` int(15) NOT NULL,
  `author_id` int(15) NOT NULL,
  `title` text NOT NULL,
  `content` text NOT NULL,
  `date_posted` text NOT NULL,
  `views` int(15) NOT NULL,
  `preview` text NOT NULL,
  `status` tinyint(1) NOT NULL,
  `modified_date` text NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE `article_tags` (
  `tag_id` int(15) NOT NULL AUTO_INCREMENT,
  `article_id` int(15) NOT NULL,
  `keyword` varchar(250) NOT NULL,
  PRIMARY KEY (`tag_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE `articles` ( `article_id` int(15) NOT NULL AUTO_INCREMENT, `parent_id` int(15) NOT NULL, `author_id` int(15) NOT NULL, `title` text NOT NULL, `content` text NOT NULL, `date_posted` text NOT NULL, `views` int(15) NOT NULL, `preview` text NOT NULL, `status` tinyint(1) NOT NULL, `modified_date` text NOT NULL, PRIMARY KEY (`article_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `article_tags` ( `tag_id` int(15) NOT NULL AUTO_INCREMENT, `article_id` int(15) NOT NULL, `keyword` varchar(250) NOT NULL, PRIMARY KEY (`tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我已经尝试过编写自己的查询,但它们似乎从不起作用。我想在查询中使用连接,而不是使用CSV和LIKE。这是我到目前为止的查询:

这是我更新的查询: SELECT A2.article_id, count(A2.article_id) AS matches FROM article_tags AS A1 JOIN article_tags ON (A1.keyword = A2.keyword AND 1.article_id != A2.article_id) JOIN articles ON (A2.article_id = A.article_id) AS A WHERE A1.article_id = 1 GROUP BY A2.article_id ORDER BY matches DESC LIMIT 5"

$query = "
            SELECT t2.article_id, count(t2.keyword) AS matches
            FROM article_tags t1
            JOIN article_tags t2 ON (t1.keyword = t2.keyword AND t1.article_id != t2.article_id)
            WHERE t1.article_id = ".$article_id."
            GROUP BY t2.article_id
            ORDER BY matches DESC
            LIMIT 5";

这是使用var_dump转储数组的结果 $query = " SELECT t2.article_id, count(t2.keyword) AS matches FROM article_tags t1 JOIN article_tags t2 ON (t1.keyword = t2.keyword AND t1.article_id != t2.article_id) WHERE t1.article_id = ".$article_id." GROUP BY t2.article_id ORDER BY matches DESC LIMIT 5";

array
  0 => 
    array
      'article_id' => string '2' (length=1)
      'matches' => string '1' (length=1)

array 0 => array 'article_id' => string '2' (length=1) 'matches' => string '1' (length=1)

1 个答案:

答案 0 :(得分:0)

基本上你的想法是正确的 - 在article_tags表上自我加入。有些事情你应该改进:

  • COUNT tag_id而不是article_id,因为您希望按相关性对文章进行排序,匹配标记的数量表示相关性。
  • 加入tag_id而不是keyword。加入非索引列将是性能问题。
  • 出于性能原因,请勿在JOIN条件下使用!=。只需获取所有相关文章,然后删除最相关的文章,这应该是当前文章本身
  • 出于性能原因,没有必要加入articles。你自己不需要文章;在获得5篇相关文章后,只需在articles上做一个简单的选择。

所以答案可能是这样的:

SELECT
    A2.article_id, count(A2.tag_id) AS matches
FROM 
    article_tags A1 
JOIN
    article_tags ON A1.tag_id=A2.tag_id
WHERE
    A1.article_id = 1
GROUP BY
    A2.article_id
ORDER BY
    matches DESC
LIMIT 6   -- instead of 5, because the first result would be the current article

你应该得到一个包含6个ID的数组,然后删除第一个数组,然后执行SELECT(例如在python中):

article_ids = article_ids[1:]
articles = cursor.execute(
    "SELECT * FROM articles WHERE article_id IN (%s)" % ",".join(article_ids)
)