練習 5:使用向量

練習 5:在 Solr 中使用向量

此練習將使用我們先前在練習 4 中看過的 Films 範例。

準備工作

請確保您已執行 Solr,並依照 tutorial-films.adoc#restart-solr 中的步驟進行。然後繼續到下一節。

準備向量資料

$ bin/solr create -c films

由於我們在建立集合時未指定 ConfigSet,因此我們將使用 _default ConfigSet。

首先,我們需要更新我們的 schema,以新增向量欄位類型、用於保存向量值的欄位,以及一些支援欄位。

$ curl https://127.0.0.1:8983/solr/films/schema -X POST -H 'Content-type:application/json' --data-binary '{
  "add-field-type" : {
    "name":"knn_vector_10",
    "class":"solr.DenseVectorField",
    "vectorDimension":10,
    "similarityFunction":"cosine",
    "knnAlgorithm":"hnsw"
  },
  "add-field" : [
      {
        "name":"film_vector",
        "type":"knn_vector_10",
        "indexed":true,
        "stored":true
      },
      {
        "name":"name",
        "type":"text_general",
        "multiValued":false,
        "stored":true
      },
      {
        "name":"initial_release_date",
        "type":"pdate",
        "stored":true
      }
    ]
}'

現在使用向量索引 Films 資料

我們的向量已嵌入在 films.json 檔案中,因此讓我們索引該資料,並利用我們剛剛定義的新 schema 欄位。

$ bin/solr post -c films example/films/films.json

讓我們進行一些向量搜尋

在進行查詢之前,我們先定義一個範例目標向量,模擬一個看過 3 部電影的人:海底總動員蜂電影哈利波特與密室。我們取得每部電影的向量,然後計算出平均向量,這將用作所有以下範例查詢的輸入向量。

[-0.1784, 0.0096, -0.1455, 0.4167, -0.1148, -0.0053, -0.0651, -0.0415, 0.0859, -0.1789]

有興趣使用 Solr 的 串流功能計算向量嗎?以下是一個串流表示式的範例,您可以使用 Solr 管理串流 UI 執行

let(
  a=select(
        search(films,
          qt="/select",
          q="name:"Finding Nemo" OR name:"Bee Movie" OR name:"Harry Potter and the Chamber of Secrets"",
          fl="id,name,film_vector"),
        film_vector),
  b=col(a, film_vector),
  m=matrix(valueAt(b, 0), valueAt(b, 1), valueAt(b, 2)),
  average=scalarDivide(3, sumColumns(m))
  )

輸出為

{
  "result-set": {
    "docs": [
      {
        "average": [
          -0.17840398,
          0.00960978666666667,
          -0.14545916333333334,
          0.41671050333333337,
          -0.11476575433333332,
          -0.005306495043333334,
          -0.06507552800000001,
          -0.041544396666666664,
          0.085892911,
          -0.1788737366666667
        ]
      },
      {
        "EOF": true,
        "RESPONSE_TIME": 129
      }
    ]
  }
}

搜尋與我們先前計算的目標向量最相似的前 10 部電影(用於推薦的 KNN 查詢)

'https://127.0.0.1:8983/solr/films/query?q={%21knn%20f=film_vector%20topK=10}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]'
  • 請注意,在結果中,有一些動畫家庭電影,例如好奇的喬治小鹿斑比,這很合理,因為目標向量是使用另外兩部動畫家庭電影(海底總動員蜂電影)建立的。

  • 我們也注意到結果中有兩部電影是該人員已經看過的。在下一個範例中,我們將它們過濾掉。

搜尋與結果向量最相似的前 10 部電影,排除已經看過的電影(使用過濾查詢的 KNN 查詢)。

https://127.0.0.1:8983/solr/films/query?q={!knn%20f=film_vector%20topK=10}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]&fq=-id:("%2Fen%2Ffinding_nemo"%20"%2Fen%2Fbee_movie"%20"%2Fen%2Fharry_potter_and_the_chamber_of_secrets_2002")
  • 在與目標向量最相似的前 50 部電影中,搜尋名稱包含「cinderella」的電影(使用 KNN 作為過濾查詢)。

    https://127.0.0.1:8983/solr/films/query?q=name:cinderella&fq={!knn%20f=film_vector%20topK=50}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]
    • 索引中有 3 部「cinderella」電影,但只有 1 部在前 50 部與目標向量最相似的電影中(仙履奇緣 III:時間的扭曲)。

  • 搜尋類型為「動畫」的電影,並透過將原始查詢分數與目標向量相似度的兩倍 (2x) 相加,重新排序前 5 個文件(使用重新排序的 KNN)。

    https://127.0.0.1:8983/solr/films/query?q=genre:animation&rqq={!knn%20f=film_vector%20topK=10000}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]&rq={!rerank%20reRankQuery=$rqq%20reRankDocs=5%20reRankWeight=2}
    • 為了確保我們計算所有電影的向量相似度分數,我們將 topK=10000,這個數字高於文件總數 (1100)。

    • 透過使用子查詢、函數查詢參數解引用 Solr 功能,可以將向量相似度分數與其他分數結合。

  • 搜尋「哈利波特」電影,根據與目標向量的相似度而不是詞彙查詢分數對結果進行排序。除了 q 參數外,我們定義了一個名為 q_vector 的「子查詢」,它將計算所有電影之間的相似度分數(因為我們設定了 topK=10000)。然後我們使用子查詢參數名稱作為 sort 的輸入,指定我們要根據向量相似度分數降序排列 (sort=$q_vector desc)。

    https://127.0.0.1:8983/solr/films/query?q=name:"harry%20potter"&q_vector={!knn%20f=film_vector%20topK=10000}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]&sort=$q_vector%20desc
  • 搜尋名稱中包含「the」的電影,保留原始的詞彙查詢排名,但僅返回與目標向量的相似度為 0.8 或更高的電影。與先前一樣,我們定義了子查詢 q_vector,但這次我們將其用作 frange 過濾器的輸入,指定我們想要向量相似度分數至少為 0.8 的文件。

    https://127.0.0.1:8983/solr/films/query?q=name:the&q_vector={!knn%20f=film_vector%20topK=10000}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]&fq={!frange%20l=0.8}$q_vector
  • 搜尋「蝙蝠俠」電影,透過將原始詞彙查詢分數的 70% 和與目標向量相似度的 30% 相結合,對結果進行排序。除了 q 主要查詢和 q_vector 子查詢之外,我們還指定了 q_lexical 查詢,它將保留主要 q 查詢的詞彙分數。然後我們指定一個名為 score_combined 的參數變數,該變數會縮放詞彙和相似度分數,應用 0.7 和 0.3 的權重,然後將結果相加。我們將 sort 參數設定為根據組合分數排序,並設定 fl 參數,以便我們可以在回應中查看中間值和組合分數值。

    https://127.0.0.1:8983/solr/films/query?q=name:batman&q_lexical={!edismax%20v=$q}&q_vector={!knn%20f=film_vector%20topK=10000}[-0.1784,0.0096,-0.1455,0.4167,-0.1148,-0.0053,-0.0651,-0.0415,0.0859,-0.1789]&score_combined=sum(mul(scale($q_lexical,0,1),0.7),mul(scale($q_vector,0,1),0.3))&sort=$score_combined%20desc&fl=name,score,$q_lexical,$q_vector,$score_combined

練習 5 總結

在本練習中,我們使用 Schema API 來新增向量欄位,然後學習如何使用向量資料結構來索引和查詢 Solr。