我有一个带有音乐歌曲的SQL数据库。每首歌当然都有艺术家,专辑和流派。他们也有一般的普及程度。计数器,是从外部来源获得的。但是,我想让用户有机会对这些歌曲进行投票。最后,搜索结果应按此受欢迎程度排序,以及原始查询结果的准确性。
我使用的当前查询如下:
SELECT *
FROM p2pm_tracks
WHERE
`artist` LIKE '%$searchquestion%' OR
`genres` LIKE '%$searchquestion%' OR
`trackname` LIKE '%$searchquestion%' OR
`album_name` LIKE '%$searchquestion%'
ORDER BY `popularity` DESC
LIMIT $startingpoint, $resultsperpage
我对以下内容感到困惑:
例如,用户可能会搜索Opening Philip Glass
。
在这种情况下,第一个单词是歌曲的名称,第二个和第三个单词是艺术家名称。
另一个例子:
如果我在空格上拆分查询,则会找到正确的轨道。但是,如果仅匹配其中一个单词的其他曲目具有更高的受欢迎程度,则会在实际精确匹配搜索查询的曲目之前返回。
我仍然希望对结果进行排序,使得与查询的较大部分匹配的内容立即位于顶部。我怎么能用SQL做到这一点?
我的应用程序是用PHP构建的,但我想在SQL中尽可能多地执行此操作,最好在尽可能少的查询中减少延迟。
任何帮助都将不胜感激。
答案 0 :(得分:4)
您可以为搜索结果中的每一列添加权重。
以下是代码:
SELECT *,
CASE WHEN `artist` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS artist_match,
CASE WHEN `genres` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS genres_match,
CASE WHEN `trackname` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS trackname_match,
CASE WHEN `album_name` LIKE '%$searchquestion%' THEN 1 ELSE 0 END AS album_name_match,
FROM p2pm_tracks
WHERE
`artist` LIKE '%$searchquestion%' OR
`genres` LIKE '%$searchquestion%' OR
`trackname` LIKE '%$searchquestion%' OR
`album_name` LIKE '%$searchquestion%'
ORDER BY
`artist_match` DESC,
`genres_match` DESC,
`trackname_match` DESC,
`album_name_match` DESC,
`popularity` DESC,
LIMIT $startingpoint, $resultsperpage
此查询将收集与以下内容相关的结果:
要优化此查询,您应避免使用“LIKE”并改为使用“FULLTEXT SEARCH”。
优化的代码将是:
SELECT *,
CASE WHEN MATCH (artist) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS artist_match,
CASE WHEN MATCH (genres) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS genres_match,
CASE WHEN MATCH (trackname) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS trackname_match,
CASE WHEN MATCH (album_name) AGAINST ('$searchquestion') THEN 1 ELSE 0 END AS album_name_match,
FROM p2pm_tracks
WHERE
MATCH (artist) AGAINST ('$searchquestion') OR
MATCH (genres) AGAINST ('$searchquestion') OR
MATCH (trackname) AGAINST ('$searchquestion') OR
MATCH (album_name) AGAINST ('$searchquestion')
ORDER BY
`artist_match` DESC,
`genres_match` DESC,
`trackname_match` DESC,
`album_name_match` DESC,
`popularity` DESC,
LIMIT $startingpoint, $resultsperpage
确保您使用MyISAM引擎作为MySQL表,并为您要搜索的列创建了索引。 MySQL表的代码应如下所示:
CREATE TABLE p2pm_tracks (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
artist VARCHAR(255) NOT NULL,
trackname VARCHAR(255) NOT NULL,
...
...
FULLTEXT (artist,trackname)
) ENGINE=MyISAM;
有关详情,请查看以下内容: - http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html - http://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html
如果您正在寻找更高级的东西,那么请查看Solr(基于Lucene),Sphinx,ElasticSearch(基于Lucene)等。
答案 1 :(得分:1)
MySQL在搜索文本方面不是很好:(
您可以尝试做的是查看全文搜索功能(http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html)
通过匹配功能,您可以获得可以订购的相关性。
SELECT p2pm_tracks。*, MATCH(艺术家,流派)反对('某些词')AS相关性, MATCH(艺术家)AGAINST('some words')AS artist_relevance
答案 2 :(得分:1)
请不要使用LIKE。这很慢。您可以在mysql中使用全文搜索,但无法确定哪个列更重要。
更好的解决方案是使用sphinx的mysql。
答案 3 :(得分:0)
嗯,为了匹配你的1.例子在SQL中很难,我不确定是否有函数。 你需要的是像php中的这个funktion
http://php.net/manual/function.similar-text.php
或者您只在每次平均投票中选择sql查询,并通过php和类似文本函数计算结果匹配的“好”。