稠密向量搜索

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

此相似性旨在作为执行余弦相似性的优化方式。为了使用它,所有向量都必须是单位长度,包括文档向量和查询向量。对非单位长度的向量使用点积可能会导致错误或搜索结果不佳。
执行余弦相似性的首选方法是将所有向量归一化为单位长度,然后使用 DOT_PRODUCT。只有在需要保留原始向量且无法预先对其归一化时,才应使用此函数。

要使用以下高级参数来自定义编解码器格式和 HNSW 算法的超参数,请确保模式编解码器工厂正在使用中。

以下是使用高级超参数配置 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

[{ "id": "1",
"vector": [1.0, 2.5, 3.7, 4.1]
},
{ "id": "2",
"vector": [1.5, 5.5, 6.7, 65.1]
}
]

XML

<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>

SolrJ

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 查询解析器

knn k-最近邻查询解析器允许根据给定字段中的索引密集向量,找到与目标向量 k-最近邻的文档。

检索到的文档的分数是到目标向量的近似距离(由索引时配置的 similarityFunction 定义)。

它采用以下参数

f

必需

默认值:无

要搜索的 DenseVectorField

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-最近邻,按索引时配置的 similarityFunction 排序。

与过滤器查询一起使用

knn 查询解析器可用于过滤器查询

&q=id:(1 2 3)&fq={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]

knn 查询解析器可与过滤器查询一起使用

&q={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]&fq=id:(1 2 3)

过滤器查询作为预过滤器执行:主查询细化从所有过滤器查询的应用中派生的搜索结果子集,这些查询组合为“必须”子句(布尔 AND)。

这意味着在

&q=id:(1 2 3)&fq={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]

结果由 topK knn 检索预先过滤,然后仅返回与查询“q=id:(1 2 3)”匹配的此子集中的文档。

&q={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]&fq=id:(1 2 3)

结果由 fq=id:(1 2 3) 预先过滤,然后仅将此子集中的文档视为 topK knn 检索的候选者。

如果您想将某些过滤器查询作为后置过滤器运行,则可以使用 Apache Solr 中的后置过滤标准方法,使用缓存和成本本地参数。

例如

&q={!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]&fq={!frange cache=false l=0.99}$q

作为重新排序查询使用

knn 查询解析器可用于重新对第一遍查询结果进行排序

&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)。

有关使用重新排序查询解析器的详细信息,请参阅 查询重新排序 部分。