2016-03-15 9 views
6

多対多リレーションシップに接続された2つのエンティティがデータベースにあります。私はどのエンティティがそれに基づいて最も類似しているかをリストする最良の方法は何だろうと思いましたか?多対多関係に基づく類似エンティティの照合

私は交差でカウント(*)を試みましたが、クエリは、データベースのすべてのエントリ(約20kレコードがあります)で実行するには時間がかかりすぎます。私が書いたクエリを実行すると、CPU使用率は100%にジャンプし、データベースにはロックの問題があります。ここで

は、私が試したものを示すいくつかのコードです:私のテーブルは、これらの線に沿って何かを見

/* 20k records */ 
create table Movie(
    Id INT PRIMARY KEY, 
    Title varchar(255) 
); 

/* 200-300 records */ 
create table Tags(
    Id INT PRIMARY KEY, 
    Desc varchar(255) 
); 

/* 200,000-300,000 records */ 
create table TagMovies(
    Movie_Id INT, 
    Tag_Id INT, 
    PRIMARY KEY (Movie_Id, Tag_Id), 
    FOREIGN KEY (Movie_Id) REFERENCES Movie(Id), 
    FOREIGN KEY (Tag_Id) REFERENCES Tags(Id), 
); 

(これは動作しますが、それはひどく遅いです) をこれは、そのクエリです私はそれらを試してリストするように書いた: 私はまた、トップ1でフィルターをかける。&関連するデータの特定のセットを得るためにwhere節を加える。

SELECT 
    bk.Id, 
    rh.Id 
FROM 
    Movies bk 
    CROSS APPLY (
     SELECT TOP 15 
      b.Id, 
      /* Tags Score */ 
      (
      SELECT COUNT(*) FROM (
       SELECT x.Tag_Id FROM TagMovies x WHERE x.Movie_Id = bk.Id 
       INTERSECT 
       SELECT x.Tag_Id FROM TagMovies x WHERE x.Movie_Id = b.Id 
       ) Q1 
      ) 
      as Amount 
     FROM 
      Movies b 
     WHERE 
      b.Id <> bk.Id 
     ORDER BY Amount DESC 
    ) rh 

説明: 作品は、タグを持っており、ユーザーは、彼らが似たタグを持つ他の映画に基づいて選択されたものと類似の映画を探してみてください得ることができます。

答えて

4

うーん...ただのアイデア、多分私は理解していませんでし... このクエリは、特定の映画のIDのためのタグで最高のマッチした映画を返す必要があります:

SELECT m.id, m.title, GROUP_CONCAT(DISTINCT t.Descr SEPARATOR ', ') as tags, count(*) as matches 
FROM stack.Movie m 
LEFT JOIN stack.TagMovies tm ON m.Id = tm.Movie_Id 
LEFT JOIN stack.Tags t ON tm.Tag_Id = t.Id 
WHERE m.id != 1 
AND tm.Tag_Id IN (SELECT Tag_Id FROM stack.TagMovies tm WHERE tm.Movie_Id = 1) 
GROUP BY m.id 
ORDER BY matches DESC 
LIMIT 15; 

はEDIT: 私はちょうどことに気づきましたそれはM $ SQL用ですが、おそらく同様のことができるでしょう...

+0

ありがとうございました。私はジョインで似たような解決策を書いた。 – newb

+0

パフォーマンスはどのように向上しますか? BTW。私は、あなたがタグIDのインデックスで速度を得ることができると思う – barat

+0

1時間 - > 40秒 – newb

1

おそらく命名規則を決めてそれに固執してください。テーブルは単数形か複数形か?私はその議論に入るのではなく、どちらかを選ぶことを望んでいます。

データベースへのアクセスがないと、これはどのように実行されるのかわかりません。それはちょうど私の頭の上にあります。 M.idという値でこれを制限して、1つの映画のベストマッチを見つけることもできます。これは、パフォーマンスをかなり向上させるものだと思います。

また、TOP xは、xに最も近い一致を得ることができます。

SELECT 
    M.id, 
    M.title, 
    SM.id AS similar_movie_id, 
    SM.title AS similar_movie_title, 
    COUNT(*) AS matched_tags 
FROM 
    Movie M 
INNER JOIN TagsMovie TM1 ON TM1.movie_id = M.movie_id 
INNER JOIN TagsMovie TM2 ON 
    TM2.tag_id = TM1.tag_id AND 
    TM2.movie_id <> TM1.movie_id 
INNER JOIN Movie SM ON SM.movie_id = TM2.movie_id 
GROUP BY 
    M.id, 
    M.title, 
    SM.id AS similar_movie_id, 
    SM.title AS similar_movie_title 
ORDER BY 
    COUNT(*) DESC 
+0

私が上記の解決策がT-SQLには適用されず、あなたのものが唯一の有効な解決策であると言えます。また、一度にすべてを取得している間だけ、他のソリューションは1タイトルに絞られています。だから、なぜ他のソリューションがすべてのポイントを得たかわからない。 – Ralph