练习 5:使用向量

练习 5:在 Solr 中使用向量

本练习将使用我们在练习 4 中看到过的电影示例。

准备工作

请确保您已按照 tutorial-films.adoc#restart-solr 中的步骤运行 Solr。然后继续下一节。

准备向量数据

$ bin/solr create -c films

由于我们在创建集合时没有指定 ConfigSet,我们将使用 _default ConfigSet。

首先,我们需要更新我们的模式,以添加向量字段类型、用于保存向量值的字段以及一些支持字段。

$ 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.json 文件中嵌入了向量,因此让我们索引这些数据,利用我们刚刚定义的新模式字段。

$ 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 管理流式界面 运行的流式表达式示例

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 部“灰姑娘”电影,但只有 1 部在与目标向量最相似的前 50 部中(灰姑娘 3:时间扭转)。

  • 搜索类型为“动画”(animation)的电影,并通过将原始查询分数与目标向量的相似度(乘以 2 倍)相结合(求和)的方式,对前 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 功能,将向量相似度分数与其他分数结合起来

  • 搜索“哈利波特”(harry potter)电影,根据与目标向量的相似度而不是词法查询分数对结果进行排序。除了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
  • 搜索“蝙蝠侠”(batman)电影,通过结合 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。