MySQL 布尔模式下的全文:搜索字符串中包含“+”的关键字
MySQL FullText in Boolean mode: searching keywords that contain '+' as part of the string
我看了十几个 'similar' 问题,但没有运气。我明白 +
在 BOOLEAN 模式下附加到 FULLTEXT 中的关键字具有特殊含义,
但是,如果我们的关键字实际上包含 +
符号作为 text/string 的后缀部分会怎样?我们怎样才能仍然使用全文搜索并获得正确的结果?
数据库结构
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 查询实际上 returned 和排序结果在这种情况下更好。我也尝试过使用引号进行完全匹配,结果相同。添加 'special' 个字符,如 'test\+' 也无济于事。虽然 FT 结果并非毫无用处,但还不够完美,因为顺序不是我期望的那样。
问题
是否真的可以使用 FULLTEXT 模式实现与 return 相同的结果?如果是,怎么做?
谢谢!
如果您将列定义为使用将字符视为普通字母而非标点符号的排序规则,则只能索引标点符号。
有一个手册页显示了执行此操作的步骤: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 查询,这就没有意义了。
MySQL 全文搜索不识别特殊字符。它旨在仅搜索单词字符,+
不是。
如果你想过滤特殊字符,LIKE
就是你所需要的。
此外,对于 InnoDB,+
符号在 仅位于 之前而不是之后具有特殊含义。因此,您的查询实际上等同于 :
MATCH(`i_desc`) AGAINST ('"test"' IN BOOLEAN MODE)
我看了十几个 'similar' 问题,但没有运气。我明白 +
在 BOOLEAN 模式下附加到 FULLTEXT 中的关键字具有特殊含义,
但是,如果我们的关键字实际上包含 +
符号作为 text/string 的后缀部分会怎样?我们怎样才能仍然使用全文搜索并获得正确的结果?
数据库结构
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 查询实际上 returned 和排序结果在这种情况下更好。我也尝试过使用引号进行完全匹配,结果相同。添加 'special' 个字符,如 'test\+' 也无济于事。虽然 FT 结果并非毫无用处,但还不够完美,因为顺序不是我期望的那样。
问题
是否真的可以使用 FULLTEXT 模式实现与 return 相同的结果?如果是,怎么做?
谢谢!
如果您将列定义为使用将字符视为普通字母而非标点符号的排序规则,则只能索引标点符号。
有一个手册页显示了执行此操作的步骤: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 查询,这就没有意义了。
MySQL 全文搜索不识别特殊字符。它旨在仅搜索单词字符,+
不是。
如果你想过滤特殊字符,LIKE
就是你所需要的。
此外,对于 InnoDB,+
符号在 仅位于 之前而不是之后具有特殊含义。因此,您的查询实际上等同于 :
MATCH(`i_desc`) AGAINST ('"test"' IN BOOLEAN MODE)