稠密向量搜尋

Solr 的稠密向量搜尋新增了對索引和搜尋稠密數值向量的支援。

深度學習可用於產生資訊語料庫中查詢和文件的向量表示。

這些基於神經網路的技術通常稱為神經搜尋,是學術領域神經資訊檢索的產業衍生。

重要概念

稠密向量表示

傳統的符號化 反向索引可以被認為是將文字建模為「稀疏」向量,其中語料庫中的每個詞彙都對應一個向量維度。在這種模型中,維度的數量通常相當高(對應於詞彙表基數),而且任何給定文件的向量都大多包含零(因此它是稀疏的,因為只有少數存在於整體索引中的詞彙會出現在任何給定文件中)。

稠密向量表示與基於詞彙的稀疏向量表示相反,它將近似語義意義提煉成固定(且有限)數量的維度。

這種方法的維度數量通常比稀疏情況少得多,並且任何給定文件的向量都是稠密的,因為它的大部分維度都由非零值填充。

與稀疏方法(使用分詞器直接從文字輸入產生稀疏向量)不同,產生向量的任務必須在 Apache Solr 外部的應用程式邏輯中處理。

在某些情況下,直接搜尋本來就以向量形式存在的資料(例如,科學資料)可能是有意義的;但在文字搜尋上下文中,使用者可能會利用深度學習模型(例如 BERT)將文字資訊編碼為稠密向量,在索引和查詢時明確地將產生的向量提供給 Apache Solr。

如需更多資訊,您可以參考這篇部落格文章

稠密檢索

給定一個模擬資訊需求的稠密向量 v,提供稠密向量檢索最簡單的方法是計算 v 與每個代表資訊語料庫中文件的向量 d 之間的距離(歐氏距離、點積等)。

這種方法非常耗費資源,因此目前許多近似策略正在積極研究中。

Apache Lucene 中實作並由 Apache Solr 使用的策略基於可導航的小世界圖。

它為高維向量提供高效的近似最近鄰搜尋。

索引時間

這是 Apache Solr 設計用於支援稠密向量搜尋的欄位類型

DenseVectorField

稠密向量欄位可以索引和搜尋浮點元素的稠密向量。

例如

[1.0, 2.5, 3.7, 4.1]

以下是在架構中應如何設定 DenseVectorField

<fieldType name="knn_vector" class="solr.DenseVectorField" vectorDimension="4" similarityFunction="cosine"/>
<field name="vector" type="knn_vector" indexed="true" stored="true"/>
vectorDimension

必要

預設值:無

要傳入的稠密向量的維度。

接受的值:任何整數。

similarityFunction

選用

預設值:euclidean

向量相似度函式;用於搜尋以傳回與目標向量最相似的前 K 個向量。

可接受的值:euclideandot_productcosine

此相似度旨在作為執行餘弦相似度的最佳化方法。為了使用它,所有向量必須是單位長度,包括文件和查詢向量。對非單位長度的向量使用點積可能會導致錯誤或不良的搜尋結果。
Solr 返回的餘弦相似度分數會像這樣正規化:(1 + cosine_similarity) / 2
執行餘弦相似度的首選方法是將所有向量正規化為單位長度,然後改用 DOT_PRODUCT。只有在您需要保留原始向量且無法預先正規化它們時,才應使用此函數。

若要使用以下自訂編碼格式和 HNSW 演算法超參數的高階參數,請確保正在使用Schema Codec Factory

以下是如何使用高階超參數設定 DenseVectorField 的方法

<fieldType name="knn_vector" class="solr.DenseVectorField" vectorDimension="4" similarityFunction="cosine" knnAlgorithm="hnsw" hnswMaxConnections="10" hnswBeamWidth="40"/>
<field name="vector" type="knn_vector" indexed="true" stored="true"/>
knnAlgorithm

選用

預設值:hnsw

(高階) 指定要使用的底層 knn 演算法

可接受的值:hnsw

請注意,knnAlgorithm 可接受的值在未來版本中可能會變更。

vectorEncoding

選用

預設值:FLOAT32

(高階) 指定密集向量元素的底層編碼。這會影響索引和儲存欄位(如果已啟用)的記憶體/磁碟影響

可接受的值:FLOAT32BYTE

hnswMaxConnections

選用

預設值:16

(高階) 此參數專用於 hnsw knn 演算法

