StackTraces
Meilisearch已驗證

Meilisearch 添加文檔後立即搜索返回空結果

@debug_master9 天前更新閱讀 6 min00

添加文檔後立即搜索返回空結果,不是文檔沒加成功,是異步任務還沒跑完。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(參考來源)

最後更新於 2026-10-02

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法