2.4 相似度搜尋:找出相關向量
兩個向量有多像、怎麼量,以及資料很多時怎麼快速找到最接近的那幾個。
文字都變成向量之後,檢索就變成一個數學問題:給一個問題的向量,在一大堆向量裡,找出離它最近的 k 個。這就是相似性搜尋(similarity search)。
先要回答的是:怎麼量「兩個向量有多像」?
三種常見的量法
餘弦相似度(Cosine similarity)
看兩個向量方向的夾角。夾角越小,方向越一致,越相似。
cos(θ) = (A · B) / (‖A‖ × ‖B‖)
分子是兩個向量的內積,分母是兩個向量長度相乘。結果介於 -1 到 1:
- 接近 1:方向幾乎一樣,意思很像。
- 接近 0:沒什麼關係。
- 接近 -1:方向相反。
餘弦相似度是文字檢索最常用的量法,因為它只看方向、不看長度。一段話寫得長或短,不會影響它判斷意思像不像。
內積(Dot product)
直接把兩個向量對應位置的數字相乘再加起來。如果向量已經正規化(長度都調成 1),內積就等於餘弦相似度,而且算起來更快。很多嵌入模型的輸出本來就是正規化的。
歐氏距離(Euclidean distance)
兩個點之間的直線距離。越小越相似,跟前兩個相反(越大越相似)。
怎麼選
| 量法 | 數值方向 | 備註 |
|---|---|---|
| 餘弦相似度 | 越大越像 | 文字檢索最常用 |
| 內積 | 越大越像 | 向量正規化後等於餘弦相似度,速度快 |
| 歐氏距離 | 越小越像 | 向量正規化後,排名結果跟餘弦一致 |
最重要的是看嵌入模型的說明文件,它會告訴你建議用哪一種。向量資料庫建立索引時,也要設定同樣的量法。
暴力搜尋和近似搜尋
最直接的做法是暴力搜尋(brute force):把問題向量和知識庫裡每一個向量都算一次相似度,再排序取前 k 個。結果是最準確的,但資料量越大越慢。
- 幾千筆:暴力搜尋完全沒問題。
- 幾百萬筆以上:每次提問都要全部算一遍,太慢了。
大規模時會用近似最近鄰搜尋(Approximate Nearest Neighbor,ANN):事先建一個特別的索引結構,搜尋時只看一小部分最有希望的候選,換取速度。代價是偶爾會漏掉真正最近的那一個,但通常差距很小,大部分應用都能接受。
常見的 ANN 做法有:
- HNSW:把向量組織成多層的圖,由上往下一路靠近目標,速度快、效果好,應用很廣。
- IVF:先把向量分成很多群,搜尋時只去離問題最近的幾群找。
這些細節向量資料庫都會幫你處理,你通常只要知道它們存在,以及「速度」和「準確度」之間有取捨。
取回之後
搜尋的結果是一份排好序的清單:每一筆是一段內容和它的相似度分數。常見的後續處理有:
- 只取前 k 段。
- 設一個分數門檻,低於門檻的就算找不到,避免把完全不相關的內容硬塞給模型。
- 之後還可以用更精細的重排序(rerank),把候選再排一次,這是進階的優化。