控制有多少個最近鄰居候選連接到新節點。

它的含義與 2018 年論文中的 M 相同。

接受的值:任何整數。

hnswBeamWidth

選用

預設值:100

(高階) 此參數專用於 hnsw knn 演算法

它是搜尋圖形以尋找每個新插入節點時要追蹤的最近鄰居候選數量。

它的含義與 2018 年論文中的 efConstruction 相同。

接受的值:任何整數。

DenseVectorField 支援以下屬性:indexedstored

目前不支援多值

以下是如何索引 DenseVectorField 的方法

  • JSON

  • XML

  • SolrJ

[{ "id": "1",
"vector": [1.0, 2.5, 3.7, 4.1]
},
{ "id": "2",
"vector": [1.5, 5.5, 6.7, 65.1]
}
]
<add>
<doc>
<field name="id">1</field>
<field name="vector">1.0</field>
<field name="vector">2.5</field>
<field name="vector">3.7</field>
<field name="vector">4.1</field>
</doc>
<doc>
<field name="id">2</field>
<field name="vector">1.5</field>
<field name="vector">5.5</field>
<field name="vector">6.7</field>
<field name="vector">65.1</field>
</doc>
</add>
final SolrClient client = getSolrClient();

final SolrInputDocument d1 = new SolrInputDocument();
d1.setField("id", "1");
d1.setField("vector", Arrays.asList(1.0f, 2.5f, 3.7f, 4.1f));


final SolrInputDocument d2 = new SolrInputDocument();
d2.setField("id", "2");
d2.setField("vector", Arrays.asList(1.5f, 5.5f, 6.7f, 65.1f));

client.add(Arrays.asList(d1, d2));

查詢時間

Apache Solr 提供兩個適用於密集向量欄位的查詢解析器,每個解析器都支援基於向量相似度來比對文件的方式:knn 查詢解析器和 vectorSimilarity 查詢解析器。

兩個解析器都會針對擷取的文件傳回分數,這些分數是與目標向量的近似距離(由索引時設定的 similarityFunction 定義),而且都支援「預先篩選」文件圖形,以減少評估的候選向量數量(無需計算其向量相似度距離)。

兩個查詢解析器的通用參數如下

f

必要

預設值:無

要搜尋的 DenseVectorField

preFilter

選用

預設值:取決於使用情況,請參閱下文。

指定要使用的預先篩選查詢字串的明確清單。

includeTags

選用

預設值:無

表示只有具有指定 tagfq 篩選器才應被考慮用於隱式預先篩選。不得與 preFilter 組合使用。

excludeTags

選用

預設值:無

表示應將具有指定 tagfq 篩選器排除在隱式預先篩選的考慮之外。不得與 preFilter 組合使用。

knn 查詢解析器

knn k 最近鄰居查詢解析器會將 k 個最近的文件比對到目標向量。

除了上述的通用參數之外,它還接受以下參數

topK

選用

預設值:10

要傳回多少個 k 個最近的結果。

以下是簡單 knn 搜尋的範例

?q={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]

擷取的搜尋結果是輸入 [1.0, 2.0, 3.0, 4.0] 中向量的 k=10 個最近的文件,按索引時設定的 similarityFunction 排序。

vectorSimilarity 查詢解析器

vectorSimilarity 向量相似度查詢解析器會比對與目標向量的相似度高於最小閾值的文件。

除了上述的通用參數之外,它還接受以下參數

minReturn

必要

預設值:無

圖形中要傳回為符合項的節點的最小相似度閾值

minTraverse

選用

預設值:-Infinity

圖形中節點的最小相似度,以繼續追蹤其鄰居

以下是簡單 vectorSimilarity 搜尋的範例

?q={!vectorSimilarity f=vector minReturn=0.7}[1.0, 2.0, 3.0, 4.0]

擷取的搜尋結果是所有與輸入向量 [1.0, 2.0, 3.0, 4.0] 的相似度至少為 0.7 的文件,基於索引時設定的 similarityFunction

圖形預先篩選

當走訪圖形時,可以明確或隱式(基於現有的 fq 參數)指定考慮的候選文件集合的預先篩選,具體取決於使用這些密集向量查詢解析器的方式和時間。

明確預先篩選

可以明確指定 preFilter 參數,以減少評估距離計算的候選文件數量

