結論先講

大部分應用不需要 Elasticsearch。 MySQL LIKE 或 PostgreSQL FTS 就能解決 80% 的搜尋需求。只有當你需要「中文分詞」「模糊容錯」「faceted search」「搜尋建議」這些進階功能時,才值得付出 Elasticsearch 的維護成本。不要為了搜尋一個商品名稱就上 ELK stack。


搜尋的三個等級

等級技術能力適合規模
Level 1MySQL LIKE / ILIKE字串包含匹配< 10 萬筆
Level 2PostgreSQL FTS全文搜尋 + 排名< 100 萬筆
Level 3Elasticsearch搜尋引擎等級無上限

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 倍。


怎麼做

-- 建立 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 多了什麼

功能LIKEPG 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

微服務下要注意的事

  1. Search Service 是獨立的:有自己的 ES,不碰 Product DB
  2. 資料同步有延遲:用戶剛建的商品可能搜尋不到(幾秒延遲)
  3. ES 掛了不影響寫入:Product Service 繼續運作,event 堆在 queue 裡等 ES 恢復
  4. 重建 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。按需求漸進:

  1. 起步LIKE '%keyword%'(一天做完)
  2. 需要加速:PG pg_trgm + GIN index(半天)
  3. 需要排名:PG FTS tsvector + ts_rank(一天)
  4. 需要 fuzzy/faceted:加 Elasticsearch(一週 + 持續維護)

每一步都是在上一步「不夠用」的時候才升級。大部分應用永遠停在第 2-3 步。


下一篇

基於 ELK 的推薦系統:能做嗎?該怎麼規劃? — Elasticsearch 不只是搜尋引擎,它的 aggregation + more-like-this + vector search 可以做到基礎的推薦功能。但和 ML-based 推薦系統差在哪裡?什麼場景用 ELK 推薦就夠了?


本系列文章

完整 68 篇目錄見 系列首頁

← 上一篇:成本優化:免費午餐的 ROI 計算 → 下一篇:基於 ELK 的推薦系統:能做嗎?該怎麼規劃?