目錄
Meilisearch 是一套以應用程式搜尋為目標的全文檢索引擎。把產品、文章、文件或客服知識同步進 index 後,它可以提供前綴搜尋、拼字容錯、篩選、排序與 facets,而不必讓每個查詢都掃一次主資料庫。
它不是主資料庫,也不是替 Agent 上網找資料的 public web search,更不是只靠 embedding 找語意相似內容的 vector database。若還在比較搜尋、爬取與自架工具的成本模型,可先看〈免費搜尋與爬取工具怎麼選〉;本文處理的是選定 Meilisearch 後,怎麼把它做成可維運的搜尋服務。
先理解 index、document 與 task
Meilisearch 的資料模型不複雜,但三個名詞不能混用:
- index 是一組可搜尋文件與搜尋設定,例如
articles、products。 - document 是 JSON object。每份文件都必須有同一個 primary key,例如
id。 - task 是非同步操作的狀態。建立 index、寫入文件、刪除文件與修改設定,通常先回傳 task,再由背景工作完成。
Primary key 是同步契約,不只是方便查找的欄位。官方說明指出,一個 index 只能有一個 primary key;相同 key 的文件會更新既有文件,而且 index 已有文件後不能直接更換 primary key。與其依賴欄位名稱推測,建立 index 時就明確指定:
curl -X POST 'http://127.0.0.1:7700/indexes' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data '{"uid":"articles","primaryKey":"id"}'
回應裡的 taskUid 只代表請求已排隊。根據 task 文件,HTTP 202 或 enqueued 都不是寫入成功;部署程式必須查詢 /tasks/{taskUid},直到 succeeded,遇到 failed 則保存錯誤內容並停止下游步驟。
curl \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
"http://127.0.0.1:7700/tasks/$TASK_UID"
如果設定 task 還沒完成就開始灌資料,或寫入 task 還在排隊就立刻驗收搜尋結果,很容易得到「API 沒報錯、結果卻不完整」的假成功。
本機安裝:先做一個只綁 localhost 的 smoke test
官方 self-hosting 指南提供 binary、套件管理器與 Docker 等安裝方式。以下 Docker 指令適合本機驗證;它把連接埠限制在 localhost,並把資料放進專用 volume:
docker run --rm -it \
-p 127.0.0.1:7700:7700 \
-e MEILI_ENV=development \
-v "$PWD/meili_data:/meili_data" \
getmeili/meilisearch:v1.37
正式環境不要照搬 development 設定。至少要鎖定映像版本、設定 master key、用 TLS reverse proxy 保護傳輸、限制網路入口,並把資料目錄與備份放進持久儲存。版本升級前也要先確認 dump/snapshot 相容性,而不是把 latest 直接交給自動部署。
搜尋品質首先由 settings 決定
新 index 預設可搜尋所有欄位,對 prototype 很方便,對 production 卻太寬。Meilisearch 需要把欄位用途寫成索引設定:
searchableAttributes:哪些欄位參與全文搜尋,順序也會影響 attribute ranking。filterableAttributes:哪些欄位可以放進filter或 facet。sortableAttributes:哪些欄位允許動態排序。displayedAttributes:搜尋結果允許回傳哪些欄位。
curl -X PATCH 'http://127.0.0.1:7700/indexes/articles/settings' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data '{
"searchableAttributes": ["title", "summary", "body"],
"filterableAttributes": ["tenant_id", "lang", "category", "published"],
"sortableAttributes": ["published_at"],
"displayedAttributes": ["id", "title", "summary", "url", "lang", "published_at"]
}'
searchable attributes 文件提醒,修改後會觸發非同步重新索引。filtering 與 sorting 文件也說明,只有預先宣告的欄位能被篩選或排序,因為引擎要建立額外資料結構。不要把每個欄位都設成 filterable/sortable;這會增加索引時間與記憶體需求,也讓公開查詢介面更難限制。
這組 settings 應像 database migration 一樣進版控:先在 staging 建新 index、寫入固定資料集、跑搜尋回歸測試,再切 alias 或應用程式設定。直接在 production 修改 settings,可能同時帶來 reindex 延遲與排序變化。
寫入、更新與刪除都要追 task
PUT /indexes/{index}/documents 會依 primary key 新增或更新文件;POST 則是新增或取代文件。需要局部更新欄位時通常用 PUT,但同步器仍應送出自己能負責的完整搜尋文件,避免舊欄位因不同 producer 交錯而殘留。
curl -X PUT 'http://127.0.0.1:7700/indexes/articles/documents' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data '[{
"id": "post_20260821_meili",
"tenant_id": "site_public",
"lang": "zh-TW",
"title": "Meilisearch 完整介紹",
"summary": "索引、中文搜尋與多租戶安全",
"url": "/posts/ai/2026-08-21-meilisearch-complete-guide",
"category": "ai",
"published": true,
"published_at": 1787241600
}]'
document API一樣先回 task。刪除也不是例外:來源文章下架、帳號刪除或租戶終止時,必須送出 delete 並等待完成,不能只從主資料庫移除。
curl -X DELETE \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
'http://127.0.0.1:7700/indexes/articles/documents/post_20260821_meili'
可靠的同步器至少要保存 source revision、document id、task uid、送出時間與最終狀態,並提供重跑與 reconciliation。Meilisearch 是衍生索引;主資料庫或 object storage 才是 source of truth。
Typo tolerance 要按欄位風險調整
Typo tolerance預設啟用,適合產品名稱、文章標題與一般自然語言。它能讓使用者少打一個字或按錯鍵時仍取得結果,這也是 Meilisearch 開箱搜尋手感好的原因之一。
但訂單編號、SKU、法規條號與人員代碼通常要求精確。這些欄位可以停用 typo tolerance,數字也能另外設定;否則 AB-1208 可能匹配到另一個看似相近、實際上完全不同的識別碼。調整後要以真實 query set 比較 recall 與誤匹配率,不要只看幾個手選範例。
同義詞也不能代替資料治理。「LLM」與「大型語言模型」可以是產品語彙同義詞,但品牌名、醫療詞彙與法規術語應由領域負責人審核,並跟 settings 一起版本化。
zh-TW 的限制在語言判斷,不是完全不能分詞
Meilisearch 使用 Charabia tokenizer,官方列出的語言支援包含需要專門 tokenizer 的中文與日文。因此「Meilisearch 不支援中文分詞」並不精確。
真正要注意的是自動語言判斷。多語資料指南指出:
- 中、日文不要混在同一欄位,因為兩者共用大量字元,難以穩定判斷應採哪一種 tokenizer。
- 很短或只有部分字詞的 query 也不容易偵測語言。
- 官方優先建議每種語言使用獨立 index;若一定要共用 index,至少拆成不同欄位,並用 localized attributes 與查詢 locales 明示語言。
對 zh-TW 站內搜尋,我會先建 articles_zh_tw,不要把繁中、日文與英文全文塞進同一個 body。文件保留 lang: "zh-TW",查詢端固定語言範圍,再用實際資料做 benchmark:品牌中英混寫、同義詞、全半形標點、繁簡差異、兩字短詞與常見錯字都要進測試集。
Meilisearch 能解決 tokenizer 與 typo tolerance 的基礎問題,但不會自動理解台灣用語。例如「隨身碟/USB」、「資料庫/數據庫」或產品內部縮寫仍需要同義詞、內容正規化或額外 reranking。中文搜尋能不能上線,應由固定 query relevance 測試決定,而不是由「官方支援 Chinese」一句話決定。
API key 與 tenant token 是兩種不同邊界
安全性總覽把權限分成三層:
- master key/管理用 API key 留在後端,負責 index、settings、document 與 key 管理。
- search-only key 只適合不需要租戶隔離的公開搜尋。
- tenant token 由可信任後端產生,把 index 範圍、搜尋權限與 filter rules 綁進短效 token。
多租戶系統不能只在前端偷偷加上 tenant_id = acme filter。使用者可以自行改 request;真正的隔離條件必須由 tenant token 強制套用。依照 tenant token payload文件,token 以受限 API key 作為 parent,並可加入過期時間。parent key 也要只授予必要 action 與 index,token 不應比 parent key 活得更久。
API key 管理指南的原則很直接:最小權限、限制 index、設定 expiry、不要把 admin key 放進 browser 或 mobile app,並建立輪替程序。搜尋結果中的內容仍是原始文件資料;若要渲染成 HTML,應在輸出層 escape/sanitize,而不是相信搜尋引擎會替你處理 XSS。
Snapshot 與 dump 的用途不同
自架搜尋服務遲早會遇到磁碟損壞、誤刪 index 或版本升級。備份總覽區分兩種機制:
| 機制 | 優點 | 限制 | 適用情境 |
|---|---|---|---|
| snapshot | 是資料庫的快速複本,恢復快 | 只能由相同 Meilisearch 版本載入,檔案較大 | 同版本災難復原 |
| dump | 可攜式資料藍圖,可跨版本匯入 | 匯入時要重建 index,較慢 | 升級、遷移、長期保存 |
Snapshot 指南也提醒,預設目錄中的新 snapshot 會覆蓋舊檔。排程建立不等於備份完成:檔案必須複製到不同故障域,保留多個世代,並定期在隔離環境做 restore drill。
Dump 可透過 POST /dumps 建立,同樣要追蹤背景 task;dump 文件建議把它用於 migration。升級流程應先產生 dump、驗證檔案、在目標版本匯入並跑搜尋回歸,最後才切換流量。
給 Agent 的工具介面應該比原生 API 更窄
Agent 不需要拿到 Meilisearch admin key,也不該自由決定 index、任意 filter 或無上限 limit。比較安全的 tool contract 可以只有:
type SearchKnowledgeInput = {
query: string;
category?: "docs" | "policy" | "support";
sort?: "relevance" | "newest";
limit?: number;
};
type SearchKnowledgeHit = {
id: string;
title: string;
snippet: string;
sourceUrl: string;
updatedAt: string;
};
後端 adapter 再負責:
- 從登入身分取得 tenant,而不是相信模型傳來的
tenant_id。 - 將 category 與 sort 映射到 allowlist,不接受任意 filter expression。
- 對 query 長度、
limit、timeout 與回應大小設硬上限。 - 使用 tenant token 或伺服器端受限 key 查詢。
- 回傳可引用的 source URL、片段與更新時間,不把整份私有文件塞進 context。
寫入、刪除、settings 與 backup 應是另一套受控的 ingestion/ops 工作流,不是一般對話 Agent 的工具。若 Agent 需要「新增知識」,先寫入 source of truth,經審核與同步器產生 document,再等待 task 成功;不要讓模型直接修改搜尋索引,否則無法保證刪除傳播、權限與稽核紀錄。
上線前的最低檢查表
- Primary key 已明確指定,而且能從 source of truth 重建所有 document id。
- Settings 已進版控;可搜尋、可篩選、可排序與可顯示欄位都是最小集合。
- 所有寫入、刪除、設定與 dump 操作都等到 task
succeeded。 - zh-TW 用真實 query set 測過短詞、繁簡、品牌名、同義詞與中英混寫。
- Public search key 不負責多租戶隔離;私有資料使用後端強制的 tenant token/filter rules。
- Admin key 不出現在前端、Agent prompt、log 或 analytics event。
- Snapshot/dump 已移出主機,且真的做過還原演練。
- Search index 被視為可重建的衍生資料,不承擔交易一致性或唯一真相。
Meilisearch 的價值是用比大型搜尋叢集更小的操作面,快速交付產品內全文搜尋。代價是你仍要自己定義索引 schema、非同步 task、中文 relevance、租戶邊界與災難復原。把這些契約在第一天就寫清楚,它會是一個很務實的搜尋元件;只看 demo 裡的即時搜尋框,上線後才會發現真正難的都在搜尋框之外。
參考資料
- What is Meilisearch?
- Install Meilisearch locally
- Primary key
- Tasks and batches
- Add or update documents
- Configure searchable attributes
- Filtering, sorting, and faceting
- Typo tolerance settings
- Language support
- Index multilingual datasets
- Security overview
- Manage API keys
- Tenant token payload
- Data backup overview
- Snapshots
- Dumps
Loading...