【问题标题】:MySQL MATCH() AGAINST() FULLTEXT Index - Achieve Partial String Match Combined with Phrase MatchMySQL MATCH() AGAINST() FULLTEXT Index - 结合短语匹配实现部分字符串匹配
【发布时间】:2020-10-31 17:22:07
【问题描述】:

我有一个表,其列 content 具有 FULLTEXT 索引

我想利用 MATCH() 处理大文本的速度。

我希望搜索尽可能准确。

当我以这种方式搜索短语字符串“large truck”时:

SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck"' IN BOOLEAN MODE);

遗漏了一些实例。

我的表:

|   content    |
----------------
|Large \n truck| FOUND ✓
----------------
|large truck   | FOUND ✓
----------------
|large trucks  | *PLURAL MISSED!
----------------
|large truckl  | *TYPE-O MISSED!

如果我使用标准的 LIKE / 通配符 方法:

SELECT * FROM  `MyTable` WHERE  `content` LIKE  '%large truck%'

我的表:

|   content    |
----------------
|Large \n truck| *MISSED!
----------------
|large truck   | FOUND ✓
----------------
|large trucks  | FOUND ✓
----------------
|large truckl  | FOUND ✓

看来我也不能将 PHRASE 搜索与通配符一起使用:

SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck*"' IN BOOLEAN MODE); **DOES NOT WORK**

SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck"*' IN BOOLEAN MODE); **DOES NOT WORK**

所以...

如何成功使用 MATCH() AGAINST() 搜索短语,并返回所有实例 - 甚至 不区分大小写的部分字符串匹配?

【问题讨论】:

    标签: mysql string match match-against against


    【解决方案1】:

    这是一个使用 REGEXP 的快速破解,但它没有解决问题,因为它不使用全文索引:

    SELECT * 
    FROM MyTable 
    WHERE content REGEXP("large[[:space:]]+truck*");
    

    当然你也可以通过不使用精确词组的方式搜索来使用 FT 索引:

    SELECT * 
    FROM MyTable 
    WHERE MATCH(content) AGAINST('+large +truck*' IN BOOLEAN MODE);
    

    但这最终会包括您不想要的记录,因为它与精确短语搜索不同。

    不幸的是,无论您使用 InnoDB 还是 MyISAM,短语搜索(双引号 - “”)和截断运算符(通配符 - *)都不起作用。 does not work with the distance operator 也带有 InnoDB(可能来自同一来源)。我想这与全文索引的数据如何存储在本质上有关。

    【讨论】:

      【解决方案2】:

      我经常使用 FT 的技巧是分两步完成:

      1. 做一个MATCH,希望得到所有想要的文本,但可能会有一些额外的结果。
      2. AND 与另一个条件 - LIKE(更快)或REGEXP(更强大)。

      MATCH 会因为 FT 而变快;另一部分将第二个执行,所以它会很快,因为要检查的行不多。

      这符合您的条件:

      SELECT * FROM MyTable
          WHERE MATCH(content) AGAINST('+large +truck*' IN BOOLEAN MODE)
            AND content REGEXP "large[[:space:]]+truck";
      

      换个说法,查询将运行如下:

      1. 假设表有 10K 行。
      2. 将评估 FT 表达式。 MATCH 会非常快(因为它的设计方式)。它会在content 的任何位置找到所有带有“large”和“truck*”的行。现在,假设有 30 行满足这一要求。
      3. 评估WHERE 的其余部分。但它只针对那 30 行。因此,尽管REGEXP 的成本很高,但并不经常这样做。
      4. 然后可能返回 14 行。

      最终结果是整个查询“快速”运行,这是您的要求之一。

      注意:我需要第二部分来防止这些

      large green truck
      the truck is large
      

      根据版本,您可能需要此 REGEXP:"large\\s+truck"

      【讨论】:

      • 谢谢。我试图理解“另一部分将第二个执行,所以它会很快,因为没有多少行要检查”的逻辑。为什么“其他人会更快”?我的印象是 MATCH() 将是 FULLTEXT 索引上最快的方法。出于这个原因,我不再使用 LIKE。现在使用 LIKE 和 MATCH 的组合 - 似乎它会使我的时间加倍?在 MATCH 之后执行 LIKE 是否有条件使 LIKE 更快?谢谢。只是想理解。
      • @Stnfordly - 我添加了一个改写。是的,添加 REGEXP 所需的时间可能是 FT 部分的两倍。但它只有两倍长。只做正则表达式可能会慢 100 倍。只做 FT 会给你的行太少(见你的问题)或太多的行(根据我的版本)。 (我之所以选择 REGEXP,是因为我没有找到对这种特殊情况有用的 LIKE。)
      • 嗨。谢谢。您是说您的查询示例将首先执行 MATCH(),然后仅对它在 MATCH() 中找到的内容执行 REGEX?
      • 我要试试这个 - 但正则表达式不会找不到“|Large \n truck|”实例?
      • @Stnfordly - 如果\n 确实是回车,那么它被视为“空格”(又名空格);如果它是两个字符(反斜杠和 n),那么事情会变得更加混乱。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 2013-10-15
      • 2021-10-03
      • 2019-07-25
      • 1970-01-01
      相关资源
      最近更新 更多