MySQL 跨多个表的关键字搜索

发布于 2024-09-10 02:58:04 字数 2551 浏览 5 评论 0原文

我在音乐库应用程序中使用的 MySQL 数据库中有三个表:

Genre 表包含以下列:

  • id
  • title (字符串)

>Album 表包含以下列:

  • id
  • genre_idGenre.id 的外键)
  • title ( string)
  • artist (字符串)

Track 表包含以下列:

  • id
  • album_id的外键Album.id)
  • title (string)

每个Album可以有任意数量的Tracks,每个Track > 有一个专辑,每个专辑有一个流派


我想实现一个关键字搜索,允许用户输入任意数量的关键字并查找以下所有曲目

  • 具有匹配的标题
  • 位于专辑< /code> 具有匹配的标题艺术家
  • 或者位于 专辑 上,流派 具有匹配的 <代码>标题。

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

此外,解决方案应该使用某种形式的部分搜索。搜索 rubber 应首先匹配 titleRubber 的所有 Tracks,然后匹配 Tracks< /code> 与 title 匹配 *rubber* (*=wildcard),然后转到相册,等等。然而,我对这些细节不太确定。我只是在寻找一个更通用的解决方案,我可以对其进行调整以满足我的特定需求。

我还应该提到,我正在使用 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');

I have three tables in a MySQL database used in a music library application:

The Genre table has columns:

  • id
  • title (string)

The Album table has columns:

  • id
  • genre_id (foreign key to Genre.id)
  • title (string)
  • artist (string)

and the Track table has columns:

  • id
  • album_id (foreign key to Album.id)
  • title (string)

Each Album can have any number of Tracks, each Track has one Album, and each Album has one Genre.


I want to implement a keyword search that allows the user to input any number of keywords and find all Tracks that:

  • have a matching title,
  • are on an Album with a matching title or artist,
  • or are on an Album with a Genre with a matching title.

Results should be sorted by relevancy. It would be great if each field had a ranking for relevancy. For example, the title of a Track might be more important than the title of the Genre.

Also, the solution should use some form of partial searching. A search of rubber should first match all Tracks with a title of Rubber, then match Tracks with a title matching *rubber* (*=wildcard), then move on to Albums, and so on. However, I'm not so set on these details. I'm just looking for a more general solution that I can tweak to match my specific needs.

I should also mention that I'm using a LAMP stack, Linux, Apache, MySQL, and PHP.


What is the best way to implement this keyword search?


Update: I've been trying to implement this via a full text search, and have come up with the following SQL statements.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

╰ゝ天使的微笑 2024-09-17 02:58:04

我会使用 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')

您可能也对我的演示感兴趣 MySQL 中的实用全文搜索

I would use Apache Solr. Use the Data Import Handler to define an SQL query that joins all your tables together, create a fulltext index from the result of joined data.


The columns named as args to MATCH() must be the column(s) you defined for the index, in the same order you defined in the index. But you can't define any index (fulltext or otherwise) across multiple tables in MySQL.

So you can't do this:

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

It doesn't matter whether you're using boolean mode or natural language mode.

You need to do this:

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

You may also be interested in my presentation Practical Full-Text Search in MySQL.

星星的軌跡 2024-09-17 02:58:04

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

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

Define a fulltext index on the four columns you like to search and then do:

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

The resullt will be sorted by relevancy.
See here for more details on fulltext search:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html

情泪▽动烟 2024-09-17 02:58:04

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

I would use something like Sphinx, u can make an index out of your query and then query that.
It's a little difficult to get your head around but the results are 10 times better than mysql AGAINST and you won't have problems later on with speed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文