从 v1.15 之前的版本升级上来、索引里本来就存着中文数据的话,升级后如果不重建索引(reindex),中文查询和中文文档会被无视——搜索命中为空或明显偏少,也不报错。原因不是升级坏了,是 v1.15 换了 Charabia 的中文分词策略,旧索引里的 token 还是旧版本切出来的,跟新查询对不上。触发一次 reindex 就恢复。这条只对「从 v1.15 之前升级上来、库里已有中文」的实例成立;全新安装 v1.54.3 中文开箱可用,没有这个问题。
Issue & Env(案发现场与环境)
- 触发场景:实例原本跑在 v1.15 之前的版本(如 v1.14 及更早),索引里已有中文数据。用 dumpless upgrade 之类的方式升级到 v1.15+ 之后,之前能搜到的中文词突然搜不到,或者命中数量骤减。
- 环境:Meilisearch v1.15 及以上(本文背景实例升级到 v1.54.3)。跟 master key、索引 uid、有没有加
filter都无关。 - 适用边界:只有「先有中文数据 → 再升级到 v1.15+」这一条路径会中招。全新空库、之后才灌中文文档的 v1.54.3 实例,中文分词是开箱就对的(本地实跑 v1.54.3,搜「三体」直接命中 id 1)。
- 关键区分:它不是报错,没有 4xx,没有异常堆栈。搜索请求正常返回 200,只是结果不对——中文部分像是没进过索引。
StackTrace(堆栈日志)
这一条是官方说明型问题,没有报错文本。官方 v1.15 release notes 里的原文提示就是判断依据:
We’ve enhanced the Charabia tokenizer to provide more precise segmentation of Chinese text. If your dataset contains Chinese-language content, you must reindex your database. Otherwise, Chinese queries and documents will not be processed correctly and may be ignored during search.
(来源:Meilisearch 1.15 release notes)
对应的现象是搜索返回 200 但命中为空或偏少。比如重建前搜一个中文词,返回类似:
{
"hits": [],
"query": "三体",
"processingTimeMs": 0,
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
这里贴的是「中文被忽略」时 search 响应的形态(命中为空),不是报错 JSON——它不是错误,Meilisearch 不会为此返回错误码。要确认,请看下一节的判断方法。
Reproduce(复现步骤)
在升级后的实例上按顺序确认:
# 1. 确认当前版本 ≥ v1.15
curl -s http://localhost:7700/version \
-H 'Authorization: Bearer aSampleMasterKey'
# 2. 搜一个库里的中文词,观察 estimatedTotalHits
curl -s -X POST http://localhost:7700/indexes/books_zh/search \
-H 'Authorization: Bearer aSampleMasterKey' \
-H 'Content-Type: application/json' \
-d '{"q":"三体"}'
# 3. 查看该索引 localizedAttributes 是否为 null(未声明语言)
curl -s http://localhost:7700/indexes/books_zh/settings/localized-attributes \
-H 'Authorization: Bearer aSampleMasterKey'
如果版本 ≥ v1.15、数据在升级前就存在、中文词命中为空或偏少,基本可以判定是旧索引没重建。
Root Cause(根因分析)
v1.15 换了中文分词策略
Meilisearch 的分词由 Charabia 负责。v1.15 增强了它对中文的切分精度(对应 GitHub release 里更新 charabia 的动作)。分词结果在索引阶段就写进了倒排索引——文档里的每个 token、它的位置信息都落盘了。
旧索引里的 token 是旧分词器切的
升级 Meilisearch 二进制不会自动重切已经索引好的文档。旧索引里存的是老版本 Charabia 切出来的中文 token;升级后查询侧用的是新版本分词逻辑,两边对不上,中文部分自然匹配不到。这不是数据丢了,是索引里的 token 过期了。
什么时候必须重建
官方给的判定很直接:只要数据集含中文内容,升级到 v1.15 后就得重建索引。官方同时给出了三种「触发重建」的方式,任选其一即可(它们都是会重索引全部文档的设置变更):
- 把中文 locale 加进
localizedAttributes(例如cmn); - 改动 stop words 或自定义
dictionary; - 刷新
searchableAttributes——先把某个属性移出列表,等移除任务完成后再加回来。
The Fix(解决方案)
方式一:加中文 locale 触发重建
curl -X PUT 'http://localhost:7700/indexes/books_zh/settings/localized-attributes' \
-H 'Authorization: Bearer aSampleMasterKey' \
-H 'Content-Type: application/json' \
-d '[{"locales":["cmn"],"attributePatterns":["*_zh"]}]'
返回 {"taskUid":...,"type":"settingsUpdate"},这是异步任务,会重建该索引全部文档。
方式二:改动 dictionary 或 stop words 触发重建
对 dictionary 或 stopWords 做一次实际变更(哪怕加一个词)同样会触发重索引:
curl -X PUT 'http://localhost:7700/indexes/books_zh/settings/dictionary' \
-H 'Authorization: Bearer aSampleMasterKey' \
-H 'Content-Type: application/json' \
-d '["未来科技"]'
方式三:dump 恢复
用 dump 导出再导入到新版本,也能在建索引时用新分词器重建全部数据。官方把 dump 列为重建索引的推荐方式之一。
别忘了等任务完成
以上方式返回的都是 taskUid,要轮询到 succeeded 才算重建完:
curl -s http://localhost:7700/tasks/<taskUid> \
-H 'Authorization: Bearer aSampleMasterKey'
任务跑完再搜,中文恢复命中。
边界提醒
- 如果你是从 v1.15 之前升级上来的,重建一次就够,之后正常用。
- 全新安装 v1.54.3、之后再灌中文数据的实例不需要做这些,中文本来就可用。
- 重建会重新索引该索引的全部文档,数据量大时耗时较长,安排在低峰期做。
References(参考来源)
- Meilisearch 1.15 release notes — Meilisearch Blogmeilisearch-docs
- Meilisearch v1.15.0 — GitHub Releasegithub-release
- Settings — Meilisearch 官方文档meilisearch-docs
