如何获得准确相关的搜索结果

我多次重新讨论这个问题,而且我从未真正找到过正确的答案。

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

我正在尝试创建一个Ajax搜索表单,它可以在用户键入输入字段时提供建议,并且仅使用纯粹的MySQL查询找不到像样的解决方案。 我知道有可用的搜索服务器,例如ElasticSearch,我想知道如何使用原始MySQL查询。


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

查询(“Bio ...”) - FULLTEXT布尔模式

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

结果

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

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

查询(“Bio ...”) - LIKE

SELECT id, name
WHERE name LIKE 'bio%'
ORDER BY name

结果

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

而且,您已经看到有多少主题没有被建议,尽管这些更可能是用户所期待的。

但是,使用LIKE的问题是如何在多个单词中进行搜索,并且在像FULLTEXT这样的单词中间进行搜索。

我想要实现的基本顺序如下所示:

  • 从搜索词开始的第一句话
  • 从搜索词开始的第二个词
  • 单词不在单词的开头
  • 如果没有进一步的相关性,一切通常按字母顺序排列

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


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

    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;
    

    这会让你包含@search的所有条目。 首先是那些在一开始就有的,然后是那些在空白之后有它,然后是事件的位置,然后是字母的那些。

    name like concat(@search, '%') desc通过这种方式使用了MySQL的布尔逻辑。 1 =真,0 =假,所以排序这下降让你真正的第一。

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


    对于其他人登陆(就像我做的那样):以我的经验,为了获得最佳结果,您可以根据搜索词的数量使用条件。 如果只有一个词使用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);
        }
    

    我根据你描述的顺序尝试了这个。

    SET @src := 'bio';
    SELECT name,
    name LIKE (CONCAT(@src,'%')),
             LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(name,' ',2),' ',-1),LENGTH(@src)) = @src,
             name LIKE (CONCAT('%',@src,'%'))
    FROM subjects
    ORDER BY name LIKE (CONCAT(@src,'%')) DESC,
             LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(name,' ',2),' ',-1),LENGTH(@src)) = @src DESC,
             name LIKE (CONCAT('%',@src,'%')) DESC,
             name
    

    http://sqlfiddle.com/#!9/6bffa/1

    我想也许你甚至可能想要包括@src的出现次数在VARCHAR字段中计算字符串出现的次数?

    链接地址: http://www.djcxy.com/p/75309.html

    上一篇: How to get search results with accurate relevance

    下一篇: Fail to get all usernames from table