0

したがって、artcles というテーブルと、article tags というテーブルを含むデータベースがあります。ユーザーが記事を表示するときに、表示されているものと同様のタグを持つ最大 5 つの記事を照会したいと考えています。ここに私の2つのテーブルがあります:

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テーブルで自己結合を行います。改善すべき点があります:

  • tag_idの代わりにCOUNTを使用article_idします。これは記事を関連性で並べ替えたいためであり、一致したタグの数が関連性を示します。
  • tag_idの代わりに参加してkeywordください。インデックスが作成されていない列で結合すると、パフォーマンスの問題が発生します。
  • !=パフォーマンス上の理由から、in JOIN 条件を使用しないでください。関連するすべての記事を取得し、最も関連性の高いもの (現在の記事自体) を削除するだけです。
  • articlesパフォーマンス上の理由から、参加する必要はありません。記事自体は必要ありません。articles5 つの関連記事の 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 を持つ配列を取得し、最初の 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 に答える