Поиск по ключевым словам MySQL по нескольким таблицам - PullRequest
7 голосов
/ 17 июля 2010

У меня есть три таблицы в базе данных 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 из Track может быть более важным, чем title из Genre.

Кроме того, решение должно использовать некоторую форму частичного поиска. Поиск по rubber должен сначала сопоставить все Tracks с title из 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 ]

4 голосов
/ 17 июля 2010

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


Столбцы, названные как аргументы для 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 .

1 голос
/ 17 июля 2010

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

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

Результат будет отсортирован по релевантности. Смотрите здесь для более подробной информации о полнотекстовом поиске: http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html

0 голосов
/ 19 июля 2010

Я бы использовал что-то вроде Sphinx, вы можете сделать индекс из вашего запроса и затем запросить его.Немного сложно разобраться, но результаты в 10 раз лучше, чем mysql ПРОТИВ, и у вас не будет проблем со скоростью в дальнейшем.

...