7

我在音乐库应用程序中使用的 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一个匹配的titleartist
  • 或在一个AlbumGenre一个匹配的title

结果应按相关性排序。如果每个领域都有相关性排名,那就太好了。例如,titlea 的Track可能比 的 更title重要Genre

此外,解决方案应该使用某种形式的部分搜索。搜索rubber应该首先Tracks与 a titleof匹配所有Rubber,然后Trackstitle匹配的*rubber*( *=wildcard) 匹配,然后移动到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');
4

3 回答 3

5

我会使用Apache Solr。使用数据导入处理程序定义将所有表连接在一起的 SQL 查询,从连接数据的结果创建全文索引。


命名为 MATCH() 的 args 的列必须是您为索引定义的列,其顺序与您在索引中定义的顺序相同。但是您不能在 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')

您可能还对我的演示文稿Practical Full-Text Search in MySQL感兴趣。

于 2010-07-16T22:24:31.053 回答
1

在要搜索的四列上定义全文索引,然后执行以下操作:

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

于 2010-07-16T22:35:25.900 回答
0

我会使用像 Sphinx 这样的东西,你可以从你的查询中创建一个索引,然后查询它。理解起来有点困难,但结果比 mysql AGAINST 好 10 倍,而且你以后在速度方面不会有问题。

于 2010-07-19T17:24:18.090 回答