如何对 SQL 中多个字段的搜索进行排序和过滤

How to sort and filter searches on multiple fields in SQL

我有一个包含音乐歌曲的 SQL 数据库。每首歌当然都有艺术家、专辑和流派。他们还有一个通用的 'popularity' 计数器,它是从外部来源获得的。但是,我也想为用户提供对歌曲进行投票的机会。最后,搜索结果应该根据这个受欢迎程度以及原始查询结果的准确性进行排序。

我目前使用的查询如下:

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

我遇到以下问题:

  1. 用户搜索内容。我查看了所有领域:歌曲 标题艺术家专辑流派。但是,通常某个搜索查询包含(部分)多个这些曲目。

例如,用户可能会搜索 Opening Philip Glass

在这种情况下,第一个词是歌曲名称,第二个和第三个词是艺术家姓名

另一个例子:

如果我在空格上拆分查询,则会找到正确的曲目。但是,如果仅匹配其中一个词的另一首曲目具有更高的流行度,则它将在实际准确匹配搜索查询的曲目之前返回。

我仍然希望以一种方式对结果进行排序,即同时匹配查询的较大部分的内容位于顶部。我怎样才能使用 SQL?

  1. 我有静态的人气,想创造一个新的人气。因此,我想使用某个轨道上所有投票的平均值(这些投票存储在另一个 table 中),除非还没有投票的情况。 我如何构建执行此操作的 SQL 查询?

我的应用程序是在 PHP 中构建的,但我想在 SQL 中尽可能多地执行此操作,最好是在尽可能少的查询中减少延迟。

如有任何帮助,我们将不胜感激。

嗯,在 SQL 中很难匹配您的 1. 示例,我不确定是否有函数。 你需要的是 php

中的类似功能

http://php.net/manual/function.similar-text.php

或者您 select 在您的 sql 中仅查询每个平均投票并计算 "good" 结果如何通过 php 和相似文本函数匹配。

MySQL 不太适合搜索文本:(

  1. 您可以尝试查看全文搜索功能 (http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html)

  2. 通过匹配功能,您可以获得可以订购的相关性。

    SELECTp2pm_tracks.*, MATCH (artist, genres) A​​GAINST ('some words') 作为相关性, MATCH (艺术家) AGAINST ('some words') AS artist_relevance

请不要使用 LIKE。这很慢。您可以在 mysql 中使用全文搜索,但您无法确定哪一列更重要。

更好的解决方案是 mysql 使用狮身人面像。

您可以为搜索结果中的每一列添加权重。

代码如下:

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

此查询将收集与以下相关的结果:

  • 艺术家第一,
  • 然后是流派,
  • 然后是曲目的标题,
  • THEN 专辑名称,
  • THEN 这首歌的流行度

要优化此查询,您应该避免 使用 "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

并确保您正在为 MySQL table 使用 MyISAM 引擎,并且您为要搜索的列创建了索引。 MySQL table 的代码应如下所示:

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)等