結論先講
可以做,而且比你想的簡單。 Elasticsearch 的 more_like_this query 就能做到「看了 A 商品的人也看了 B」這種基礎推薦。加上 aggregation 做熱門排行、script score 做加權排序、kNN 做向量相似度推薦——中小型應用不需要上 TensorFlow 或 Spark MLlib,ELK 就能撐住。
推薦系統的三種策略
| 策略 | 原理 | 例子 | ES 能做嗎 |
|---|---|---|---|
| Content-Based | 推薦和你看過的「相似」的東西 | 你看了 A 手機,推薦類似規格的 B 手機 | 能(more_like_this) |
| Collaborative | 推薦「和你相似的人」喜歡的東西 | 買了 A 的人也買了 B | 部分能(aggregation) |
| Hybrid | 混合以上兩種 | Netflix 的推薦 | 基礎可以,進階要 ML |
策略一:Content-Based(ES 原生支援)
More Like This Query
ES 內建的 more_like_this(MLT)可以找出「和指定文件最相似的文件」:
GET /products/_search
{
"query": {
"more_like_this": {
"fields": ["name", "description", "category"],
"like": [
{ "_index": "products", "_id": "product-123" }
],
"min_term_freq": 1,
"min_doc_freq": 2,
"max_query_terms": 25
}
}
}這個 query 會:
- 從 product-123 的 name、description、category 欄位提取關鍵詞
- 找出包含最多相同關鍵詞的其他商品
- 按 TF-IDF 相似度排序
不需要寫任何 ML code。 一個 query 就搞定「看了這個也看看那個」。
適合的場景
- 商品詳情頁的「相似商品」
- 文章頁面的「相關文章」
- 職缺頁面的「類似職缺」
限制
- 只看內容相似度,不看用戶行為
- 對新商品(description 很短)效果差
- 不能做「買了 A 的人也買了 B」(需要行為資料)
策略二:Collaborative Filtering(ES 部分能做)
基於 Aggregation 的簡易版
如果你有用戶行為資料(瀏覽紀錄、購買紀錄),可以用 ES 的 aggregation 做簡易版的協同過濾:
// 第一步:找出「也看了 product-123」的用戶都還看了什麼
GET /user_views/_search
{
"size": 0,
"query": {
"term": { "product_id": "product-123" }
},
"aggs": {
"viewers": {
"terms": { "field": "user_id", "size": 100 }
}
}
}
// 第二步:拿這些用戶的 ID,查他們還看了什麼商品
GET /user_views/_search
{
"size": 0,
"query": {
"terms": { "user_id": ["user-1", "user-2", ...] }
},
"aggs": {
"also_viewed": {
"terms": {
"field": "product_id",
"size": 10,
"exclude": ["product-123"]
}
}
}
}兩步查詢就能得到「看了 A 的人也看了 B, C, D」。
更好的做法:Significant Terms
GET /user_views/_search
{
"size": 0,
"query": {
"term": { "product_id": "product-123" }
},
"aggs": {
"recommended": {
"significant_terms": {
"field": "product_id",
"exclude": ["product-123"],
"size": 10
}
}
}
}significant_terms 比普通的 terms 更聰明——它不只看頻率,還看「在看了 A 的人群中特別突出的商品」vs「全體用戶都常看的商品」。比如每個人都看過「iPhone」,但只有看了 A 的人特別常看「AirPods」→ AirPods 是更好的推薦。
策略三:向量搜尋推薦(ES 8.x kNN)
什麼是向量推薦
把每個商品轉成一個數值向量(embedding),相似的商品向量距離近。搜尋時找最近的 K 個向量 = 最相似的 K 個商品。
// 建 index 時加 dense_vector 欄位
PUT /products
{
"mappings": {
"properties": {
"name": { "type": "text" },
"embedding": {
"type": "dense_vector",
"dims": 384,
"index": true,
"similarity": "cosine"
}
}
}
}
// kNN 搜尋:找最相似的 10 個商品
GET /products/_knn_search
{
"knn": {
"field": "embedding",
"query_vector": [0.1, 0.2, ...], // product-123 的向量
"k": 10,
"num_candidates": 100
}
}向量從哪來
| 來源 | 難度 | 品質 |
|---|---|---|
| OpenAI Embeddings API | 最低(API call) | 高 |
| Sentence-BERT(本地跑) | 中 | 高 |
| TF-IDF 向量(ES 自己算) | 低 | 中 |
| 手動特徵工程 | 高 | 看功力 |
最簡單的做法:用 OpenAI 或 Claude 的 embedding API,把商品名稱 + 描述轉成向量,存進 ES。
和 pgvector 的比較
第 31 篇 提到 PostgreSQL 的 pgvector 也能做向量搜尋。差異:
| 維度 | ES kNN | pgvector |
|---|---|---|
| 速度(百萬筆) | 快(HNSW index) | 中 |
| 和搜尋整合 | 天然整合(同一個 query 混合文字 + 向量) | 分開查 |
| 維護 | 需要 ES 叢集 | PG 內建 |
| 適合 | 已經有 ES 的系統 | 只要向量搜尋、不要全文搜尋 |
如果你已經有 ES 做搜尋,向量推薦直接在 ES 裡做。如果只需要向量搜尋,用 pgvector 不用多裝 ES。
架構規劃
小規模(< 10 萬商品)
用戶瀏覽商品 → API → Elasticsearch more_like_this → 相似商品
一個 ES 節點、一個 index、MLT query。半天搞定。
中規模(10-100 萬商品)
行為收集: 用戶瀏覽/購買 → Event → Kafka → user_views index
推薦: API → significant_terms(user_views) + more_like_this(products) → 混合排序
加上行為資料做協同過濾。需要一個 Kafka + consumer pipeline。
大規模(> 100 萬商品)
離線: 定期用 ML model 算 embedding → 寫入 ES dense_vector
線上: API → kNN search + content score + behavior score → 混合排序
即時: 用 Kibana 監控推薦點擊率 → 調參
這個規模才需要 ML。但 ES 仍然是 serving layer——ML model 離線算 embedding,ES 線上做 kNN。
ELK 推薦 vs ML 推薦
| 維度 | ELK 推薦 | ML 推薦(TensorFlow/Spark) |
|---|---|---|
| 建置時間 | 1-2 天 | 2-6 個月 |
| 需要的人 | 後端工程師 | ML 工程師 |
| 推薦品質 | 中(夠用) | 高 |
| 個人化 | 基礎(行為 aggregation) | 深度(user embedding) |
| 維護成本 | 低(ES 叢集) | 高(training pipeline + model serving) |
| 適合 | 中小型電商、內容平台 | Netflix、Spotify、淘寶 |
中小型應用用 ELK 推薦就夠了。 花兩天做一個 80 分的推薦,比花半年做一個 95 分的推薦划算。等到推薦的點擊率是你的核心 KPI 時,再上 ML。
實作清單
如果你現在要開始做:
- 第一天:在商品詳情頁加
more_like_this(相似商品) - 第一週:建
user_viewsindex,記錄瀏覽行為,用significant_terms做「也看了」 - 第二週:用 Kibana 做推薦效果 dashboard(點擊率、轉換率)
- 需要時:加 embedding(OpenAI API),用 kNN 做向量推薦
- 更需要時:上 ML model,用 ES 當 serving layer
每一步都是在上一步「效果不夠好」時才做。
下一篇
微服務通訊協定:REST vs gRPC vs GraphQL — 搜尋和推薦搞定了,接下來看微服務之間怎麼溝通——對外 REST、對內 gRPC、什麼時候用 GraphQL。
本系列文章
完整 68 篇目錄見 系列首頁
← 上一篇:搜尋的演進:從 MySQL LIKE 到 PostgreSQL FTS 到 Elasticsearch → 下一篇:微服務通訊協定:REST vs gRPC vs GraphQL,什麼時候用什麼