結論先講

可以做,而且比你想的簡單。 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 會:

  1. 從 product-123 的 name、description、category 欄位提取關鍵詞
  2. 找出包含最多相同關鍵詞的其他商品
  3. 按 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 kNNpgvector
速度(百萬筆)快(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。


實作清單

如果你現在要開始做:

  1. 第一天:在商品詳情頁加 more_like_this(相似商品)
  2. 第一週:建 user_views index,記錄瀏覽行為,用 significant_terms 做「也看了」
  3. 第二週:用 Kibana 做推薦效果 dashboard(點擊率、轉換率)
  4. 需要時:加 embedding(OpenAI API),用 kNN 做向量推薦
  5. 更需要時:上 ML model,用 ES 當 serving layer

每一步都是在上一步「效果不夠好」時才做。



下一篇

微服務通訊協定:REST vs gRPC vs GraphQL — 搜尋和推薦搞定了,接下來看微服務之間怎麼溝通——對外 REST、對內 gRPC、什麼時候用 GraphQL。

本系列文章

完整 68 篇目錄見 系列首頁

← 上一篇:搜尋的演進:從 MySQL LIKE 到 PostgreSQL FTS 到 Elasticsearch → 下一篇:微服務通訊協定:REST vs gRPC vs GraphQL,什麼時候用什麼