結論先講
大部分應用不需要 Elasticsearch。 MySQL LIKE 或 PostgreSQL FTS 就能解決 80% 的搜尋需求。只有當你需要「中文分詞」「模糊容錯」「faceted search」「搜尋建議」這些進階功能時,才值得付出 Elasticsearch 的維護成本。不要為了搜尋一個商品名稱就上 ELK stack。
搜尋的三個等級
| 等級 | 技術 | 能力 | 適合規模 |
|---|---|---|---|
| Level 1 | MySQL LIKE / ILIKE | 字串包含匹配 | < 10 萬筆 |
| Level 2 | PostgreSQL FTS | 全文搜尋 + 排名 | < 100 萬筆 |
| Level 3 | Elasticsearch | 搜尋引擎等級 | 無上限 |
Level 1:MySQL / PostgreSQL LIKE
怎麼做
-- 最簡單的搜尋
SELECT * FROM products WHERE name LIKE '%手機%';
-- PostgreSQL 的 ILIKE(不分大小寫)
SELECT * FROM products WHERE name ILIKE '%phone%';好處
- 零成本:不需要額外服務、不需要額外學習
- 即時一致:搜尋結果永遠是最新的(直接查 DB)
- 所有框架都支援:ORM 原生支援
壞處
- 慢:
LIKE '%keyword%'不走索引,每次都全表掃描 - 笨:搜「手機殼」找不到「手機保護殼」、搜「iphone」找不到「iPhone」(MySQL 預設 case-insensitive,PG 預設 case-sensitive)
- 沒有排名:所有結果同等重要,沒有「最相關的排前面」
什麼時候夠用
- 後台管理系統(管理員搜用戶、搜訂單)
- 資料量 < 10 萬筆
- 搜尋不是核心功能
- 不需要模糊匹配
加速技巧
-- MySQL:前綴匹配可以走 B-tree index
SELECT * FROM products WHERE name LIKE '手機%'; -- 走索引
SELECT * FROM products WHERE name LIKE '%手機%'; -- 不走索引
-- PostgreSQL:pg_trgm extension + GIN index
CREATE EXTENSION pg_trgm;
CREATE INDEX idx_products_name_trgm ON products USING GIN (name gin_trgm_ops);
-- 之後 LIKE '%手機%' 也能走索引PostgreSQL 的 pg_trgm 是個寶——它用 trigram(三字母組合)建索引,讓 %keyword% 也能走索引。效能可以提升 10-50 倍。
Level 2:PostgreSQL Full Text Search
怎麼做
-- 建立 tsvector 欄位
ALTER TABLE products ADD COLUMN search_vector tsvector;
UPDATE products SET search_vector = to_tsvector('chinese', name || ' ' || description);
CREATE INDEX idx_search_vector ON products USING GIN (search_vector);
-- 搜尋
SELECT *, ts_rank(search_vector, query) AS rank
FROM products, to_tsquery('chinese', '手機 & 保護殼') query
WHERE search_vector @@ query
ORDER BY rank DESC;比 LIKE 多了什麼
| 功能 | LIKE | PG FTS |
|---|---|---|
| 全表掃描 | 是 | 否(GIN 索引) |
| 分詞 | 沒有 | 有(支援中英文) |
| 排名 | 沒有 | ts_rank 按相關度排序 |
| 同義詞 | 沒有 | 可以設定 |
| 布林搜尋 | 沒有 | &(AND)` |
壓測數據
第 20 篇 的數據:Elasticsearch 做全文搜尋比 PG LIKE 快 2.6 倍。但 PG FTS(不是 LIKE)和 ES 的差距小很多——大約 1.5-2 倍。
好處
- 不需要額外服務:PG 內建,不用裝 Elasticsearch
- 資料一致:搜尋和 CRUD 在同一個 DB,不需要資料同步
- 夠用:百萬筆以內的搜尋效能完全可接受
壞處
- 中文分詞有限:PG 的中文分詞(
zhparser)功能比 ES 的ik分詞器弱 - 沒有 fuzzy match:搜「iphon」不會自動匹配「iphone」
- 沒有 aggregation:不能做「按品牌分類統計數量」這種 faceted search
- 沒有搜尋建議:不能做「你是不是要搜…」
什麼時候夠用
- 搜尋是功能之一但不是核心
- 資料量 < 100 萬筆
- 不需要 fuzzy、faceted、suggest
- 不想多維護一個 Elasticsearch 叢集
Level 3:Elasticsearch
怎麼做
// 建立 index + 中文分詞
PUT /products
{
"settings": {
"analysis": {
"analyzer": {
"chinese": { "type": "ik_max_word" }
}
}
},
"mappings": {
"properties": {
"name": { "type": "text", "analyzer": "chinese" },
"description": { "type": "text", "analyzer": "chinese" },
"brand": { "type": "keyword" },
"price": { "type": "float" }
}
}
}
// 搜尋:fuzzy + boost + aggregation
GET /products/_search
{
"query": {
"bool": {
"should": [
{ "match": { "name": { "query": "iphon", "fuzziness": "AUTO", "boost": 2 } } },
{ "match": { "description": { "query": "iphon", "fuzziness": "AUTO" } } }
]
}
},
"aggs": {
"brands": { "terms": { "field": "brand" } },
"price_range": { "histogram": { "field": "price", "interval": 1000 } }
}
}ES 獨有的能力
| 功能 | 說明 | 使用場景 |
|---|---|---|
| Fuzzy Search | 搜「iphon」→ 找到「iPhone」 | 容錯搜尋 |
| 中文智慧分詞 | 「手機保護殼」→「手機」「保護」「殼」 | 中文搜尋 |
| Aggregation | 按品牌、價格、評分分類統計 | 電商 faceted search |
| Suggest | 「你是不是要搜 iPhone 15」 | 搜尋建議 |
| Highlight | 搜尋結果中標記匹配的關鍵字 | 搜尋結果展示 |
| Synonym | 搜「手機」也找到「行動電話」 | 同義詞擴展 |
| Multi-language | 同時支援中英日韓 | 多語系網站 |
壞處
- 額外服務:要跑一個 Elasticsearch 叢集(至少 3 節點才算 production)
- 資料同步:DB 是 source of truth,ES 是副本。寫入 DB 後要同步到 ES
- 記憶體吃很多:ES 建議給 heap 至少 4GB,3 節點就是 12GB
- 學習成本:Query DSL、Mapping、Analyzer、Tokenizer——一堆新概念
- 最終一致:DB 寫了但 ES 還沒同步,搜尋結果可能延遲幾秒
單體 vs 微服務:搜尋怎麼做
單體架構
用戶搜尋 → 單體 API → DB (LIKE / FTS) → 回傳結果
- 簡單直接
- 資料永遠一致
- 效能受限於 DB
如果要加 ES:
用戶搜尋 → 單體 API → Elasticsearch → 回傳結果
寫入時同步: 單體 API → DB + ES (dual write)
注意 dual write 的風險:如果寫 DB 成功但寫 ES 失敗,資料不一致。
微服務架構
用戶搜尋 → API Gateway → Search Service → Elasticsearch → 回傳結果
寫入同步: Product Service → 發事件 "product.updated"
→ Search Service 收到 → 更新 ES index
用 event-driven(第 35 篇)做資料同步:
- Product Service 只管寫 DB
- Search Service 只管維護 ES index
- 透過 event 解耦,不是 dual write
微服務下要注意的事
- Search Service 是獨立的:有自己的 ES,不碰 Product DB
- 資料同步有延遲:用戶剛建的商品可能搜尋不到(幾秒延遲)
- ES 掛了不影響寫入:Product Service 繼續運作,event 堆在 queue 裡等 ES 恢復
- 重建 index 要有機制:ES 資料壞了或 mapping 改了,要能從 DB 重建整個 index
選型決策樹
你需要搜尋功能嗎?
├── 只是後台找資料 → LIKE / ILIKE 就好
├── 需要排名 + 基本分詞 → PostgreSQL FTS
│ ├── < 100 萬筆 → PG FTS 夠用
│ └── > 100 萬筆 → 考慮 ES
└── 需要 fuzzy + faceted + suggest → Elasticsearch
├── 單體 → dual write(簡單但有一致性風險)
└── 微服務 → event-driven 同步(複雜但解耦)
從 Level 1 升級到 Level 3 的漸進路線
不要一開始就上 ES。按需求漸進:
- 起步:
LIKE '%keyword%'(一天做完) - 需要加速:PG
pg_trgm+ GIN index(半天) - 需要排名:PG FTS
tsvector+ts_rank(一天) - 需要 fuzzy/faceted:加 Elasticsearch(一週 + 持續維護)
每一步都是在上一步「不夠用」的時候才升級。大部分應用永遠停在第 2-3 步。
下一篇
基於 ELK 的推薦系統:能做嗎?該怎麼規劃? — Elasticsearch 不只是搜尋引擎,它的 aggregation + more-like-this + vector search 可以做到基礎的推薦功能。但和 ML-based 推薦系統差在哪裡?什麼場景用 ELK 推薦就夠了?
本系列文章
完整 68 篇目錄見 系列首頁
← 上一篇:成本優化:免費午餐的 ROI 計算 → 下一篇:基於 ELK 的推薦系統:能做嗎?該怎麼規劃?