FAISS 向量相似搜尋

FAISS (Facebook AI Similarity Search) 是 Facebook AI 開發的開源函式庫,專門用來在大規模向量集合中進行快速的相似度搜尋。

它是現代推薦系統、語意搜尋、RAG (檢索增強生成) 的底層核心引擎。

安裝 FAISS

pip install faiss-cpu  # 或 faiss-gpu(如果有 GPU)

基本使用

import numpy as np
import faiss
import time

# 產生測試資料:10000 個 128 維向量
np.random.seed(42)
d = 128  # 向量維度
n = 10000  # 向量數量

xb = np.random.random((n, d)).astype('float32')

# 建立 Index(暴力掃描 L2 距離)
index = faiss.IndexFlatL2(d)
print(f"Index 是否訓練: {index.is_trained}")

# 加入向量
index.add(xb)
print(f"Index 中向量數: {index.ntotal}")

# 搜尋:找最近的 5 個鄰居
xq = np.random.random((5, d)).astype('float32')  # 5 個查詢向量

start = time.time()
k = 5
distances, indices = index.search(xq, k)
elapsed = time.time() - start

print(f"\n=== 暴力搜尋結果 ===")
print(f"耗時: {elapsed*1000:.2f} ms")
for i in range(5):
    print(f"查詢 {i}: 最近鄰居 = {indices[i]}, 距離 = {distances[i]}")

使用 IVF 加速大規模搜尋

當向量數量超過 100 萬時,暴力掃描太慢。我們使用 IVF (Inverted File) 索引:

# 建立 IVF 索引(使用 100 個聚類中心)
nlist = 100
quantizer = faiss.IndexFlatL2(d)
index_ivf = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)

# IVF 需要訓練
index_ivf.train(xb)
index_ivf.add(xb)

# 搜尋(nprobe 控制探索的聚類數)
index_ivf.nprobe = 10  # 探索 10 個最近的聚類

start = time.time()
distances_ivf, indices_ivf = index_ivf.search(xq, k)
elapsed_ivf = time.time() - start

print(f"\n=== IVF 搜尋結果 ===")
print(f"耗時: {elapsed_ivf*1000:.2f} ms (加速 {(elapsed/elapsed_ivf):.1f}x)")

# 檢查準確率
correct = sum(1 for i in range(5) 
              if set(indices[i]) == set(indices_ivf[i]))
print(f"前 5 完全匹配率: {correct/5:.0%}")

應用:向量-Based 推薦系統

# 模擬電影推薦
n_movies = 5000
n_dims = 64

# 產生電影特徵向量(每個維度代表一種風格)
movie_features = np.random.random((n_movies, n_dims)).astype('float32')
movie_titles = [f"電影 {i}" for i in range(n_movies)]

# 建立 Index
index_movies = faiss.IndexFlatIP(n_dims)  # 內積 = 餘弦相似度(向量已正規化)
faiss.normalize_L2(movie_features)
index_movies.add(movie_features)

# 模擬使用者偏好
user_pref = np.random.random((1, n_dims)).astype('float32')
faiss.normalize_L2(user_pref)

# 推薦 10 部電影
D, I = index_movies.search(user_pref, 10)

print(f"\n=== 向量推薦結果 ===")
for idx, score in zip(I[0], D[0]):
    print(f"推薦: {movie_titles[idx]} (相似度: {score:.4f})")

使用 Vibe Coding 整合 FAISS

🔥 【FAISS 詠唱範例】 「請幫我建立一個向量搜尋 API: 1. 使用 FAISS 建立 100 萬條 256 維向量的索引。 2. 使用 IVF1000 + PQ32 壓縮索引,控制記憶體在 1GB 內。 3. 用 FastAPI 包裝成 POST /search 端點。 4. 支援新增向量 (add) 與搜尋 (search)。 5. 加入快取層減少重複查詢。 6. 輸出搜尋耗時與每秒查詢數 (QPS)。」



一切回到同一個問題:推薦系統怎麼知道「你可能喜歡」?

Netflix 是怎麼知道你可能喜歡《魷魚遊戲》的?Amazon 為什麼在你買了印表機後推薦你買紙?Spotify 的每週推薦歌單是怎麼產生的?

答案都在向量嵌入 (Vector Embeddings) 裡。

從文字到向量

每個商品、電影、歌曲、使用者都被轉換成一個向量(例如 128 維的浮點數陣列)。這個向量的位置代表了該物品的「語意」——相似的物品在向量空間中距離較近。

電影 A(動作片):| 0.9, 0.1, 0.8, 0.2, ... |
電影 B(動作片):| 0.8, 0.2, 0.7, 0.3, ... | → 距離近(相似)
電影 C(文藝片):| 0.1, 0.9, 0.2, 0.8, ... | → 距離遠(不相似)

當你看了電影 A 後,推薦系統只需要在向量空間中找離 A 最近的 N 部電影——這就是 FAISS 在做的事。

FAISS 的索引類型選擇

| 索引類型 | 搜尋速度 | 記憶體 | 精確度 | 適合場景 | |:--------:|:--------:|:------:|:------:|---------| | IndexFlatL2 | 慢(暴力) | 高 | 100% | 小規模資料 (<10萬) | | IndexIVFFlat | 快 10-100x | 高 | ~95% | 中等規模 (<1000萬) | | IndexIVFPQ | 極快 | 低(壓縮) | ~85-90% | 大規模 (>1000萬) | | IndexHNSW | 極快 | 中 | ~99% | 需要高精確度的大規模搜尋 |

# 實際場景:1000 萬部電影的向量搜尋
import faiss
import numpy as np

d = 128  # 向量維度
n = 10000000  # 1000 萬部電影

# 建立 IVF + PQ 索引(平衡速度與記憶體)
nlist = 10000  # 聚類中心數
m = 16  # PQ 壓縮的子量化器數
quantizer = faiss.IndexFlatL2(d)
index = faiss.IndexIVFPQ(quantizer, d, nlist, m, 8)

index.train(xb)
index.add(xb)
index.nprobe = 100  # 搜尋時檢查的聚類數

# 搜尋:找最相似的 10 部電影
D, I = index.search(xq, k=10)
print(f"推薦電影 ID: {I[0]}")
print(f"相似度分數: {D[0]}")

下章預告:把一切兜起來

你已經學會了 Bloom Filter(是否存在)、HyperLogLog(有多少不同)、Count-Min Sketch(出現幾次)、FAISS(誰跟誰最像)。下一章 串流資料處理管線實戰 將把這四個工具整合成一個完整的即時資料處理系統——從原始串流資料到最終的分析報告,一條龍產出。

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!