為什麼 SQL LIKE 不夠用?
大部分開發者在初期都用 SQL 的 LIKE 語法做搜尋功能。 這在資料量小的時候看起來沒問題,但當用戶數據量成長、或搜尋需求變得稍微複雜, 就會遇到一系列根本無法用 SQL 解決的問題。
Elasticsearch 對以上每個問題都有針對性的解法,而且這些解法是在架構層面設計的,不是打補丁:
SQL 的問題
O(n) 全表掃描
ES 解法:倒排索引(Inverted Index)
搜尋複雜度從 O(n) 降為接近 O(1),10 萬筆和 1 億筆的搜尋速度差距極小。
SQL 的問題
沒有相關度排序
ES 解法:TF-IDF / BM25 算法
根據詞頻、文件頻率、文件長度自動計算每個結果的相關度分數(_score)。
SQL 的問題
不理解語意
ES 解法:Analyzer(分析器)
分詞、去除停用詞(的、了、是)、同義詞展開、詞幹提取,讓搜尋理解語言。
SQL 的問題
字串精確匹配
ES 解法:模糊搜尋 + 多欄位加權
支援 fuzziness(typo 容錯)、phonetic(發音相似)、跨欄位搜尋並設定不同權重。
什麼時候該考慮引入 Elasticsearch?
- →搜尋功能是產品核心(電商、文件系統、部落格、Log 分析)
- →需要模糊搜尋、高亮顯示、同義詞、中文分詞等進階功能
- →資料量超過 10 萬筆,SQL LIKE 查詢已明顯變慢
- →需要聚合統計(各分類文章數、平均評分、時間序列分布)
Elasticsearch 核心概念
第一步是建立 Elasticsearch 與傳統 SQL 資料庫的概念對應關係。 這不是完美的類比(兩者設計哲學不同),但能幫助你快速建立心智模型。
SQL vs Elasticsearch 概念對照
| SQL(關聯式資料庫) | Elasticsearch | 說明 |
|---|---|---|
| Database | Index | 資料的最頂層容器,通常一個服務對應一個或多個 Index |
| Table | (廢棄) | ES 7.x 後移除 Type 概念,Index 直接對應 Table |
| Row | Document(JSON) | 最小資料單位,ES 中以 JSON 格式儲存 |
| Column | Field | Document 的每個 JSON 欄位 |
| Schema | Mapping | 定義每個 Field 的資料型別和分析方式 |
| SELECT | GET / Search API | 查詢資料,ES 用 HTTP REST API |
| INSERT / UPDATE | Index a Document | 寫入文件,自動建立倒排索引 |
| Primary Key | _id | 每個 Document 的唯一識別碼 |
| SQL JOIN | (不支援) | ES 是文件型,需在應用層做 JOIN 或用 nested/parent-child |
倒排索引(Inverted Index)— 最重要的概念
倒排索引是 Elasticsearch 高效搜尋的根本原因。傳統資料庫是「文件 → 詞彙」的正向索引, 而倒排索引反過來,建立「詞彙 → 文件列表」的映射。
為什麼倒排索引這麼快?
傳統 SQL LIKE 必須逐一掃描每筆資料(O(n))。倒排索引預先建立「詞彙 → 文件」的映射, 搜尋時直接查表找到包含此詞的文件列表(接近 O(1))。代價是寫入時需要額外建立索引, 但搜尋系統通常「讀多寫少」,這個取捨非常值得。
Mapping 定義(Schema)
Mapping 相當於 SQL 的 Schema,定義每個欄位的資料型別和分析方式。 Elasticsearch 有「Dynamic Mapping」(自動推斷型別),但生產環境強烈建議手動定義 Mapping, 避免型別推斷錯誤導致後續無法修改(Mapping 一旦建立就不能修改,只能 reindex)。
text vs keyword — 最常搞混的概念
text(全文搜尋)
- • 寫入時會被 Analyzer 分詞
- • 支援模糊搜尋、相關度排序
- • 無法精確匹配、排序、聚合
- • 適合:title、content、description
keyword(精確匹配)
- • 整個字串作為一個詞彙
- • 支援精確匹配、排序、聚合
- • 無法全文搜尋
- • 適合:tags、status、author ID
最佳實踐:重要的文字欄位同時設定 text 和 keyword(用 fields 子欄位), 如 title.keyword 可用於排序,title 本身用於全文搜尋。
Query DSL — 查詢語言
Query DSL(Domain Specific Language)是 Elasticsearch 的查詢語法, 透過 JSON 格式描述查詢邏輯。掌握以下幾種核心 Query 類型, 就能應對 90% 的搜尋需求。
Aggregation — 統計分析
Aggregation 是 Elasticsearch 的統計分析功能,相當於 SQL 的 GROUP BY + 聚合函數。 它可以在搜尋的同時做統計,非常適合做 Dashboard、Filter Facets(電商的側邊篩選器)、 Log 分析等需求。
三大 Aggregation 類型速查
將文件分組(類似 GROUP BY)
terms(按欄位值分組)、range(按數值範圍)、date_histogram(按時間區間)
計算統計數值
avg(平均)、sum(總和)、min/max(最小/最大)、cardinality(去重計數)
對其他聚合的結果再做計算
moving_avg(移動平均)、derivative(環比變化)、cumulative_sum(累計值)
Node.js 整合實戰
官方提供 @elastic/elasticsearch Node.js client, API 設計與 REST API 結構一致,上手非常快。
架構建議:Elasticsearch 是搜尋加速層,不是主資料庫
Elasticsearch 不應該是你的主要資料庫。它不支援完整的 ACID 交易、 JOIN 操作受限、且資料可能在節點重啟後有短暫不一致。 正確的架構是:主資料存在 PostgreSQL,搜尋索引同步到 Elasticsearch。 PostgreSQL 是 Source of Truth,ES 只是搜尋的加速層。
# 推薦的資料同步架構
用戶寫入 → PostgreSQL(主資料庫)
→ Debezium CDC 監聽 WAL
→ Kafka 事件佇列
→ ES Sync Consumer
→ Elasticsearch(搜尋索引)
# 用戶搜尋 → 直接查 Elasticsearch
# 用戶讀取文章 → 查 PostgreSQL 或 Redis Cache