当传统的关键词搜索无法满足语义理解、商品推荐或以图搜图等复杂应用场景时,您需要一种更为先进的相似性搜索技术。PolarSearch的向量检索功能通过将文本、图像等非结构化数据转化为多维向量,能够在海量数据中快速而精准地找到与查询目标最为相似的结果,从而有效提升应用的智能化水平。
功能简介
向量检索,也称为相似性搜索,是一种通过比较向量之间的“距离”来查找最相似数据的技术,它与依赖精确关键词匹配的传统搜索有着本质区别。
它的核心思想是将现实世界中的文本、图像、音频等非结构化数据,通过深度学习模型(如LLM)转换为向量嵌入(Embedding) 的数值表示。这些多维向量能够捕捉数据的深层语义信息。
当您发起一次查询时,PolarSearch会将您的查询内容同样转换为向量,然后执行k-最近邻(k-Nearest Neighbor, k-NN)搜索。这是一种核心算法,其目标是在海量数据中找到与您的查询向量“距离”最近的k个向量。这里的k是一个由您定义的数字(例如,当k=5时,即代表查找最相似的5个结果)。最终,PolarSearch会返回这k个最相似的结果。
为实现高效检索,PolarSearch依赖两大核心组件:向量索引和向量存储优化。
向量索引:为了避免在海量数据中进行全量计算,需要预先建立向量索引。索引能够根据向量数据的特征构建一种为查询而优化的数据结构,在查询时能够大幅缩小搜索范围,从而显著提升检索性能。PolarSearch内支持了多种类型的向量索引,以下为您主要介绍业界主流的HNSW和IVF索引:
HNSW (Hierarchical Navigable Small World):一种基于图的索引,具有高性能和高召回率的优点,但内存开销也相应较大。适用于对查询延迟和精度要求极高,且数据集大小在内存容量范围内的场景。
IVF (Inverted File):一种基于聚类的倒排索引,内存占用较低,更适合需要处理超大规模数据集且内存受限的场景,但其搜索精度通常略低于HNSW。
向量存储优化:向量数据,尤其是高维向量,会占用大量内存和存储空间。PolarSearch提供多种优化技术来降低资源消耗。
向量量化:通过降低向量数值的精度来压缩数据,显著减少空间占用,是一种在压缩率和精度之间取得平衡的技术。PolarSearch支持乘积量化(PQ)、标量量化(SQ)和二值量化(BQ)。
基于磁盘的存储:对于低内存环境,允许将部分索引数据存储在磁盘上,以较低的内存成本运行向量检索服务,代价是会适当增加查询延迟。
注意事项
在使用PolarSearch向量检索功能时,请您注意以下几点:
索引训练要求:
IVF
索引和PQ
(乘积量化)技术在使用前需要一个独立的训练步骤。您需要提供一部分具有代表性的向量数据来训练模型,否则索引无法正常工作。内存开销:
HNSW
索引虽然性能优异,但其图结构需要完全加载到内存中,会产生较高的内存开销。请在选择前评估您的集群内存资源。性能与成本权衡:基于磁盘的向量搜索会适当增加查询延迟,请根据您的业务场景进行评估。
自动训练:二值量化(BQ)的训练过程在索引构建期间自动处理,您无需进行额外的训练操作。
操作指南
要使用PolarSearch向量检索,您需要先创建一个配置好的向量检索的索引。以下是关键步骤与参数配置说明。
1. 启用k-NN并定义向量字段
在创建索引时,您需要将index.knn
设置为true
来启用k-NN搜索,并定义一个knn_vector
类型的字段用于存储向量。
核心参数
engine
:固定为faiss。说明Faiss (Facebook AI Similarity Search) 是一个由Meta AI开发的高性能开源库,专门用于高效的相似度搜索和海量向量数据聚类,PolarSearch使用Faiss作为其核心向量检索引擎。
dimension
:用于指定向量的维度,需要与您模型产出的向量维度完全一致。data_type
:定义向量的数据类型。默认为float
,您也可以选择byte
或binary
以优化存储。space_type
:定义向量相似度的计算方式(距离度量)。支持的范围如下:space_type
距离度量
说明
l2
L2(欧几里得距离)
计算平方差和的平方根,对数值大小敏感。
l1
L1(曼哈顿距离)
对向量各维度差值的绝对值求和。
cosinesimil
余弦相似度
测量向量间的夹角,更关注方向而非大小。
innerproduct
内积
计算向量点积,常用于排序场景。
hamming
汉明距离
计算二进制向量中不同元素的数量。
chebyshev
L∞(切比雪夫距离)
仅考虑向量各维度差值绝对值的最大值。
2. 选择并配置索引方法(HNSW或IVF)
选型建议
HNSW和IVF在性能、资源消耗和精度上各有侧重,适用于不同的业务场景。您可以参考下表进行快速选型:
对比维度 | HNSW | IVF |
查询延迟 | 极低。通过层级化的图结构快速定位,搜索路径短。 | 较低。需要先定位到簇,再在簇内搜索,路径相对较长。 |
召回率(精度) | 高。图的连接性更好,不容易漏掉近邻点。 | 中到高。存在边缘效应(查询点在簇的边界),可能损失一定精度,可通过调整 |
内存占用 | 高。需要将完整的图结构加载到内存中。 | 低。主要存储聚类中心和倒排列表,内存开销远低于HNSW。 |
构建时间 | 较长。构建高质量的图结构需要复杂的计算。 | 较快。但需要一个额外的训练步骤来生成聚类中心。 |
适用场景 | 对查询性能和精度有极致要求,且内存资源充足的场景。例如:实时语义搜索、人脸识别。 | 数据集规模巨大,内存资源受限,且可以接受微小精度损失的成本敏感型场景。例如:海量商品推荐、大规模图片库检索。 |
操作说明
在method
中配置索引的具体实现方法和参数。
HNSW
HNSW通过IndexHNSWFlat
实现,适用于对性能和召回率有高要求的场景。
核心参数
参数 | 取值范围 | 说明 |
| 正整数。 | 图中每个节点的最大邻居(出度)数量。此值决定了图的密度,且是影响索引质量和内存占用的最关键参数。
|
| 正整数,且通常应大于 | 构建索引时,动态邻居列表的大小。它控制了构建图期间的搜索深度和广度。此值主要影响索引的构建时间和最终质量。
|
| 正整数。 | 查询时,动态邻居列表的大小。它控制了查询期间的搜索深度。 说明 此参数不在创建索引时指定,而是在查询时或在索引的
|
实际创建HNSW索引时,请将下述<my-hnsw-index>
替换为您的索引名称,<my_vector_field>
替换为您的字段名称。同时,其他核心参数dimension
、data_type
、space_type
、m
以及ef_construction
等参数请根据实际业务需求配置。
// HNSW索引创建示例,请将<my-hnsw-index>替换为您的实际的索引名称
PUT /<my-hnsw-index>
{
"settings": {
"index": {
"knn": true
}
},
"mappings": {
"properties": {
"<my_vector_field>": {//请将<my_vector_field>替换为您的实际的字段名称
"type": "knn_vector",
"dimension": 128,
"data_type": "float",
"method": {
"name": "hnsw",
"engine": "faiss",
"space_type": "l2",
"parameters": {
"m": 16,
"ef_construction": 256,
"ef_search": 512 // ef_search通常在查询时指定,此处为示例
}
}
}
}
}
}
IVF
IVF通过IndexIVFFlat
实现,适用于内存受限的超大规模数据集场景。
核心参数
参数 | 取值范围 | 说明 |
| 正整数。 | 聚类中心的数量。索引会将整个向量空间划分为
|
| 正整数,且通常应小于 | 查询时,需要搜索的聚类中心(簇)的数量。此值是在查询速度和召回率之间进行权衡的最直接参数。
|
实际创建IVF索引时,请将下述<my-ivf-index>
替换为您的索引名称,<my_vector_field>
替换为您的字段名称。同时,其他核心参数dimension
、data_type
、space_type
、nlist
、nprobes
等参数请根据实际业务需求配置。
// IVF索引创建示例,请将<my-ivf-index>替换为您的实际的索引名称
PUT /<my-ivf-index>
{
"settings": {
"index": {
"knn": true
}
},
"mappings": {
"properties": {
"<my_vector_field>": {// 请将<my_vector_field>替换为您的实际的字段名称
"type": "knn_vector",
"dimension": 4,
"data_type": "byte",
"method": {
"name": "ivf",
"engine": "faiss",
"space_type": "l2",
"parameters": {
"nlist": 1024,
"nprobes": 10 // nprobes通常在查询时指定,此处为示例
}
}
}
}
}
}
3. (可选)配置存储优化
向量数据,尤其是高维浮点型向量,会占用大量内存。PolarSearch提供多种存储优化技术,通过对向量进行压缩(量化)或改变存储介质,在内存成本、查询性能和搜索精度之间取得平衡。
选型建议
在选择具体的优化策略前,您可以参考下表,快速找到最适合您业务场景的方案。
优化策略 | 压缩率 | 精度影响 | 训练要求 | CPU开销 | 适用场景 |
标量量化 (SQ) | 低 (固定2倍) | 极小 | 无需训练 | 低 | 对搜索精度要求极高,希望在几乎不损失精度的前提下,获得适度内存优化的场景。 |
二值量化 (BQ) | 高 (8-32倍) | 较大 | 无需训练 | 中等 | 对内存极度敏感,可以接受一定(甚至较大)精度损失,以换取最大程度内存节省的场景。 |
乘积量化 (PQ) | 最高 | 中等 | 需要训练 | 中等 | 数据集巨大,需要极致的压缩率,且愿意投入时间进行模型训练以平衡精度和内存的场景。 |
基于磁盘的向量存储 | - | 较大 | 无需训练 | 较高 | 内存资源极其有限,宁愿牺牲查询延迟(因磁盘I/O),也要将内存占用降至最低的成本敏感型场景。 |
操作说明
标量量化(SQ)
工作原理:将标准的32位浮点(float)向量转换为16位浮点(fp16)向量进行存储,使内存占用直接减半。在计算距离时,会解码回32位进行,因此对精度的影响非常小。
内存估算:
公式:
内存 (GB) ≈ 1.1 * (2 * dimension + 8 * m) * num_vectors / 1024^3
参数详解:
dimension
:向量的维度。m
:HNSW索引中的m
参数,即每个节点的最大邻居数。num_vectors
:向量总数。1.1
:约10%的系统开销系数。
示例:假设您有 100 万个向量,每个向量的维度为 256,每个向量的维度
m
为 16。内存需求可以估算如下:1.1 * (2 * 256 + 8 * 16) * 1,000,000 ~= 0.656 GB
使用示例:
// HNSW + 标量量化(SQ)示例 PUT /<my-sq-index> { "settings": { "index": { "knn": true } }, "mappings": { "properties": { "<my_vector_field>": { "type": "knn_vector", "dimension": 128, "method": { "name": "hnsw", "engine": "faiss", "parameters": { "m": 16, "ef_construction": 256, "encoder": {// 启用SQ "name": "fp16" } } } } } } }
二值量化(BQ)
工作原理:将浮点向量的每个维度压缩为二进制位(0和1)进行存储,从而实现极高的压缩率。训练过程在索引构建时自动完成。
内存估算:
公式:
内存 (GB) ≈ 1.1 * ((dimension * bits / 8) + 8 * m) * num_vectors / 1024^3
参数详解:
dimension
:向量的维度。bits
:每个维度用多少个二进制位表示,可选值为1,2,4。bits
越小,压缩率越高,但精度损失越大。m
:HNSW索引中的m
参数。num_vectors
:向量总数。
示例:假设您有100万个向量,每个向量的维度为256,每个向量的维度
m
为16。以下部分提供了各种压缩值对内存需求的估算。1位量化(32倍压缩):在1位量化中,每个维度用1位表示,相当于32倍压缩系数。内存需求可以估算如下:
1.1 * ((256 * 1 / 8) + 8 * 16) * 1,000,000 ~= 0.176 GB
2位量化(16倍压缩):在2位量化中,每个维度用2位表示,相当于16倍压缩系数。内存需求可以估算如下:
1.1 * ((256 * 2 / 8) + 8 * 16) * 1,000,000 ~= 0.211 GB
使用示例:
// HNSW + 二值量化(BQ)示例 PUT /<my-bq-index> { "settings" : { "index": { "knn": true } }, "mappings": { "properties": { "<my_vector_field>": { "type": "knn_vector", "dimension": 128, "method": { "name": "hnsw", "engine": "faiss", "parameters": { "m": 16, "ef_construction": 512, "encoder": { "name": "binary", "parameters": {// 启用BQ,使用1位量化 "bits": 1 } } } } } } } }
乘积量化(PQ)
PQ是一种先进的向量压缩技术,它能实现比SQ或BQ更高的压缩率,但代价是需要一个独立的训练步骤来构建压缩模型。
工作原理:
向量切分:首先,将一个原始的高维向量(例如256维)切分为
m
个等长的低维子向量。例如,将256维向量按m=32
切分,会得到32个8维的子向量。码本训练:接着,系统会为每一个子向量空间独立学习一个“码本”(Codebook)。这个码本包含
2^code_size
个中心点(也称质心)。这个训练过程通常使用K-均值聚类算法完成。量化编码:训练完成后,在对新向量进行编码时,其每个子向量不再存储原始的浮点值,而是被替换为该子向量空间码本中距离它最近的那个中心点的ID。如果
code_size
为8,则ID范围是0-255,正好用1个字节存储。最终结果:一个原始向量就被转换成了一组中心点ID的序列,从而实现了极高的压缩。
训练要求:PQ的性能严重依赖于训练数据的质量。您必须提供一组与您最终要检索的数据分布相似的向量来进行训练。
训练数据来源:可以是您要索引的向量数据的子集。
建议的训练数据量:
结合HNSW使用时:建议训练向量数量为
2^code_size * 1000
。结合IVF使用时:建议训练向量数量为
max(1000 * nlist, 2^code_size * 1000)
。
内存估算:以HNSW+PQ为例。因为当HNSW与PQ结合使用时,其内存计算公式较为复杂,因为它包含了压缩向量、HNSW图结构和PQ码本三部分的开销。
公式:
内存 (字节) ≈ 1.1 * ( (per_vector_cost) * num_vectors + (codebook_cost) )
per_vector_cost = (pq_code_size / 8 * pq_m) + 24 + (8 * hnsw_m)
codebook_cost = num_segments * (2^pq_code_size) * 4 * dimension
参数详解:
num_vectors
:向量总数。dimension
:原始向量的维度。pq_m
:向量切分的段数。dimension
必须能被pq_m
整除。pq_code_size
:每个子向量码本的大小,以比特为单位。通常为8。hnsw_m
:HNSW索引中的m
参数,即每个节点的最大邻居数。num_segments
:一个底层技术参数,代表索引被分成的段数。在估算时可以按集群分片数或一个保守值(如100)来计算。1.1
:约10%的系统开销系数。24
和8
:HNSW图结构中每个节点的固定开销和指针开销。4
:代表码本中的中心点坐标使用32位浮点数(4字节)存储。
示例:假设您有100万个向量(
num_vectors
),每个向量的维度(dimension
)为256,每个向量切分段数(pq_m
)为32,每个子向量码本的大小(pq_code_size
)为8,HNSW索引的m
参数为16,num_segments
为100。计算单个向量的开销(
per_vector_cost
):压缩后向量大小 = pq_code_size / 8 * pq_m = 8 / 8 * 32 = 32字节。
HNSW图开销 = 24 + 8 * hnsw_m = 24 + 8 * 16 = 152字节。
per_vector_cost = 32 + 152 = 184字节
计算码本的总开销(
codebook_cost
):codebook_cost = num_segments * (2^pq_code_size) * 4 * dimension。
codebook_cost = 100 * (2^8) * 4 * 256 = 100 * 256 * 4 * 256 = 26,214,400字节。
计算总内存:
总内存 ≈ 1.1 * (per_vector_cost * num_vectors + codebook_cost)
总内存 ≈ 1.1 * (184 * 1,000,000 + 26,214,400) ≈ 231,235,840 字节 ≈ 0.215 GB
使用示例:
// HNSW + 乘积量化(PQ)示例 PUT /<my-hnswpq-index> { "settings" : { "index": { "knn": true } }, "mappings": { "properties": { "<my_vector_field>": { "type": "knn_vector", "dimension": 128, // 维度必须能被 m 整除 "method": { "name": "hnsw", "engine": "faiss", "parameters": { "m": 16, // HNSW的m参数 "ef_construction": 512, "encoder": { "name": "pq", "parameters": { "m": 4, // PQ的m参数:将128维切为4段32维 "code_size": 8 } } } } } } } }
基于磁盘的向量存储
工作原理:基于磁盘的向量搜索是利用内部的量化技术压缩向量,并将主要的图结构存储在磁盘上,而不是堆内存中。这种内存优化可以大幅节省内存,但搜索延迟会略有增加,同时仍能保持较高的召回率。
内存估算:无固定公式。实际物理内存占用由操作系统根据访问模式动态管理。
使用示例:
// 基于磁盘存储的示例 PUT /<my-ondisk-index> { "settings" : { "index": { "knn": true } }, "mappings": { "properties": { "<my_vector_field>": { "type": "knn_vector", "dimension": 128, "mode": "on_disk" // 启用基于磁盘的模式 } } } }