在上一篇中,我們已經建立了一個可以儲存向量的 Index,並寫入了包含向量欄位在內的 108 筆資料,還沒看過的可以先到下方連結查看喔!
接續上篇,我們會在這個 Index 上開始執行向量搜尋,交叉使用先前設定好的兩種演算法,最後會結合全文檢索進行混和搜尋。
完整程式碼於文末 GitHub 連結提供!
相關連結:【Azure Cognitive Search】使用 Python SDK 在認知搜尋中進行全文檢索
相關連結:【Azure Cognitive Search】使用 Python SDK 在認知搜尋中進行向量搜尋(上)
相關連結:https://github.com/Azure/cognitive-search-vector-pr/tree/main/demo-python
必要條件
- 具有與上篇相同設定的 Cognitive Search Index
- Cognitive Search 的官方 Python SDK:azure-search-documents 的 11.4.0b11 版
連線 Index
首先必須要連線到在上篇建立好的 Index:
使用 SearchClient 類與現有的 Index 建立連線,這邊要注意 index_name 是要建立連線的 Index 名稱 ,後面都會使用到這個物件,不過文章中就不會再重複這段程式碼了。
單一欄位的純向量搜尋
在執行向量搜尋時,一般都需要先將要搜尋的語句轉換為向量,後續才能與其他向量計算相似度,但每次執行都需要多這一步確實有點麻煩,常見的解法也是把流程包成函數來重複使用。
但在 Cognitive Search 中,非常貼心的幫我們把這一步處理掉了,現在我們可以直接把查詢問句丟進呼叫的接口,而不再是先轉換成向量,以下程式碼會更清楚這個流程:
原因是我們使用 VectorizableTextQuery 這個類別,背後他會自己去使用我們在上篇設定給 Index 的 Azure OpenAI 連線資訊來轉換向量,真的是非常方便,但因為還是使用我們自己的 Azure OpenAI 資源,所以轉換費用還是逃不了的😓
VectorizableTextQuery 代表的是一組向量搜尋的設定,k=3 表示回傳分數前三高的結果,fields="contentVector" 指定對哪一個欄位進行搜尋。
search_client.search 是真正執行搜尋的方法,vector_queries 放的是上述的向量搜尋設定,select 指定回傳時需要包含哪些欄位。
再來看看執行結果:
這邊使用 @search.score 印出每個搜尋結果的分數,但要注意的是這個分數並不是向量間的餘弦值,Cognitive Search 對分數進行了一些轉換,確保 @search.score 是一個單調遞減函數:
- 餘弦相似度定義為兩個向量之間角度的餘弦值
- 餘弦距離為 1 - cosine_similarity
- 最終的 @search.score 為 1 / (1 + cosine_distance)
如果你跟我一樣什麼都不想管,那你只要知道輸出的 @search.score 分數越高代表越相近就可以囉!
換個語言
就像上面說的,VectorizableTextQuery 背後使用 Azure OpenAI 的 Embedding 模型做向量轉換,所以進行向量搜尋的語句事實上是不限語言的,就像這樣:
執行結果:
Exhaustive KNN
因為在上篇中我們有加入 Exhaustive KNN 的設定,所以可以由預設的 HNSW 轉換成使用 Exhaustive KNN 算法。
執行結果:
只要加上 exhaustive=True 參數就能快速地切換到 Exhaustive KNN!
多欄位的純向量搜尋
這邊有兩種方式可以做到同時多欄位的向量搜尋:
跨欄位的單一向量搜尋
第一種方式比較簡單,適用在同一個搜尋語句在多個欄位中搜尋的情況,只要在 VectorizableTextQuery 的 fields 中加入要一起執行向量搜尋的欄位就可以了。
多個向量搜尋
第二種方式是將每個向量搜尋分別建立 VectorizableTextQuery 實例,當執行 search_client.search 方法時再彙整到 vector_queries 中。
這個方式有比較廣泛的適用情境,例如兩個欄位需要分別使用不同的 Embedding 模型,甚至轉換後的向量是不同維度的;而另一個常見的案例是希望執行多模態的搜尋,想要同時對圖片與文字進行向量搜尋,這些情況下都可以透過這個方式來達成。
在目前這個範例中,兩種方式的執行結果是一樣的:
可以看到分數似乎與先前都有點不同,這是因為當同時執行多個查詢時,Cognitive Search 會轉換成一種 RRF 評分算法來混和多個查詢的結果,最終呈現出來的分數一樣是一個望大的值。
帶有篩選條件的向量搜尋
Cognitive Search 本身就帶有篩選的功能,與原本使用的語法相同,當執行 search_client.search 方法時在 filter 參數帶上即可。
執行結果:
注意到執行時有加上 vector_filter_mode=VectorFilterMode.PRE_FILTER 參數,與之相反的是 VectorFilterMode.POST_FILTER,分別代表在向量搜尋前或後執行篩選,這個設定對於查詢結果的數量會有影響,如果要盡可能確保輸出數量保持 k=3,那就是選擇 VectorFilterMode.PRE_FILTER。
混合式搜尋
最後則是結合全文檢索與向量搜尋的混合式搜尋。
在搜尋中如果帶有特別的專有名詞或是特定領域的行話時,還是需要使用一般的全文檢索來做補強,這種情況下使用全文檢索與向量搜尋的混合式搜尋,甚至可以達到更好的效果。
最終的執行結果:
總結
整體來說,Cognitive Search 在加入向量搜尋的功能後,真正成為了完整的搜尋服務解決方案,多種搜尋方式的快速切換與任意的混和搭配使用,在程式設計上也簡單直觀,內建的數種算法與 Azure OpenAI 的整合,甚至讓完全不懂演算法的開發者也能快速上手,推薦給有興趣的人都來玩玩看!
系列文章
- 【Azure Cognitive Search】使用 Python SDK 在認知搜尋中進行全文檢索
- 【Azure Cognitive Search】使用 Python SDK 在認知搜尋中進行向量搜尋(上)
- 【Azure Cognitive Search】使用 Python SDK 在認知搜尋中進行向量搜尋(下)
留言
張貼留言