2016-03-15 13 views
6

Ho due entità nel mio database che sono connesse con una relazione molti a molti. Mi stavo chiedendo quale sarebbe il modo migliore per elencare quali entità hanno le somiglianze più basate su di esso?Corrispondenza di entità simili basate su relazioni molte a molte

Ho provato a fare un conteggio (*) con intersect, ma la query impiega troppo tempo per essere eseguita su ogni voce nel mio database (ci sono circa 20k di record). Durante l'esecuzione della query che ho scritto, l'utilizzo della CPU salta al 100% e il database presenta problemi di blocco.

Ecco un po 'di codice che mostra quello che ho provato:

miei tavoli guardano qualcosa in queste righe:

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

(questo funziona, ma è terribilmente lento) Questa è la domanda che Ho scritto per provare ad elencarli: Di solito filtro anche con la parte superiore 1 & aggiungi una clausola where per ottenere un set specifico di dati correlati.

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 

Spiegazione: Film hanno tag e l'utente può ottenere cercare di trovare film simili a quello che essi selezionati sulla base di altri film che hanno tag simili.

risposta

4

Hmm ... solo un'idea, ma forse non ho capito ... Questa query deve restituire i film migliori appaiati per i tag per un determinato ID filmato:

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: Ho appena realizzato che è per M $ SQL ... ma forse qualcosa di simile può essere fatto ...

+0

Grazie. Ho finito per scrivere una soluzione simile con i join. – newb

+0

E come vanno le prestazioni? BTW. Penso che tu possa guadagnare un po 'di velocità dall'indice per il tag ID – barat

+0

1hr -> 40 secondi – newb

1

Probabilmente dovresti decidere una convenzione di denominazione e mantenerla. Le tabelle sono nomi singolari o plurali? Non voglio entrare in quella discussione, ma scegliere l'una o l'altra.

Senza accesso al database, non so come funzionerà. È appena fuori dalla mia testa. Potresti anche limitare questo valore con il valore M.id per trovare le corrispondenze migliori per un singolo film, il che credo possa migliorare le prestazioni di un bel po '.

Inoltre, TOP x dovrebbe consentire di ottenere le corrispondenze x più vicine.

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

Per quanto ne so, la soluzione di cui sopra non si applica nemmeno a T-SQL e la tua è l'unica soluzione valida. Inoltre, l'altra soluzione viene ridotta a 1 solo mentre stai ricevendo tutto in una volta. Quindi, non sono sicuro del motivo per cui l'altra soluzione ha ottenuto tutti i punti. – Ralph

Problemi correlati