2010-07-16 22 views
7

Ho tre tabelle di un database MySQL utilizzati in un'applicazione di libreria musicale:MySQL Parole chiave di ricerca in più tabelle

La tabella Genre ha colonne:

  • id
  • title (stringa)

La tabella Album ha colonne:

  • id
  • genre_id (chiave esterna Genre.id)
  • title (stringa)
  • artist (stringa)

e la tabella Track comprende colonne:

  • id
  • album_id (chiave esterna Album.id)
  • title (stringa)

Ogni Album può avere qualsiasi numero di Tracks, ciascuna Track ha un Album, e ciascuno ha una AlbumGenre.


Voglio realizzare una ricerca parola chiave che permette all'utente di inserire qualsiasi numero di parole chiave e trovare tutti Tracks che:

  • hanno una corrispondenza title,
  • sono su un Album con un corrispondenti a title o artist,
  • o su un Album con un Genre con un valore di corrispondenza title.

I risultati devono essere ordinati per pertinenza. Sarebbe bello se ogni campo avesse una classifica per rilevanza. Ad esempio, lo title di un Track potrebbe essere più importante dello title dello Genre.

Inoltre, la soluzione dovrebbe utilizzare una qualche forma di ricerca parziale. Una ricerca di rubber dovrebbe prima partita tutto Tracks con una title di Rubber, poi abbinare Tracks con un title corrispondenza *rubber* (* = wildcard), per poi passare a Albums, e così via. Tuttavia, non sono così determinato su questi dettagli. Sto solo cercando una soluzione più generale che possa essere modificata per soddisfare le mie esigenze specifiche.

Devo anche menzionare che sto usando uno stack LAMP, Linux, Apache, MySQL e PHP.


Qual è il modo migliore per attuare questa ricerca di parole chiave?


Aggiornamento: Ho cercato di attuare questa tramite una ricerca full text, e sono venuto su con le seguenti istruzioni SQL.

CREATE TABLE `Genre` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `title` text NOT NULL, 
    PRIMARY KEY (`id`), 
    FULLTEXT KEY (`title`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

INSERT INTO `Genre` VALUES(1, 'Rock'); 

CREATE TABLE `Album` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `genre_id` int(11) NOT NULL, 
    `title` text NOT NULL, 
    `artist` text, 
    PRIMARY KEY (`id`), 
    FULLTEXT KEY (`title`, `artist`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

INSERT INTO `Album` VALUES(1, 1, 'Rubber Soul', 'The Beatles'); 

CREATE TABLE `Track` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `album_id` int(11) NOT NULL, 
    `title` text NOT NULL, 
    PRIMARY KEY (`id`), 
    FULLTEXT KEY (`title`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

INSERT INTO `Track` VALUES(1, 1, 'Drive My Car'); 
INSERT INTO `Track` VALUES(2, 1, 'What Goes On'); 
INSERT INTO `Track` VALUES(3, 1, 'Run For Your Life'); 
INSERT INTO `Track` VALUES(4, 1, 'Girl'); 
+0

Stai cercando corrispondenza esatta o corrispondenza parziale? –

+0

Grazie per la risposta, ho aggiunto più informazioni alla domanda. –

risposta

4

Vorrei utilizzare Apache Solr. Utilizzare Data Import Handler per definire una query SQL che unisce tutte le tabelle, creare un indice di testo completo dal risultato dei dati uniti.


Le colonne denominate come args al match() deve essere la colonna (s) definito per l'indice, nello stesso ordine definito nell'indice. Ma non è possibile definire alcun indice (fulltext o altro) su più tabelle in MySQL.

Quindi non si può fare questo:

WHERE MATCH (g.title, a.title, a.artist, t.title) AGAINST ('beatles') 

Non importa se si sta utilizzando la modalità booleana o la modalità del linguaggio naturale.

Hai bisogno di fare questo:

WHERE MATCH (g.title) AGAINST ('beatles') 
    OR MATCH (a.title, a.artist) AGAINST ('beatles') 
    OR MATCH (t.title) AGAINST ('beatles') 

Potreste anche essere interessati a mia presentazione Practical Full-Text Search in MySQL.

1

definire un indice full-text sulle quattro colonne che ti piace di cercare e poi fare:

SELECT * FROM genre AS g 
    LEFT JOIN album AS a ON g.id = a.genre_id 
    LEFT JOIN tracks AS t ON a.id = t.album_id 
    WHERE MATCH (g.title, a.title, a.artist, t.title) AGAINST ('searchstring'); 

Il resullt verranno ordinati per rilevanza. Vedi qui per maggiori dettagli sulla ricerca full-text: http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html

+0

Il problema è che l'OP vuole una corrispondenza parziale. I caratteri jolly funzionano solo per i caratteri che seguono la stringa di ricerca. Non è possibile applicare il carattere jolly * all'inizio della stringa di ricerca –

+0

Penso che l'unico modo di fare una corrispondenza esatta prima e poi una corrispondenza LIKE * abc * in MySQL sia di utilizzare due query. La soluzione Fulltext, penso, è la più vicina che è possibile ottenere in una sola query. – JochenJung

+0

Funziona, anche se deve essere in modalità booleana. La mia query modificata è: 'SELECT * FROM Genere AS g LEFT JOIN Album AS a ON g.id = a.genre_id LEFT JOIN Traccia AS t ON a.id = t.album_id WHERE MATCH (g.title, a.title, a .artist, t.title) CONTRO ('beatles' IN BOOLEAN MODE) ' Quando eseguo la query senza' IN BOOLEAN MODE', ottengo l'errore '# 1210 - Errori errati per MATCH'. –

0

vorrei usare qualcosa come Sfinge, u può fare un indice fuori della vostra query e quindi eseguire una query che. È un po 'difficile capirlo, ma i risultati sono 10 volte migliori di mysql CONTRO e non avrai più problemi con la velocità.

Problemi correlati