mysql - 全文搜索 Innodb 失败,MyIsam 返回结果
问题描述
我已经将一张桌子从 升级myisam
到 ,innodb
但性能不一样。当应该有某种关系时innodb
返回一个分数。0
该myisam
表返回相同术语的匹配项(我保留了旧表的副本,因此我仍然可以运行相同的查询)。
SELECT MATCH (COLUMNS) AGAINST ('+"Term Ex"' IN BOOLEAN MODE) as score
FROM table_myisam
where id = 1;
回报:
+-------+
| score |
+-------+
| 1 |
+-------+
但:
SELECT MATCH (COLUMNS) AGAINST ('+"Term Ex"' IN BOOLEAN MODE) as score
FROM table
where id = 1;
返回:
+-------+
| score |
+-------+
| 0 |
+-------+
我认为ex
可能没有被索引,因为innodb_ft_min_token_size
设置为3
. 我将其降低1
并优化了表格,但这没有影响。列内容的长度为 99 个字符,因此我假设整个列没有被索引,因为innodb_ft_max_token_size
. 我也增加了它并150
再次运行优化但再次得到相同的结果。
这些表之间的唯一区别是引擎和字符集。这张桌子正在使用utf8
,这张桌子myisam
正在使用latin1
。
有没有人看到这些行为,或者对如何解决它有建议?
更新:
我添加ft_stopword_file=""
到我的my.cnf
并OPTIMIZE TABLE table
再次运行。这次我得到了
优化 | 注意 | 表不支持优化,改为重新创建+分析
查询在此更改后有效。Ex
虽然不是停用词,但不确定为什么会有所作为。
一个失败的新查询是:
SELECT MATCH (Columns) AGAINST ('+Term +Ex +in' IN BOOLEAN MODE) as score FROM Table where id = 1;
+-------+
| score |
+-------+
| 0 |
+-------+
这in
导致失败,但这是我表中的下一个词。
SELECT MATCH (Columns) AGAINST ('+Term +Ex' IN BOOLEAN MODE) as score FROM Table where id = 1;
+--------------------+
| score |
+--------------------+
| 219.30206298828125 |
+--------------------+
我也试过了CREATE TABLE my_stopwords(value VARCHAR(30)) ENGINE = INNODB;
,然后更新my.cnf
了innodb_ft_server_stopword_table='db/my_stopwords'
。我重新启动并运行:
show variables like 'innodb_ft_server_stopword_table';
这带回了:
+---------------------------------+---------------------------+
| Variable_name | Value |
+---------------------------------+---------------------------+
| innodb_ft_server_stopword_table | 'db/my_stopwords'; |
+---------------------------------+---------------------------+
所以我认为in
现在不会导致查询失败,但它会继续。我也OPTIMIZE TABLE table
再试了一次,甚至ALTER TABLE table DROP INDEX ...
都ALTER TABLE table ADD FULLTEXT KEY ...
没有影响。
第二次更新 问题在于停用词。
$userinput = preg_replace('/\b(a|about|an|are|as|at|be|by|com|de|en|for|from|how|i|in|is|it|la|of|on|or|that|the|this|to|was|what|when|where|who|will|with|und|the|www)\b/', '', $userinput);
解决了这个问题,但这对我来说似乎不是一个好的解决方案。我想要一个避免在 mysql 中出现停用词的解决方案。
停用词表数据:
CREATE TABLE `my_stopwords` (
`value` varchar(30) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
和
Name: my_stopwords
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2019-04-09 17:39:55
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
解决方案
MyISAM 的 FULLTEXT 和 InnoDB 之间有几个不同之处。我认为您被“短”词和/或停用词的处理所吸引。MyISAM 将显示行,但 InnoDB 将失败。
我在使用 FT 时(以及在切换到 InnoDB 之后)所做的是过滤用户的输入以避免简短的单词。这需要额外的努力,但可以让我得到想要的行。我的情况略有不同,因为结果查询是这样的。请注意,我已经添加+
了要求单词,但不是短于 3 的单词(我ft_min_token_size
的是 3)。这些搜索是针对build a table
和build the table
:
WHERE match(description) AGAINST('+build* a +table*' IN BOOLEAN MODE)
WHERE match(description) AGAINST('+build* +the* +table*' IN BOOLEAN MODE)
(尾随*
可能是多余的;我没有对此进行调查。)
另一种方法
由于 FT 在非短、非停用词方面非常有效,因此分两个阶段进行搜索,每个阶段都是可选的:要搜索“长词”,请执行
WHERE MATCH(d) AGAINST ('+long +word' IN BOOLEAN MODE)
AND d REGEXP '[[:<:]]a[[:>:]]'
第一部分通过查找“long”和“word”(作为words)快速减少可能的行。第二部分确保字符串中也有一个单词 a
。这REGEXP
是昂贵的,但只会应用于通过第一次测试的那些行。
只搜索“长词”:
WHERE MATCH(d) AGAINST ('+long +word' IN BOOLEAN MODE)
只搜索单词“a”:
WHERE d REGEXP '[[:<:]]a[[:>:]]'
警告:这种情况会很慢。
注意:我的示例允许单词按任何顺序排列,并且位于字符串中的任何位置。也就是说,这个字符串在我所有的例子中都会匹配:“她想从他那里得到一句话。”
推荐阅读
- r - 在进行 PCA(主成分分析)时,数据必须有多“相似/兼容”?
- c# - 使用 VS Code 手动设置 .NET Framework 项目
- r - 使用ggplot2覆盖密度图的一般规则
- ios - iOS:如何从包含字符串和图像的数据中获取特定字符串?
- sql - 从 MS SQL 2012 odbc 连接读取表时描述符索引无效
- javascript - Vue Chart.js - 无法将返回数据用于图表数据集
- vb.net - 使用对象触发 MouseMove 事件的问题(VS 2012)
- reactjs - 在 React-Redux 应用程序中显示和管理错误消息的最佳实践
- r - 在R中获取html网站时如何保存for循环的结果?
- python - 取没有 NaN 的数据帧的最后 n 行