今天遇到一个奇怪的 Magento 网站的搜索问题。折腾了好久,终于找到了解决方案。记录一下排查过程和解决方法,以备后续参考。
问题现象
例如,一个产品的名称是:
World Best Programming Language GO-JS-PHP
产品的 SKU 是 GO-JS-PHP
可以在网站搜索中输入 Best Programming 搜索到该产品,获取其他任意在标题中的词语都可以搜索到该产品。
但是,如果输入 SKU GO-JS-PHP 进行搜索,却无法搜索到该产品。
即便,删除该产品,重新创建并保存,也是上面一样的问题。
☀️ 遇事不决问 AI
遇到这种问题,第一时间想到的是问问 AI。问了豆包,给出的答案很模糊,也只是一个大致的排查范围。
而使用 DeepSeek 则精准定位到了问题。
Magento/MySQL 默认的最小搜索词长度限制
由于这是一个低版本的 Magento,1.7 版本,所以并没有使用 Elasticsearch 作为搜索引擎。 而是使用了 MySQL 作为搜索引擎。(到服务器上确认了一下,也确实没有 Elasticsearch 进程)
Magento(在使用 MySQL 作为搜索引擎时)依赖于 MySQL 的 FULLTEXT 索引。
MySQL 有一个配置项 innodb_ft_min_token_size (InnoDB 引擎) 或 ft_min_word_len (MyISAM 引擎),它定义了索引和搜索时会被考虑的最小词长度。
默认值通常是 4。这意味着任何长度小于 4 个字符的词(例如 GO (2字符), PHP (3字符), JS (2字符))会被 MySQL 的全文索引完全忽略。
查看 MySQL 引擎
> mysql --version
mysql Ver 14.14 Distrib 5.6.44, for Linux (x86_64) using EditLine wrapper
进入 MySQL Console,查看当前的引擎:
mysql> SHOW TABLE STATUS LIKE 'catalogsearch_fulltext';
| Name | Engine | ...
| catalogsearch_fulltext | MyISAM | ...
对应的需要检查 MyISAM 引擎的配置项 ft_min_word_len
:
mysql> SHOW VARIABLES LIKE 'ft_min_word_len';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| ft_min_word_len | 4 |
+-----------------+-------+
果然,ft_min_word_len 的值是 4。这就解释了为什么 SKU GO-JS-PHP 无法被搜索到,因为它的每个部分(GO, JS, PHP)都小于 4 个字符,导致 MySQL 在全文索引中忽略了这些词。
而要修改 - 不触发分词,这个除非修改 MySQL 源码,或者修改 Magento 的 PHP 代码来实现。不合适,太麻烦了。
MySQL 修改设置
/etc/my.cnf
ft_min_word_len = 3
然后重启 MySQL 服务:
/etc/init.d/mysql restart
Magento 重建搜索索引
修改 MySQL 的配置后,需要重建 Magento 的搜索索引,以便新的设置生效。
但是,不知道这个系统为何在重建索引时会报错,System -> Index Management 中的 Catalog Search Indexer 报错。
所以,我换了个策略,直接把对应的产品修改,再保存,触发索引重建。果然这样就能搜索到了。
但是,如果 - 分割的每一部分都是两个字符的词(例如 GO-JS-OC),则仍然无法搜索到。即便设置了
ft_min_word_len = 2
我没有找到原因。
换个思路不用 MySQL 的全文索引
Magento 后台的 System -> Configuration -> Catalog -> Catalog Search 中有一个选项
Search Type 有三个选项:
- Like
- Fulltext
- Combine (Like and Fulltext)
当前值是 Fulltext,所以,何不直接改成 Like。
毕竟这个网站只有几千个产品,理论上使用 LIKE 查询性能也不会太差,且可以避免 MySQL 的全文索引限制。 改成 Like 之后,果然就能搜索出来 GO-JS-OC 这样的 SKU 了。
而且在输入多个词时,Magento 会自动将它们拆分成多个单词进行 LIKE 查询,这样就能搜索到包含任意单词的产品。
好了,完美解决了问题。
数据库错误
在切换 Search Type 的时候,Magento 搜索报错了:
SQLSTATE[HY000]: General error: 145 Table './catalogsearch_fulltext' is marked as crashed and should be repaired
把我吓坏了,第一次遇到这么恐怖的错误。猜测是之前的索引重建过程还没结束,我就重启了 MySQL 服务,导致索引表损坏? 不确定啊。。。
mysql> check table catalogsearch_fulltext;
+---------------------------------+-------+----------+----------------------------+
| Table | Op | Msg_type | Msg_text |
+---------------------------------+-------+----------+----------------------------+
| catalogsearch_fulltext | check | warning | Table is marked as crashed |
| catalogsearch_fulltext | check | error | Found 1044 keys of 1046 |
| catalogsearch_fulltext | check | error | Corrupt |
+---------------------------------+-------+----------+----------------------------+
3 rows in set (0.04 sec)
mysql> repair table catalogsearch_fulltext;
+---------------------------------+--------+----------+-----------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+---------------------------------+--------+----------+-----------------------------------------------------------+
| catalogsearch_fulltext | repair | warning | Duplicate key for record at 37128 against record at 34220 |
| catalogsearch_fulltext | repair | warning | Number of rows changed from 1046 to 1045 |
| catalogsearch_fulltext | repair | status | OK |
+---------------------------------+--------+----------+-----------------------------------------------------------+
3 rows in set (0.46 sec)
好在可以使用 :
repair table catalogsearch_fulltext
一键修复!差点提桶跑路 😅
据说 InnoDB 一般不需要手动修复,因为它会自动处理崩溃恢复,但 MyISAM 引擎就需要手动修复了。
维护这些历史遗留系统,真是个挑战啊!
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式