Elasticsearch 搜尋引擎 (Elasticsearch)

一句話定位

Elasticsearch 是建立在 Apache Lucene 之上的分散式搜尋協調層。Lucene 負責「搜尋本身」(inverted index、doc values);Elasticsearch 負責「分散式那層」(cluster 協調、REST API、aggregation、即時能力)。
面試定位:搜尋層,不是真理來源(source of truth)。權威資料放別處,用 CDC 同步進 ES。

從使用端看:四個核心名詞

名詞 對應 RDBMS 說明
Document row 一筆被搜尋的資料,本質是任意 JSON 物件,有唯一 _id
Index table 一群 document 的集合;搜尋是針對 index 做的
Mapping schema 定義有哪些 field、型別、如何被索引
Field column document 裡的鍵值對
兩種「index」別搞混

ES 的 Index(≈table) 和「讓查詢變快的輔助資料結構(inverted index)」是不同概念,靠上下文區分。

keyword vs text — mapping 最關鍵的選擇

型別 處理方式 查詢行為 用途
keyword 整段值,不分詞 精確比對(像 hash 表) id、tag、category、排序
text 經 analyzer 分詞 全文檢索(像倒排索引) title、description
Mapping 影響成本

把不參與搜尋的欄位也 map 進去 → 每個 index 記憶體開銷變大、成本上升。只 map 你會搜的欄位

nested 的正規化取捨

reviews 巢狀在書的 document 裡(nested 型別)vs 另建 reviews index——和 RDBMS 的正規化/反正規化一樣:


基本操作(REST API)

PUT  /books                建立 index(可設 shards / replicas)
PUT  /books/_mapping       設定 mapping
POST /books/_doc           新增 document(回傳 _id、_version)
PUT  /books/_doc/{id}      整份覆寫
POST /books/_update/{id}   只更新部分欄位
_version = 樂觀並行控制

ES 用 _version 做 document 的原子更新。PUT /books/_doc/{id}?version=1 表示「只有 version 為 1 時才更新」,否則回錯 → client 處理衝突並重試。
注意 ES 是分散式、非同步、並行的,request 可能到多個 node 且順序不定——更新語意要寫清楚。


搜尋查詢

語法接近 SQL 思維,用 JSON 表示、好組合:

match  → 全文比對單一欄位
bool   → must / should / must_not 組合多條件
range  → 數值/日期範圍(price lte 1000)
nested → 在巢狀物件內搜(reviews.comment + reviews.rating)

回應帶 _score(相關度分數)、_source(原始 JSON)。

排序的四種方式

方式 機制
欄位排序 sort: [{price: asc}],可多欄位
Script 排序 Painless script 依計算值排序(如打折後價格)
Nested 排序 排序值取自同一巢狀物件(mode: max
相關度 不指定 sort 時的預設,_scoreTF-IDF

分頁:三種策略

策略 機制 代價
from / size 指定起始位置 + 每頁筆數 深分頁(> 1 萬)極貴,要先排序取出前面所有 doc
search_after 用「上一頁最後一筆的 sort 值」當下一頁起點 不能隨機跳頁、只能往後;不漏不重
PIT cursor Point in Time + search_after 成本最高,但提供一致視角
from/size:     每頁都重排 + 取出前面全部  → 深分頁雪崩
search_after:  只取「上一頁最後一筆之後」 → 逐步縮小範圍,省資源
PIT + after:   凍結一個時間點的快照       → 翻頁期間資料在變也不影響
search_after 的好處

即使兩次請求間有新增 document 也不會漏、不會在頁間重複;代價是 client 要自己記住「上一頁最後一筆的 sort 值」。


底層架構

Cluster 與五種 Node

Node 型別 職責
Master 協調 cluster,唯一能建/刪 index、增刪 node(管理員)
Data 實際存資料;搜尋真正發生的地方
Coordinating 對外入口,解析查詢、分發到 shard、合併結果
Ingest 寫入前置處理(ingest pipeline)
Machine Learning ML 相關工作

一個 instance 可同時扮演多種角色。Master-eligible nodes 跑 leader election,同時只有一個 active master

寫入路由:hash(_id) % number_of_shards 決定寫進哪個 primary shard。

Shard 與 Replica

Lucene Segment 的不可變 CRUD

Segment 是「不可變」的索引容器

寫入先批次累積 → 建好一個 segment → flush 到磁碟。segment 太多時 merge 成新的再刪舊的。

操作 做法
新增 寫進 segment,不動舊的 → 寫入快
刪除 標記「已刪除」ID,查詢時當不存在;merge 時才真正清掉 → 刪除快
更新 對舊 document 做 soft delete + 插入一筆新的 → merge 時清理
ES 不適合「寫入/更新非常頻繁」的資料

更新比插入更耗效能(要處理 soft delete 簿記)。merge 前會一直帶著效能包袱。「按讚數/曝光數」這類高頻更新讓 ES 很吃力。
不可變設計換來:寫入快、快取簡單(segment 不變可安心 cache)、並行單純、壓縮效果好。

Segment 內的兩個關鍵結構

結構 解決什麼 機制
Inverted Index 「哪些 doc 符合」 詞 → document 清單;把 O(n) 掃描變 O(1) 查表(Lucene 的心臟)
Doc Values 排序 / aggregation 單一欄位、整個 segment 的欄式(columnar)連續儲存

Query Planning

Coordinating node 的 query planner 用統計資訊(欄位型別、詞分布、document 長度)選最省的執行策略。
例:搜 "bill nye"bill 有幾百萬筆、nye 只有幾百筆 → 先建 nye 集合再掃 bill 比反過來快好幾個數量級。


面試用法與限制

何時用 ES

題目涉及複雜搜尋(排序、篩選、排名、分面)通常都是好候選。實務上常用 CDC 從 Postgres / DynamoDB 同步權威資料進 ES。

幾條一定要會講的限制:

可遷移的設計原則(即使不用 ES)