2016-03-15 24 views
6

Tôi có hai thực thể trong cơ sở dữ liệu của mình được kết nối với nhiều mối quan hệ. Tôi đã tự hỏi điều gì sẽ là cách tốt nhất để liệt kê những thực thể nào có nhiều điểm tương đồng nhất dựa trên nó?Kết hợp các thực thể tương tự dựa trên nhiều mối quan hệ

Tôi đã thử đếm (*) với giao nhau, nhưng truy vấn mất quá nhiều thời gian để chạy trên mọi mục nhập trong cơ sở dữ liệu của tôi (có khoảng 20 nghìn bản ghi). Khi chạy truy vấn tôi đã viết, mức sử dụng CPU nhảy tới 100% và cơ sở dữ liệu có vấn đề về khóa.

Dưới đây là một số mã hiển thị những gì tôi đã cố gắng:

bảng của tôi trông giống cùng những dòng này:

/* 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), 
); 

(này hoạt động, nhưng nó là terribly chậm) Đây là câu hỏi mà Tôi đã viết để thử và liệt kê chúng: Thông thường tôi cũng lọc với đầu trang 1 & thêm mệnh đề where để có được một bộ dữ liệu liên quan cụ thể.

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 

Giải thích: Phim có thẻ và người sử dụng có thể được cố gắng tìm phim tương tự như một trong đó họ lựa chọn dựa trên các bộ phim khác mà có thẻ tương tự.

Trả lời

4

Hmm ... chỉ cần một ý tưởng, nhưng có lẽ tôi didnt hiểu ... truy vấn này sẽ trả về phim phù hợp tốt nhất bằng thẻ cho một ID phim đưa ra:

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: Tôi chỉ nhận ra rằng nó cho M $ SQL ... nhưng có thể một cái gì đó tương tự có thể được thực hiện ...

+0

Cảm ơn. Tôi đã viết một giải pháp tương tự với các kết nối. – newb

+0

Và hiệu suất đạt được như thế nào? BTW. Tôi nghĩ rằng, bạn có thể kiếm được một số tốc độ theo chỉ mục cho ID thẻ – barat

+0

1 giờ -> 40 giây – newb

1

Bạn có lẽ nên quyết định một quy ước đặt tên và gắn bó với nó. Bảng danh từ số ít hay số nhiều? Tôi không muốn tham gia vào cuộc tranh luận đó, nhưng chọn cái này hay cái kia.

Không có quyền truy cập vào cơ sở dữ liệu của bạn Tôi không biết điều này sẽ thực hiện như thế nào. Nó chỉ nằm ngoài đỉnh đầu tôi. Bạn cũng có thể giới hạn giá trị này theo giá trị M.id để tìm các kết quả phù hợp nhất cho một bộ phim mà tôi cho rằng sẽ cải thiện hiệu suất một chút.

Ngoài ra, TOP x sẽ cho phép bạn nhận được x kết quả phù hợp nhất.

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

Theo như tôi có thể nói các giải pháp trên thậm chí không áp dụng cho T-SQL và của bạn là giải pháp hợp lệ duy nhất. Ngoài ra, giải pháp khác được thu hẹp xuống chỉ còn 1 tiêu đề trong khi bạn nhận được tất cả cùng một lúc. Vì vậy, không chắc chắn tại sao giải pháp khác có tất cả các điểm. – Ralph

Các vấn đề liên quan