方法和引擎

_方法_定义了在索引时组织向量数据并在搜索时进行搜索的算法,用于 近似 k-NN 搜索

UDB-SX 支持以下方法:

_引擎_是实现这些方法的库。不同的引擎可以实现相同的方法,有时具有不同的优化或特性。例如,所有支持的引擎都实现了 HNSW,每个引擎都有自己的优势。

UDB-SX 支持以下引擎:

  • Lucene:原生搜索库,提供具有高效过滤功能的 HNSW 实现

  • Faiss(Facebook AI 相似性搜索):一个综合库,实现了 HNSW 和 IVF 方法,并提供了额外的向量压缩选项

  • NMSLIB(非度量空间库):HNSW 的旧版实现(现已弃用)

方法定义示例

方法定义包含以下组件:

  • 方法的 name(例如,hnswivf

  • 方法构建的 space_type(例如,l2cosinesimil

  • 将实现该方法的 engine(例如,faisslucene

  • 特定于该实现的 parameters 映射

以下示例配置了一个 hnsw 方法,使用 l2 空间类型、faiss 引擎以及方法特定参数:

PUT test-index
{
  "settings": {
    "index": {
      "knn": true,
      "knn.algo_param.ef_search": 100
    }
  },
  "mappings": {
    "properties": {
      "my_vector1": {
        "type": "knn_vector",
        "dimension": 1024,
        "method": {
          "name": "hnsw",
          "space_type": "l2",
          "engine": "faiss",
          "parameters": {
            "ef_construction": 128,
            "m": 24
          }
        }
      }
    }
  }
}

并非每个方法/引擎组合都支持所有空间。有关支持的空间列表,请参阅特定引擎的部分。

通用参数

以下参数是所有方法定义通用的。

映射参数 必需 默认值 可更新 描述
name 不适用 最近邻方法。有效值为 hnswivf。并非每个引擎组合都支持所有方法。有关支持的方法列表,请参阅特定引擎的部分。
space_type l2 用于计算向量之间距离的向量空间。有效值为 l1l2linfcosinesimilinnerproducthamminghammingbit。并非每个方法/引擎组合都支持所有空间。有关支持的空间列表,请参阅特定引擎的部分。注意:此值也可以在映射的顶层指定。更多信息,请参阅 空间
engine faiss 用于索引和搜索的近似 k-NN 库。有效值为 faisslucenenmslib(已弃用)。
parameters null 用于最近邻方法的参数。更多信息,请参阅特定引擎的部分。

Lucene 引擎

Lucene 引擎直接在 Lucene 内部提供了向量搜索的原生实现。它提供高效的过滤功能,非常适合较小的部署。

支持的方法

Lucene 引擎支持以下方法。

方法名称 需要训练 支持的空间
hnsw l2cosinesimilinnerproduct

HNSW 参数

HNSW 方法支持以下参数。

参数名称 必需 默认值 可更新 描述
ef_construction 100 在 k-NN 图创建期间使用的动态列表的大小。值越高,图越精确,但索引速度越慢。
注意:Lucene 内部使用术语 beam_width,但 UDB-SX 文档为了保持一致性使用 ef_construction
m 16 为每个新元素创建的双向链接数。显著影响内存消耗。保持在 2100 之间。
注意:Lucene 内部使用术语 max_connections,但 UDB-SX 文档为了保持一致性使用 m

Lucene 的 HNSW 实现会忽略 ef_search 并将其动态设置为搜索请求中的 “k” 值。因此,在使用 Lucene 引擎时无需配置 ef_search 的设置。

示例配置

"method": {
    "name": "hnsw",
    "engine": "lucene",
    "parameters": {
        "m": 2048,
        "ef_construction": 245
    }
}

Faiss 引擎

Faiss 引擎提供高级向量索引功能,支持多种方法和编码选项,以优化内存使用和搜索性能。

支持的方法

Faiss 引擎支持以下方法。

方法名称 需要训练 支持的空间
hnsw l2innerproduct(使用 PQ 时不可用)、hamming
ivf l2innerproducthamming(UDB-SX 支持二进制向量。更多信息,请参阅 二进制 k-NN 向量)。

HNSW 参数

hnsw 方法支持以下参数。

参数名称 必需 默认值 可更新 描述
ef_search 100 在 k-NN 搜索期间使用的动态列表的大小。值越高,搜索结果越精确,但搜索速度越慢。
ef_construction 100 在 k-NN 图创建期间使用的动态列表的大小。值越高,图越精确,但索引速度越慢。
m 16 插件为每个新元素创建的双向链接数。增加和减少此值会对内存消耗产生很大影响。将此值保持在 2100 之间。
encoder flat 用于编码向量的编码器定义。编码器可以减少索引的内存占用,但会牺牲搜索精度。

IVF 参数

IVF 方法支持以下参数。

参数名称 必需 默认值 可更新 描述
nlist 4 用于分区向量的桶数。值越高可能提高精度,但也会增加内存和训练延迟。
nprobes 1 查询期间搜索的桶数。值越高,搜索结果越精确,但搜索速度越慢。
encoder flat 用于编码向量的编码器定义。

有关这些参数的更多信息,请参阅 Faiss 文档

IVF 训练要求

IVF 算法需要训练步骤。要创建使用 IVF 的索引,您需要使用 训练 API 训练一个模型,并传递 IVF 方法定义。IVF 至少需要 nlist 个训练数据点,但我们建议 您使用比这更多的数据点。训练数据可以是您计划索引的数据,也可以来自单独的数据集。

支持的编码器

您可以使用编码器来减少向量索引的内存占用,但会牺牲搜索精度。

UDB-SX 目前支持 Faiss 库中的以下编码器。

编码器名称 需要训练 描述
flat(默认) 将向量编码为浮点数组。此编码不会减少内存占用。
pq 乘积量化(Product Quantization)的缩写,PQ 是一种有损压缩技术,使用聚类将向量编码为固定字节大小,旨在最小化 k-NN 搜索精度的下降。简而言之,向量被分成 m 个子向量,然后每个子向量由训练期间生成的码本中的 code_size 代码表示。有关乘积量化的更多信息,请参阅 这篇博客文章
sq 标量量化(Scalar Quantization)的缩写。您可以使用 sq 编码器将 32 位浮点向量量化为 16 位浮点数。在 2.13 版本中,内置的 sq 编码器是 SQFP16 Faiss 编码器。该编码器以最小的精度损失减少了内存占用,并通过使用 SIMD 优化(在 x86 架构上使用 AVX2 或在 ARM64 架构上使用 Neon)提高了性能。更多信息,请参阅 Faiss 标量量化

PQ 参数

pq 编码器支持以下参数。

参数名称 必需 默认值 可更新 描述
m 1 确定将向量分割成的子向量数量。子向量彼此独立编码。向量维度必须能被 m 整除。最大值为 1,024。
code_size 8 确定用于编码子向量的比特数。最大值为 8。对于 ivf,此值必须小于或等于 8。对于 hnsw,此值必须为 8

hnsw 方法支持 UDB-SX 及更高版本的 pq 编码器。带有 hnsw 方法的 pq 编码器的 code_size 参数必须为 8

SQ 参数

sq 编码器支持以下参数。

参数名称 必需 默认值 可更新 描述
type fp16 用于将 32 位浮点向量编码为相应类型的标量量化类型。对于 fp16 编码器,向量值必须在 [-65504.0, 65504.0] 范围内。
clip false 如果为 true,则任何超出指定向量类型支持范围的向量值将被舍入到范围内。如果为 false,则如果任何向量值超出支持范围,请求将被拒绝。将 clip 设置为 true 可能会降低召回率。

更多信息和示例,请参阅 使用 Faiss 标量量化

SIMD 优化

从 2.13 版本开始,如果底层硬件支持 SIMD 指令(x64 架构上的 AVX2 和 ARM64 架构上的 Neon),UDB-SX 支持 单指令多数据(SIMD) 处理。SIMD 在 Linux 机器上默认支持,仅适用于 Faiss 引擎。SIMD 架构通过提高索引吞吐量和减少搜索延迟来提升整体性能。从 2.18 版本开始,UDB-SX 在 x64 架构上支持 AVX-512 SIMD 指令。UDB-SX 在 x64 架构上为 Intel Sapphire Rapids 或更新一代处理器支持高级 AVX-512 SIMD 指令,提高了汉明距离计算的性能。

仅当向量维度是 8 的倍数时,SIMD 优化才适用。

x64 架构

对于 x64 架构,Faiss 库的以下版本随制品一起构建和分发:

  • libopensearchknn_faiss_avx512_spr.so:包含针对新一代处理器的高级 AVX-512 SIMD 指令的 Faiss 库,可在公共云(如 AWS 的 c/m/r 7i 或更新实例)上使用。

  • libopensearchknn_faiss_avx512.so:包含 AVX-512 SIMD 指令的 Faiss 库。

  • libopensearchknn_faiss_avx2.so:包含 AVX2 SIMD 指令的 Faiss 库。

  • libopensearchknn_faiss.so:未优化的 Faiss 库,不含 SIMD 指令。

使用 Faiss 库时,性能排名如下:高级 AVX-512 > AVX-512 > AVX2 > 无优化。

如果您的硬件支持高级 AVX-512(spr),UDB-SX 会在运行时加载 libopensearchknn_faiss_avx512_spr.so 库。

如果您的硬件支持 AVX-512,UDB-SX 会在运行时加载 libopensearchknn_faiss_avx512.so 库。

如果您的硬件支持 AVX2 但不支持 AVX-512,UDB-SX 会在运行时加载 libopensearchknn_faiss_avx2.so 库。

要禁用高级 AVX-512(针对 Sapphire Rapids 或更新一代处理器)、AVX-512 和 AVX2 SIMD 指令并加载未优化的 Faiss 库(libopensearchknn_faiss.so),请在 opensearch.yml 中将 knn.faiss.avx512_spr.disabledknn.faiss.avx512.disabledknn.faiss.avx2.disabled 静态设置指定为 true(默认情况下,所有这些都设置为 false)。

请注意,更新静态设置需要停止集群,更改设置,然后重新启动集群。

ARM64 架构

对于 ARM64 架构,仅构建和分发一个性能提升的 Faiss 库(libopensearchknn_faiss.so)。该库包含 Neon SIMD 指令,无法禁用。

示例配置

以下示例使用 ivf 方法,未指定编码器(默认情况下,UDB-SX 使用 flat 编码器):

"method": {
  "name":"ivf",
  "engine":"faiss",
  "parameters":{
    "nlist": 4,
    "nprobes": 2
  }
}

以下示例使用带有 pq 编码器的 ivf 方法:

"method": {
  "name":"ivf",
  "engine":"faiss",
  "parameters":{
    "encoder":{
      "name":"pq",
      "parameters":{
        "code_size": 8,
        "m": 8
      }
    }
  }
}

以下示例使用 hnsw 方法,未指定编码器(默认情况下,UDB-SX 使用 flat 编码器):

"method": {
  "name":"hnsw",
  "engine":"faiss",
  "parameters":{
    "ef_construction": 256,
    "m": 8
  }
}

以下示例使用带有 fp16 类型 sq 编码器的 ivf 方法:

"method": {
  "name":"ivf",
  "engine":"faiss",
  "parameters":{
    "encoder": {
      "name": "sq",
      "parameters": {
        "type": "fp16",
        "clip": false
      }
    },
    "nprobes": 2
  }
}

以下示例使用带有启用了 clipfp16 类型 sq 编码器的 hnsw 方法:

"method": {
  "name":"hnsw",
  "engine":"faiss",
  "parameters":{
    "encoder": {
      "name": "sq",
      "parameters": {
        "type": "fp16",
        "clip": true
      }  
    },    
    "ef_construction": 256,
    "m": 8
  }
}

NMSLIB 引擎(已弃用)

非度量空间库(NMSLIB)引擎是 UDB-SX 中最早的向量搜索实现之一。虽然仍然支持,但已被 Faiss 和 Lucene 引擎取代,现已弃用。

支持的方法

NMSLIB 引擎支持以下方法。

方法名称 需要训练 支持的空间
hnsw l2innerproductcosinesimill1linf

HNSW 参数

HNSW 方法支持以下参数。

参数名称 必需 默认值 可更新 描述
ef_construction 100 在 k-NN 图创建期间使用的动态列表的大小。值越高,图越精确,但索引速度越慢。
m 16 为每个新元素创建的双向链接数。显著影响内存消耗。保持在 2100 之间。

对于 NMSLIB(已弃用),ef_search索引设置 中设置。

示例配置

"method": {
    "name": "hnsw",
    "engine": "nmslib",
    "space_type": "l2",
    "parameters": {
        "ef_construction": 100,
        "m": 16
    }
}

选择正确的方法

在构建 knn_vector 字段时,有多个选项可供选择。要选择正确的方法和参数,您应首先了解工作负载的需求以及您愿意做出的权衡。需要考虑的因素包括:(1) 查询延迟,(2) 查询质量,(3) 内存限制,以及 (4) 索引延迟。

如果内存不是问题,HNSW 在查询延迟/查询质量权衡方面表现良好。

如果您希望与 HNSW 相比使用更少的内存并提高索引速度,同时保持相似的查询质量,您应该评估 IVF。

如果内存是一个问题,请考虑在 HNSW 或 IVF 索引中添加 PQ 编码器。由于 PQ 是有损编码,查询质量会下降。

您可以通过使用 fp_16 编码器 将内存占用减少 2 倍,且搜索质量损失最小。如果您的向量维度在 [-128, 127] 字节范围内,我们建议使用 字节量化器 将内存占用减少 4 倍。要了解更多关于向量量化的选项,请参阅 k-NN 向量量化

引擎推荐

一般来说,对于大规模用例选择 Faiss。Lucene 是较小部署的良好选择,并提供诸如智能过滤等优势,其中根据情况自动应用最佳过滤策略——预过滤、后过滤或精确 k-NN。下表总结了每个选项之间的差异。

Faiss/HNSW Faiss/IVF Lucene/HNSW
最大维度 16,000 16,000 16,000
过滤 后过滤 后过滤 搜索期间过滤
需要训练 否(PQ 需要)
相似度度量 l2innerproduct l2innerproduct l2cosinesimil
向量数量 数百亿 数百亿 少于 1000 万
索引延迟 最低
查询延迟和质量 低延迟和高质量 低延迟和低质量 高延迟和高质量
向量压缩 平铺

PQ
平铺

PQ
平铺
内存消耗

PQ 下低


PQ 下低

内存估算

在典型的 UDB-SX 集群中,一部分 RAM 被保留给 JVM 堆。UDB-SX 将原生库索引分配到剩余 RAM 的一部分。这部分的大小由 circuit_breaker_limit 集群设置决定。默认情况下,该限制设置为 50%。

使用副本会使向量总数翻倍。

有关将内存估算与向量量化结合使用的信息,请参阅 向量量化

HNSW 内存估算

HNSW 所需的内存估计为 1.1 * (4 * dimension + 8 * m) 字节/向量。

例如,假设您有 100 万个向量,dimension 为 256,m 为 16。内存需求可以估算如下:

1.1 * (4 * 256 + 8 * 16) * 1,000,000 ~= 1.267 GB

IVF 内存估算

IVF 所需的内存估计为 1.1 * (((4 * dimension) * num_vectors) + (4 * nlist * d)) 字节。

例如,假设您有 100 万个向量,dimension256nlist128。内存需求可以估算如下:

1.1 * (((4 * 256) * 1,000,000) + (4 * 128 * 256))  ~= 1.126 GB