Magento 网站中无法通过 SKU 搜索到产品的问题排查

文章目录

    今天遇到一个奇怪的 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 中有一个选项

    Magento Search Type

    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 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式