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(誰跟誰最像)。下一章 串流資料處理管線實戰 將把這四個工具整合成一個完整的即時資料處理系統——從原始串流資料到最終的分析報告,一條龍產出。