2012-09-29 56 views
0

所以,我有一個名爲artcles的表和一個名爲文章標籤的表的數據庫。當用戶查看文章時,我想查詢最多五個與正在查看的標籤類似的文章。這裏是我的兩個表:MySQL相關標籤加入

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; 

    } 

回答

0

基本上的結果你的想法是正確的 - 在article_tags表上自我加入。有東西,你應該改善:

  • COUNT tag_id代替article_id,因爲你想按相關性排序的文章,並匹配標記的計數指示的相關性。
  • 加入tag_id而不是keyword。加入非索引列將是一個性能問題。
  • 由於性能原因,請勿在JOIN條件下使用!=。只需獲取所有相關文章,並簡單地刪除最相關的文章,這應該是當前文章本身
  • 加入articles沒有必要,因爲表現的原因。你不需要自己的文章;在獲得5篇相關文章的ID後,在articles上做一個簡單的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個IDS,只是去掉第一位的,然後做一個選擇(在Python如):

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

你的建議似乎有幫助,但我遇到了一個問題......當我在PHP中對數組進行迭代時,出於某種原因,它是由正在查看的文章的ID。我已經更新了我原來的問題。 – ShoeLace1291

+0

請將您的'$ query-> result_array()'結果轉儲並查看是否有任何錯誤。我不確定,但我認爲在處理'$ query-> result_array()'的代碼中存在錯誤。 – charlee

+0

我在更新後的查詢和實際的PHP代碼之間添加了var_dump的結果... btw,我使用CodeIgniter來處理這個哈哈。我知道你的查詢沒有問題,因爲數組返回的文章ID實際上會返回正確的ID。被查看文章的ID是1,而被轉儲文章的ID是2.我幾乎可以肯定,問題在於我如何遍歷數組。 – ShoeLace1291