【问题标题】:MySQL FullText in Boolean mode: searching keywords that contain '+' as part of the string布尔模式下的 MySQL FullText:搜索包含“+”作为字符串一部分的关键字
【发布时间】:2019-02-22 00:23:12
【问题描述】:

我已经看了十几个“类似”的问题,但没有运气。我了解+在BOOLEAN模式下附加到FULLTEXT中的关键字有特殊含义, 但是,如果我们的关键字实际上包含 + 符号作为文本/字符串的后缀部分怎么办。我们怎样才能仍然使用 FULL-TEXT 搜索并获得正确的结果?

数据库结构

CREATE TABLE `ft_test` (
  `i_id` int(11) NOT NULL,
  `i_desc` mediumtext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

ALTER TABLE `ft_test`
  ADD PRIMARY KEY (`i_id`) USING BTREE;
ALTER TABLE `ft_test` ADD FULLTEXT KEY `i_desc` (`i_desc`);

ALTER TABLE `ft_test`
  MODIFY `i_id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;

数据库数据

SELECT * FROM ft_test;
+------+-----------+
| i_id | i_desc    |
+------+-----------+
|    1 | test      |
|    2 | test+     |
|    3 | test++    |
|    4 | test +    |
|    5 | test plus |
+------+-----------+

测试#1:喜欢查询

SELECT * FROM ft_test WHERE i_desc LIKE 'test+%';
+------+--------+
| i_id | i_desc |
+------+--------+
|    2 | test+  |
|    3 | test++ |
+------+--------+

测试 #2:全文查询

SELECT *, MATCH(`i_desc`) AGAINST ('"test+"' IN BOOLEAN MODE) AS RELEVANCE
    -> FROM `ft_test`
    -> WHERE MATCH(`i_desc`) AGAINST ('"test+"' IN BOOLEAN MODE)
    -> ORDER BY RELEVANCE;

+------+-----------+-----------+
| i_id | i_desc    | RELEVANCE |
+------+-----------+-----------+
|    1 | test      |         1 |
|    2 | test+     |         1 |
|    3 | test++    |         1 |
|    4 | test +    |         1 |
|    5 | test plus |         1 |
+------+-----------+-----------+

如您所见,在这种情况下,LIKE 查询实际上返回并更好地排序了结果。我也尝试过使用引号进行完全匹配,结果相同。添加像“test\+”这样的“特殊”字符也无济于事。虽然 FT 结果并非毫无用处,但它们并不完美,因为排序不是我所期望的。

问题

真的有可能实现这一点并返回与使用 FULLTEXT 模式的 LIKE 相同的结果吗?如果是,怎么做?

谢谢!

【问题讨论】:

  • 如果不需要运算符,为什么要使用布尔模式?
  • 它是脚本的一部分,硬编码。
  • 我不确定 + 是否被视为单词的一部分。我猜它是一个单词分隔符,因此被排除在全文索引之外并在搜索中被忽略。

标签: mysql sql full-text-search mariadb


【解决方案1】:

如果您将列定义为使用将字符视为普通字母而非标点符号的排序规则,则只能索引标点符号字符。

有一个手册页显示了执行此操作的步骤:https://dev.mysql.com/doc/refman/8.0/en/full-text-adding-collation.html

但是由于您说您的脚本是硬编码的,我想您无权重新定义您正在搜索的列的排序规则,或者在安装自定义排序规则定义后重新启动 MySQL 服务器。

一种解决方法是搜索没有标点符号的单词,然后在找到匹配的单词后添加要应用的条件。

SELECT *, MATCH(`i_desc`) AGAINST ('"test"' IN BOOLEAN MODE) AS RELEVANCE
FROM `ft_test`
WHERE MATCH(`i_desc`) AGAINST ('"test"' IN BOOLEAN MODE)
 AND i_desc LIKE 'test+%';
ORDER BY RELEVANCE;

它将使用全文索引来查找与单词匹配的行,然后另一个条件项将针对包含+ 的字符串的那些行(希望很小)进行过滤。

但同样,如果您无权更改 SQL 查询,那就没有实际意义了。

【讨论】:

  • 谢谢比尔,作为答案被接受。当然,我可以更改源代码,但如果不是真的需要,我会避免这样做。
【解决方案2】:

MySQL 全文搜索不识别特殊字符。它仅用于搜索单词字符,+ 不是。

如果您想过滤特殊字符,LIKE 就是您所需要的。

此外,在 InnoDB 中,+ 符号在仅放置在单词之前,而不是之后放置时具有特殊含义。因此,您的查询实际上等同于:

MATCH(`i_desc`) AGAINST ('"test"' IN BOOLEAN MODE)

【讨论】:

  • 谢谢。我知道关于 InnoDB 的那部分,这就是它的 MyISAM 表的原因,是的,通过比较并获得与最后没有任何特殊字符的结果相同的结果来计算这部分。切换到 LIKE 的“问题”是它必须以某种方式从前端输入中管理(取决于查询是否包含+,这是逻辑串联还是单词的一部分?),并且切换使搜索变得相当复杂。我接受了上面比尔的回答,因为它恰到好处。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 2023-02-02
  • 1970-01-01
  • 2012-07-16
  • 2011-05-25
  • 1970-01-01
  • 2021-07-09
相关资源
最近更新 更多