0

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

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 转储数组的结果

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

$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";

        if($query = $this->db->query($query)){

            if($query->num_rows() > 0){

                foreach($query->result_array() as $id => $article){

                    $articles[$id] = $this->fetch_article($article['article_id']);

                }

            } else {

                $articles = array();

            }

        } else {

            $articles = array();

        }

        return $articles;

    }

4

1 回答 1

0

article_tags基本上你的想法是正确的——在桌子上做一个自我加入。有一些你应该改进的地方:

  • COUNTtag_id而不是article_id,因为您想按相关性对文章进行排序,并且匹配标签的计数表示相关性。
  • 加入tag_id而不是keyword. 加入非索引列将是一个性能问题。
  • !=出于性能原因,请勿使用in JOIN 条件。只需获取所有相关文章并删除最相关的一篇,这应该是当前文章本身
  • 出于性能的原因,加入articles不是必需的。您不需要文章本身;articles在获得 5 篇相关文章的 id 后,只需执行简单的 SELECT 即可。

所以答案可能是这样的:

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)
)
于 2012-09-29T05:51:15.503 回答