【问题标题】:How to sort and filter searches on multiple fields in SQL如何在 SQL 中对多个字段的搜索进行排序和过滤
【发布时间】:2015-03-15 13:30:14
【问题描述】:

我有一个包含音乐歌曲的 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

我在以下问题上苦苦挣扎:

  1. 用户搜索某些内容。我查看了所有领域:歌曲 titleartistalbumgenre。但是,通常某个搜索查询包含多个(部分)这些轨道。

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

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

另一个例子:

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

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

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

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

任何帮助将不胜感激。

【问题讨论】:

  • SQL 不是完成此任务的最佳方式。文本搜索引擎(例如 Solr Lucene)是一种更好的方法,特别是如果您允许像 opening philip glass 这样的搜索。一些 RDBMS(例如 SQL Server)确实内置了全文引擎,并且可能是合适的。
  • 另请注意,您的 MySQL 查询现在很容易受到这种方式的 SQL 注入攻击。总是逃避你的查询。
  • 您可以在服务器端使用 levenstein php.net/manual/en/function.levenshtein.php对其进行排序
  • 我很想给你一个答案,但我需要先处理一些 sql 转储,如果你可以发给我,我想我可以帮助你。
  • @Ruben:别担心,我会在将语句插入查询之前对其进行清理。我确实从中学到了:xkcd.com/327

标签: php sql database search search-engine


【解决方案1】:

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

代码如下:

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

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

  • 艺术家 FIRST,
  • 然后是类型,
  • 然后是曲目的标题,
  • 然后是专辑名称,
  • 那么这首歌的流行度

要优化此查询,您应该避免使用“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 表使用了 MyISAM 引擎,并为要搜索的列创建了索引。 您的 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)等。

【讨论】:

  • 谢谢!这有很大帮助。很高兴知道可以以这种方式对结果进行排序:-)
【解决方案2】:

MySQL 不擅长搜索文本 :(

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

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

    选择 p2pm_tracks.*, MATCH(艺术家,流派)反对('一些词')作为相关性, MATCH(艺术家)反对('一些词')作为艺术家相关性

【讨论】:

    【解决方案3】:

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

    更好的解决方案是使用 sphinx 的 mysql。

    【讨论】:

      【解决方案4】:

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

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

      或者你只在你的 sql 查询中选择平均投票,然后通过 php 和相似文本函数计算结果匹配的“好”程度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-22
        • 2015-10-06
        • 2015-12-02
        • 1970-01-01
        • 2016-01-07
        • 1970-01-01
        • 2021-05-06
        • 2011-07-29
        相关资源
        最近更新 更多