添加文档后立即搜索返回空结果,不是文档没加成功,是异步任务还没跑完。Meilisearch 的文档添加是异步操作,POST 返回的
taskUid只表示任务入队,文档尚未被索引。必须轮询GET /tasks/{taskUid}直到status变为succeeded,文档才可搜索。适用 Meilisearch 全版本。
Issue & Env(案发现场与环境)
- 业务场景:通过
POST /indexes/{uid}/documents添加了一批文档,API 返回了taskUid,紧接着调用POST /indexes/{uid}/search搜索,返回hits为空数组或estimatedTotalHits为 0。 - 环境:Meilisearch v1.54.3,curl / JS SDK / Python SDK 均可复现。
- 关键区分:这不是索引创建失败,也不是 master key 认证问题,是异步任务尚未完成。文档确实已收到(
receivedDocuments > 0),但还没建完倒排索引。
StackTrace(堆栈日志)
添加文档后立即搜索,返回空结果:
{
"hits": [],
"query": "botman",
"processingTimeMs": 0,
"limit": 20,
"offset": 0,
"estimatedTotalHits": 0
}
查看任务状态,发现还停在 enqueued:
{
"uid": 0,
"indexUid": "movies",
"status": "enqueued",
"type": "documentAdditionOrUpdate",
"details": {
"receivedDocuments": 19547,
"indexedDocuments": null
},
"enqueuedAt": "2026-10-02T09:25:53.000000Z",
"startedAt": null,
"finishedAt": null
}
indexedDocuments 为 null 说明还没开始索引。等几秒后再查,状态变成 succeeded:
{
"uid": 0,
"indexUid": "movies",
"status": "succeeded",
"type": "documentAdditionOrUpdate",
"details": {
"receivedDocuments": 19547,
"indexedDocuments": 19547
},
"duration": "PT0.030750S",
"enqueuedAt": "2026-10-02T09:25:53.000000Z",
"startedAt": "2026-10-02T09:25:53.352490Z",
"finishedAt": "2026-10-02T09:25:53.380038Z"
}
此时再搜索才能命中。
官方 FAQ 原文:
I uploaded documents but get no search results — Your document upload likely failed. Check the status of the task using the returned
taskUid.
Reproduce(复现代码)
# 1. 添加文档
curl -X POST 'http://localhost:7700/indexes/movies/documents?primaryKey=id' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer aSampleMasterKey' \
--data-binary @movies.json
# 返回:{"taskUid": 0, "indexUid": "movies", "status": "enqueued", "type": "documentAdditionOrUpdate", ...}
# 2. 立即搜索——返回空
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Authorization: Bearer aSampleMasterKey' \
-H 'Content-Type: application/json' \
--data-binary '{"q": "botman"}'
# 返回:{"hits": [], "estimatedTotalHits": 0, ...}
Root Cause(根因分析)
所有写操作都是异步的
Meilisearch 的设计哲学是把耗时操作全部异步化。官方异步操作指南原文:
Many operations in Meilisearch are processed asynchronously. These API requests are not handled immediately—instead, Meilisearch places them in a queue and processes them in the order they were received.
异步操作包括:创建 / 更新 / 删除索引、更新设置、添加 / 更新 / 删除文档、创建 dump / snapshot 等。API 请求被放入 FIFO 队列,逐个处理。请求立即返回一个 summarized task object(含 taskUid、status: enqueued),客户端需要轮询 GET /tasks/{taskUid} 等待 status 变为 succeeded。
任务状态流转
任务状态经过四个阶段:
enqueued:任务已入队,等待处理processing:Meilisearch 正在处理succeeded:处理成功,数据可搜索failed:处理失败,数据库无变更
在 enqueued 或 processing 状态下搜索,文档尚未进入倒排索引,自然搜不到。只有 succeeded 后文档才可搜索。
为什么不是同步的
Meilisearch 把索引构建和搜索查询分离,搜索请求永远优先于索引任务。这样即使后台正在索引数百万文档,前台搜索响应不受影响。代价是客户端必须自行轮询任务状态——没有“索引完成”的回调推送(v1.x 有实验性的 stream 端点,但主流用法还是轮询)。
The Fix(解决方案)
第一步:拿到 taskUid 后轮询任务状态
# 添加文档后拿到 taskUid=0,轮询直到 succeeded
curl http://localhost:7700/tasks/0 \
-H 'Authorization: Bearer aSampleMasterKey'
第二步:循环等待直到 status=succeeded
用 shell 轮询:
TASK_UID=0
while true; do
STATUS=$(curl -s "http://localhost:7700/tasks/${TASK_UID}" \
-H 'Authorization: Bearer aSampleMasterKey' | jq -r '.status')
if [ "$STATUS" = "succeeded" ]; then
echo "Indexing complete"
break
elif [ "$STATUS" = "failed" ]; then
echo "Indexing failed"
curl -s "http://localhost:7700/tasks/${TASK_UID}" \
-H 'Authorization: Bearer aSampleMasterKey' | jq '.error'
break
fi
sleep 1
done
用 Python SDK 等待:
from meilisearch_sdk import Client
client = Client('http://localhost:7700', 'aSampleMasterKey')
index = client.index('movies')
# 添加文档,拿到 task
task = index.add_documents(movies_json)
# 等待任务完成(SDK 内置轮询)
client.wait_for_task(task.task_uid)
# 或指定超时和间隔
client.wait_for_task(task.task_uid, timeout_in_ms=60000, interval_in_ms=500)
第三步:任务成功后再搜索
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Authorization: Bearer aSampleMasterKey' \
-H 'Content-Type: application/json' \
--data-binary '{"q": "botman"}'
# 现在能搜到了:{"hits": [...], "estimatedTotalHits": 21, ...}
注意事项
- 如果任务状态是
failed,检查error字段。常见原因:primary key 推断失败、文档格式错误。 - 大数据集索引时间较长(万级文档通常 <1 秒,百万级可能数分钟)。
- 中断 Meilisearch 进程是安全的——
processing状态的任务会重置为enqueued,重启后继续处理。 - 官方 FAQ 还提示:如果
status已经是succeeded但仍然搜不到,检查indexedDocuments是否等于receivedDocuments,不等说明部分文档被跳过。
References(参考来源)
- FAQ — Meilisearch 官方文档meilisearch-docs
- Tasks and asynchronous operations — Meilisearch 官方文档meilisearch-docs
- Quick start — Meilisearch 官方文档meilisearch-docs
- Tasks API — Meilisearch 规范文档meilisearch-spec
- Working with tasks — Meilisearch 官方文档meilisearch-docs
