В MySQL Поиск По Нескольким Таблицам

у меня есть три таблицы в базе данных MySQL, используемой в приложении музыкальной библиотеки:

на Genre таблица имеет столбцы:

  • id
  • title (строка)

на Album таблица имеет столбцы:

  • id
  • genre_id (внешний ключ Genre.id)
  • title (строка)
  • artist (строка)

и Track таблица колонки:

  • id
  • album_id (внешний ключ Album.id)
  • title (строка)

каждого Album может иметь любое количество Tracks, каждый Track один Album и друг Album один Genre.


я хочу реализовать поиск по ключевому слову, который позволяет пользователю вводить любое количество ключевых слов и найти все Tracks что:

  • есть соответствие title,
  • на Album С соответствующим title или artist,
  • или Album С Genre С соответствующим title.

результаты должны быть отсортированы по релевантности. Было бы здорово, если бы каждое поле имело рейтинг релевантности. Например,title of a Track может быть важнее, чем title на Genre.

кроме того, решение должно использовать некоторую форму частичного поиска. Поиск rubber должен сначала соответствовать всем Tracks С title of Rubber, затем Tracks С title соответствующего *rubber* (* =подстановочный знак), затем перейдите к Albums и так далее. Однако я не очень-то настаиваю на этих деталях. Я просто ищу более общее решение, которое я могу настроить в соответствии с моими конкретными потребностями.

я также должен упомянуть, что я использую стек LAMP, Linux, Apache, MySQL и PHP.


каков наилучший способ реализации этого ключевого слова поиск?


обновление: я пытался реализовать это с помощью полнотекстового поиска и придумал следующие инструкции 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');

3 ответов


Я хотел бы использовать Apache Solr. Используйте Обработчик Импорта Данных чтобы определить SQL-запрос, который объединяет все таблицы вместе, создайте полнотекстовый индекс из результата объединенных данных.


столбцы с именем args to MATCH () должны быть столбцами, определенными для индекса, в том же порядке, что и в индексе. Но вы не можете определить какой-либо индекс (полный текст или иначе) через несколько таблиц в MySQL.

Так что вы не можете сделать это:

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

не имеет значения, используете ли вы логический режим или режим естественного языка.

вам нужно сделать это:

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

вы также можете быть заинтересованы в моей презентации практический полнотекстовый поиск в MySQL.


определите полнотекстовый индекс для четырех столбцов, которые вы хотите найти, а затем выполните:

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');

в resullt будут отсортированы по релевантности. Подробнее о полнотекстовом поиске см. здесь: http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html


Я бы использовал что-то вроде Сфинкса, u может сделать индекс из вашего запроса, а затем запросить это. Это немного сложно, чтобы получить вашу голову вокруг, но результаты в 10 раз лучше, чем mysql против, и у вас не будет проблем позже со скоростью.