?q={!vectorSimilarity f=vector minReturn=0.7 preFilter=inStock:true}[1.0, 2.0, 3.0, 4.0]

在上面的範例中,只有符合預先篩選 inStock:true 的文件才會在評估針對指定向量的 vectorSimilarity 搜尋時被考慮為候選。

preFilter 參數可以是空白的(例如:preFilter=""),表示不應執行預先篩選;或可以是多值的,透過重複或透過重複的 參數參考

這兩個範例是等效的

?q={!knn f=vector topK=10 preFilter=category:AAA preFilter=inStock:true}[1.0, 2.0, 3.0, 4.0]
?q={!knn f=vector topK=10 preFilter=$knnPreFilter}[1.0, 2.0, 3.0, 4.0]
&knnPreFilter=category:AAA
&knnPreFilter=inStock:true

隱式預先篩選

雖然可以在 knnvectorSimilarity 查詢解析器的任何用法上明確指定 preFilter 參數,但預設的預先篩選行為(未指定 preFilter 參數時)會根據查詢解析器的使用方式而有所不同

  • 當用作主要的 q 參數時:請求中的 fq 篩選器(不是 Solr Post 篩選器)將會組合以形成隱式圖形預先篩選。

    • 此預設行為會最佳化考慮的向量距離計算數量,消除無論如何都會被 fq 篩選器排除的文件。

    • includeTagsexcludeTags 可用於限制預先篩選中使用的 fq 篩選器集合。

  • 當向量搜尋查詢解析器用作 fq 參數或較大查詢中的子查詢子句時:不會使用隱式預先篩選。

    • 在這些情況下,不得使用 includeTagsexcludeTags

下面的範例請求顯示了向量查詢解析器的兩種用法,它們不會從任何 fq 參數取得任何隱式預先篩選,因為這兩種用法都不是主要 q 參數。

?q=(color_str:red OR {!vectorSimilarity f=color_vector minReturn=0.7 v="[1.0, 2.0, 3.0, 4.0]"})
&fq={!knn f=title_vector topK=10}[9.0, 8.0, 7.0, 6.0]
&fq=inStock:true

但是,下一個範例顯示了一個基本請求,其中所有 fq 參數都將用作主要 knn 查詢的隱式預先篩選器

?q={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]
&fq=category:AAA
&fq=inStock:true

如果我們修改上述請求以將標籤新增至 fq 參數,我們可以在 knn 解析器上指定 includeTags 選項,以限制哪些 fq 篩選器用於預先篩選

?q={!knn f=vector topK=10 includeTags=for_knn}[1.0, 2.0, 3.0, 4.0]
&fq=category:AAA
&fq={!tag=for_knn}inStock:true

在本範例中,只會使用 inStock:true 篩選器進行預先篩選,以尋找 topK=10 個文件,並且會獨立套用 category:AAA 篩選器;可能會導致少於 10 個符合項。

某些使用案例中,includeTags 和/或 excludeTags 可能比明確的 preFilter 參數更有用

  • 您有一些 在許多請求中重複使用的 fq 參數(即使您不使用搜尋密集向量欄位),您希望在確實搜尋密集向量欄位時將其用作預先篩選器。

  • 您通常希望所有 fq 參數都用作 knn 查詢中的圖形預先篩選器,但是當使用者「向下鑽取」刻面時,您希望排除新增的 fq 參數,以便結果集變小;而不是只計算新的 topK 集合。

在重新排序查詢中的用法

兩種密集向量搜尋查詢解析器都可用於重新排序第一遍查詢結果

&q=id:(3 4 9 2)&rq={!rerank reRankQuery=$rqq reRankDocs=4 reRankWeight=1}&rqq={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]

在重新排序中使用 knn 時,請注意 topK 參數。

只有當第一遍中的文件 d 位於要搜尋的目標向量的 k 個最近鄰居(在整個索引中)時,才會計算第二遍分數(來自 knn)。

這表示第二遍 knn 無論如何都會在整個索引上執行,這是目前的限制。

最終排序的結果清單會將第一遍分數(主要查詢 q)加上第二遍分數(與要搜尋的目標向量的近似 similarityFunction 距離)乘以一個乘法因子 (reRankWeight)。

有關使用重新排序查詢解析器的詳細資訊,請參閱查詢重新排序章節。