MySQL - 如何获得具有准确相关性的搜索结果

Bad*_*sie 7 php mysql sql search

我已多次重新审视这个问题,而且我从未真正找到合适的答案.

是否可以执行MySQL搜索,通过相关性返回ACTUAL准确排序的结果?

我正在尝试创建一个ajax搜索表单,它在用户输入到输入字段时提出建议,并且仅使用纯MySQL查询找不到合适的解决方案.我知道有可用的搜索服务器,例如ElasticSearch,我想知道如何只使用原始MySQL查询.


我有一张学校科目表.行数不到1200行,这永远不会改变.让我们执行一个基本的FULLTEXT搜索,用户开始输入"Bio".

查询("Bio ...") - FULLTEXT BOOLEAN MODE

SELECT name, MATCH(name) AGAINST('bio*' IN BOOLEAN MODE) AS relevance
FROM subjects
WHERE MATCH(name) AGAINST('bio*' IN BOOLEAN MODE)
ORDER BY relevance DESC
LIMIT 10
Run Code Online (Sandbox Code Playgroud)

结果

name                                        |  relevance
--------------------------------------------------------
Biomechanics, Biomaterials and Prosthetics  |  1
Applied Biology                             |  1
Behavioural Biology                         |  1
Cell Biology                                |  1
Applied Cell Biology                        |  1
Developmental/Reproductive Biology          |  1
Developmental Biology                       |  1
Reproductive Biology                        |  1
Environmental Biology                       |  1
Marine/Freshwater Biology                   |  1
Run Code Online (Sandbox Code Playgroud)

为了显示这些结果有多糟糕,这里是一个简单LIKE查询的比较,它显示了未显示的所有更相关的结果:

查询("生物......") - 喜欢

SELECT id, name
WHERE name LIKE 'bio%'
ORDER BY name
Run Code Online (Sandbox Code Playgroud)

结果

name                                        |  relevance
--------------------------------------------------------
Bio-organic Chemistry                       |  1
Biochemical Engineering                     |  1
Biodiversity                                |  1
Bioengineering                              |  1
Biogeography                                |  1
Biological Chemistry                        |  1
Biological Sciences                         |  1
Biology                                     |  1
Biomechanics, Biomaterials and Prosthetics  |  1
Biometry                                    |  1
Run Code Online (Sandbox Code Playgroud)

并且您已经看到有多少主题没有被建议,即使这些主题更可能是用户将要寻找的.

LIKE然而,使用的问题是如何搜索多个单词以及像单词一样的单词FULLTEXT.

我想要实现的基本顺序是:

  1. 首字以搜索词开头
  2. 以搜索词开头的第二个单词
  3. 术语不在单词开头的单词
  4. 如果没有进一步的相关性,一般都是字母顺序

所以我的问题是,如何通过跨多个单词的MySQL搜索为用户获取明智的排序建议列表?

Tho*_*ner 10

您可以使用字符串函数,例如:

select id, name
from subjects
where name like concat('%', @search, '%')
order by 
  name like concat(@search, '%') desc,
  ifnull(nullif(instr(name, concat(' ', @search)), 0), 99999),
  ifnull(nullif(instr(name, @search), 0), 99999),
  name;
Run Code Online (Sandbox Code Playgroud)

这将获取包含@search的所有条目.首先是那些在开始时拥有它的那些,然后是那些在空白之后拥有它,然后通过发生的位置,然后按字母顺序排列的那些.

name like concat(@search, '%') desc顺便使用MySQL的布尔逻辑.1 = true,0 = false,因此按顺序排序会先给出真实值.

SQL小提琴:http://sqlfiddle.com/#!9/c6321a/1


Jed*_*ate 5

对于其他登陆的人(就像我一样):根据我的经验,为了获得最佳效果,您可以根据搜索词的数量使用条件.如果只有一个单词使用LIKE'%word%',否则使用布尔全文搜索,如下所示:

if(sizeof($keywords) > 1){
   $query = "SELECT *,
             MATCH (col1) AGAINST ('+word1* +word2*' IN BOOLEAN MODE) 
             AS relevance1,
             MATCH (col2) AGAINST ('+word1* +word2*' IN BOOLEAN MODE) 
             AS relevance2
             FROM table1 c
             LEFT JOIN table2 p ON p.id = c.id
             WHERE MATCH(col1, col2) 
             AGAINST ('+word1* +word2*' IN BOOLEAN MODE) 
             HAVING (relevance1 + relevance2) > 0
             ORDER BY relevance1 DESC;";
    $execute_query = $this->conn->prepare($query);
}else{          
   $query = "SELECT * FROM table1_description c
             LEFT JOIN table2 p ON p.product_id = c.product_id
             WHERE colum1 LIKE ? AND column2 LIKE ?;";
        // sanitize
        $execute_query = $this->conn->prepare($query);
        $word=htmlspecialchars(strip_tags($keywords[0]));
        $word = "%{$word}%";
        $execute_query->bindParam(1, $word);
        $execute_query->bindParam(2, $word);
    }
Run Code Online (Sandbox Code Playgroud)

  • 小提示:我建议使用 [count()](http://php.net/manual/en/function.count.php) 而不是 `sizeof()`,这是一个很少使用的别名,并且具有在大多数其他编程语言中具有不同的含义。 (2认同)

fri*_*108 5

这是我使用上述答案组合可以获得的最佳结果:

$searchTerm = 'John';
// $searchTerm = 'John Smit';
if (substr_count($searchTerm, ' ') <= 1)
    $sql = "SELECT id, name
    FROM people
    WHERE name like '%{$searchTerm}%')
    ORDER BY
      name LIKE '{$searchTerm}%') DESC,
      ifnull(nullif(instr(name, ' {$searchTerm}'), 0), 99999),
      ifnull(nullif(instr(name, '{$searchTerm}'), 0), 99999),
      name
    LIMIT 10";
}
else {
$searchTerm = '+' . str_replace(' ', ' +', $searchTerm) . '*';
$sql = "SELECT id,name, MATCH(lead.name) AGAINST('{$searchTerm}' IN BOOLEAN MODE) AS SCORE
        FROM lead
    WHERE MATCH(lead.name) AGAINST('{$searchTerm}' IN BOOLEAN MODE)
    ORDER BY `SCORE` DESC
    LIMIT 10";
Run Code Online (Sandbox Code Playgroud)

确保在列上设置全文索引(如果您最终使用的是多列)并使用OPTIMIZE table_name.

最好的一点是,如果您输入Jo,那么拥有姓名的人的Jo排名将高于John您想要的姓名!