k-NN API

UDB-SX 提供了多个 k-最近邻 API,用于管理、监控和优化您的向量工作负载。

统计信息

k-NN stats API 提供有关实现向量搜索功能的 k-NN 插件的当前状态信息。这包括集群级别和节点级别的统计信息。集群级别统计信息对整个集群有单一值。节点级别统计信息对集群中的每个节点有单一值。您可以通过 nodeIdstatName 过滤查询,如下例所示:

GET /_plugins/_knn/nodeId1,nodeId2/stats/statName1,statName2

响应体字段

下表列出了可用的响应体字段。

字段 描述
circuit_breaker_triggered 指示断路器是否被触发。此统计信息仅适用于近似 k-NN 搜索。
total_load_time k-NN 将原生库索引加载到缓存中所花费的时间(纳秒)。此统计信息仅适用于近似 k-NN 搜索。
eviction_count 由于内存限制或空闲时间而从缓存中逐出的原生库索引数量。此统计信息仅适用于近似 k-NN 搜索。
请注意:因索引删除而发生的显式逐出不计入此数。
hit_count 缓存命中次数。当用户查询已加载到内存中的原生库索引时发生缓存命中。此统计信息仅适用于近似 k-NN 搜索。
miss_count 缓存未命中次数。当用户查询尚未加载到内存中的原生库索引时发生缓存未命中。此统计信息仅适用于近似 k-NN 搜索。
graph_memory_usage 节点上原生库索引使用的原生内存量(KB)。
graph_memory_usage_percentage 节点上原生库索引使用的原生内存量占最大缓存容量的百分比。
graph_index_requests 将文档的 knn_vector 字段添加到原生库索引的请求数。
graph_index_errors 将文档的 knn_vector 字段添加到原生库索引时产生错误的请求数。
graph_query_requests 已执行的原生库索引查询数量。
graph_query_errors 产生错误的原生库索引查询数量。
knn_query_requests 接收到的 k-NN 查询请求数量。
cache_capacity_reached 是否已达到 knn.memory.circuit_breaker.limit。此统计信息仅适用于近似 k-NN 搜索。
load_success_count k-NN 成功将原生库索引加载到缓存中的次数。此统计信息仅适用于近似 k-NN 搜索。
load_exception_count 尝试将原生库索引加载到缓存时发生异常的次数。此统计信息仅适用于近似 k-NN 搜索。
indices_in_cache 对于每个启用了近似 k-NN 的 knn_vector 字段的 UDB-SX 索引,此统计信息提供该 UDB-SX 索引拥有的原生库索引数量以及该 UDB-SX 索引使用的总 graph_memory_usage(KB)。
script_compilations k-NN 脚本被编译的次数。此值通常应为 1 或 0,但如果包含已编译脚本的缓存已满,k-NN 脚本可能会被重新编译。此统计信息仅适用于 k-NN 评分脚本搜索。
script_compilation_errors 脚本编译期间的错误数。此统计信息仅适用于 k-NN 评分脚本搜索。
script_query_requests 脚本查询总数。此统计信息仅适用于 k-NN 评分脚本搜索。
script_query_errors 脚本查询期间的错误数。此统计信息仅适用于 k-NN 评分脚本搜索。
nmslib_initialized 布尔值,指示 nmslib JNI 库是否已在节点上加载并初始化。
faiss_initialized 布尔值,指示 faiss JNI 库是否已在节点上加载并初始化。
model_index_status 模型系统索引的状态。有效值为 redyellowgreen。如果索引不存在,此值为 null
indexing_from_model_degraded 布尔值,指示从模型索引是否降级。如果 JVM 内存不足以缓存模型,则会发生这种情况。
ing_requests 向节点发出的训练请求数。
training_errors 节点上发生的训练错误数。
training_memory_usage 节点上训练使用的原生内存量(KB)。
training_memory_usage_percentage 节点上训练使用的原生内存量占最大缓存容量的百分比。

请注意:一些统计信息的名称中包含 graph。在这些情况下,graph原生库索引 的同义词。术语 graph 反映了插件最初仅支持由分层图组成的 HNSW 算法时的命名。

示例请求

以下示例演示如何检索与 k-NN 插件相关的统计信息。

以下示例获取集群中所有节点的 k-NN 插件综合统计信息:

GET /_plugins/_knn/stats?pretty
{
    "_nodes" : {
        "total" : 1,
        "successful" : 1,
        "failed" : 0
    },
    "cluster_name" : "my-cluster",
    "circuit_breaker_triggered" : false,
    "model_index_status" : "YELLOW",
    "nodes" : {
      "JdfxIkOS1-43UxqNz98nw" : {
        "graph_memory_usage_percentage" : 3.68,
        "graph_query_requests" : 1420920,
        "graph_memory_usage" : 2,
        "cache_capacity_reached" : false,
        "load_success_count" : 179,
        "training_memory_usage" : 0,
        "indices_in_cache" : {
            "myindex" : {
                "graph_memory_usage" : 2,
                "graph_memory_usage_percentage" : 3.68,
                "graph_count" : 2
            }
        },
        "script_query_errors" : 0,
        "hit_count" : 1420775,
        "knn_query_requests" : 147092,
        "total_load_time" : 2436679306,
        "miss_count" : 179,
        "training_memory_usage_percentage" : 0.0,
        "graph_index_requests" : 656,
        "faiss_initialized" : true,
        "load_exception_count" : 0,
        "training_errors" : 0,
        "eviction_count" : 0,
        "nmslib_initialized" : false,
        "script_compilations" : 0,
        "script_query_requests" : 0,
        "graph_query_errors" : 0,
        "indexing_from_model_degraded" : false,
        "graph_index_errors" : 0,
        "training_requests" : 17,
        "script_compilation_errors" : 0
    }
  }
}

以下示例为单个节点检索特定指标(断路器状态和图内存使用情况):

GET /_plugins/_knn/HYMrXXsBSamUkcAjhjeN0w/stats/circuit_breaker_triggered,graph_memory_usage?pretty
{
    "_nodes" : {
        "total" : 1,
        "successful" : 1,
        "failed" : 0
    },
    "cluster_name" : "my-cluster",
    "circuit_breaker_triggered" : false,
    "nodes" : {
        "HYMrXXsBSamUkcAjhjeN0w" : {
            "graph_memory_usage" : 1
        }
    }
}

预热操作

用于执行近似 k-NN 搜索的原生库索引与其他 Apache Lucene 段文件一起存储为特殊文件。要使用 k-NN 插件对这些索引进行搜索,插件需要将这些文件加载到原生内存中。

如果插件尚未将文件加载到原生内存中,则会在收到搜索请求时加载它们。加载时间可能导致初始查询期间的高延迟。为了避免这种情况,用户通常在预热期间运行随机查询。在此预热期之后,文件被加载到原生内存中,他们的生产工作负载可以启动。这种加载过程是间接的,需要额外的努力。

作为替代方案,您可以通过对要搜索的索引运行 k-NN 插件预热 API 操作来避免此延迟问题。此操作将请求中指定的所有索引的所有分片(主分片和副本)的所有原生库文件加载到原生内存中。

该过程完成后,您可以对索引进行搜索而无需初始延迟损失。预热 API 操作是幂等的,因此如果段的原生库文件已加载到内存中,此操作无效。它仅加载当前未存储在内存中的文件。

示例请求

以下请求对三个索引执行预热:

GET /_plugins/_knn/warmup/index1,index2,index3?pretty
{
  "_shards" : {
    "total" : 6,
    "successful" : 6,
    "failed" : 0
  }
}

total 值表示 k-NN 插件尝试预热的分片数量。响应还包括插件成功预热和未能预热的分片数量。

该调用在预热操作完成或请求超时之前不会返回结果。如果请求超时,操作将在集群上继续。要监控预热操作,请使用 UDB-SX _tasks API:

GET /_tasks

操作完成后,使用 k-NN _stats API 操作 查看 k-NN 插件加载到图中的内容。

最佳实践

为确保预热操作正常运行,请遵循以下最佳实践:

  • 不要在要预热的索引上运行合并操作。在合并操作期间,k-NN 插件创建新段,有时会删除旧段。例如,您可能会遇到这样的情况:预热 API 操作将原生库索引 A 和 B 加载到原生内存中,但段 C 是由合并段 A 和 B 创建的。原生库索引 A 和 B 将不再在内存中,而原生库索引 C 也不在内存中。在这种情况下,加载原生库索引 C 的初始损失仍然存在。

  • 确认要预热的所有原生库索引都能放入原生内存。有关原生内存限制的更多信息,请参阅 knn.memory.circuit_breaker.limit 统计信息。高图内存使用率会导致缓存抖动,这可能导致操作不断失败并尝试再次运行。

  • 不要索引任何要加载到缓存中的文档。向段写入新信息会阻止预热 API 操作加载原生库索引,直到它们可搜索为止。这意味着您必须在索引后再次运行预热操作。

k-NN 清除缓存

引入版本 2.14

在近似 k-NN 搜索或预热操作期间,原生库索引(针对 faissnmslib [已弃用] 引擎)被加载到原生内存中。目前,您可以通过删除索引或设置 k-NN 集群设置 knn.cache.item.expiry.enabledknn.cache.item.expiry.minutes 来从缓存或原生内存中逐出索引,这会在索引空闲给定时间后将其从缓存中移除。然而,如果不删除索引就无法从缓存中逐出索引。为解决此问题,您可以使用 k-NN 清除缓存 API 操作,该操作从缓存中清除给定的一组索引。

k-NN 清除缓存 API 逐出请求中指定的所有索引的所有分片(主分片和副本)的所有原生库文件。与预热操作类似,k-NN 清除缓存 API 是幂等的,这意味着如果您尝试清除已从缓存中逐出的索引的缓存,它不会有任何额外效果。

请注意:此 API 操作仅适用于使用 faissnmslib(已弃用)引擎创建的索引。对使用 lucene 引擎创建的索引无效。

示例请求

以下请求从缓存中逐出三个索引的原生库索引:

POST /_plugins/_knn/clear_cache/index1,index2,index3?pretty
{
  "_shards" : {
    "total" : 6,
    "successful" : 6,
    "failed" : 0
  }
}

total 参数表示 API 尝试从缓存中清除的分片数量。响应包括已清除的分片数量和插件未能清除的分片数量。

k-NN 清除缓存 API 可与索引模式结合使用,以从缓存中清除与给定模式匹配的一个或多个索引,如下例所示:

POST /_plugins/_knn/clear_cache/index*?pretty
{
  "_shards" : {
    "total" : 6,
    "successful" : 6,
    "failed" : 0
  }
}

该 API 调用在操作完成或请求超时之前不会返回结果。如果请求超时,操作将在集群上继续。要监控请求,请使用 _tasks API,如下例所示:

GET /_tasks

操作完成后,使用 k-NN _stats API 操作 查看哪些索引已从缓存中逐出。

获取模型

GET 模型操作检索集群中存在的模型信息。一些原生库索引配置在索引和查询开始之前需要训练步骤。训练的输出是一个模型,可用于在索引期间初始化原生库索引文件。该模型在 k-NN 模型系统索引中被序列化。

示例请求

GET /_plugins/_knn/models/{model_id}

响应体字段

下表列出了可用的响应体字段。

响应字段 描述
model_id 获取的模型的唯一标识符。
model_blob 序列化模型的 base64 编码字符串。
state 模型的当前状态,可以是 createdfailedtraining
timestamp 模型创建的日期和时间。
description 用户提供的模型描述。
error 解释模型为何处于失败状态的错误消息。
space_type 模型训练所用的空间类型,例如欧几里得或余弦。请注意:此值可在请求的顶层设置。
dimension 该模型设计的向量空间的维度。
engine 用于创建模型的原生库,可以是 faissnmslib(已弃用)。

示例请求

以下示例演示如何使用 k-NN 插件 API 检索特定模型的信息。

以下示例返回模型的所有可用信息:

GET /_plugins/_knn/models/test-model?pretty
{
  "model_id" : "test-model",
  "model_blob" : "SXdGbIAAAAAAAAAAAA...",
  "state" : "created",
  "timestamp" : "2021-11-15T18:45:07.505369036Z",
  "description" : "Default",
  "error" : "",
  "space_type" : "l2",
  "dimension" : 128,
  "engine" : "faiss" 
}

以下示例演示如何选择性地检索字段:

GET /_plugins/_knn/models/test-model?pretty&filter_path=model_id,state
{
  "model_id" : "test-model",
  "state" : "created"
}

搜索模型

您可以使用 UDB-SX 查询在索引中搜索模型。请参见以下使用示例。

示例请求

以下示例显示如何搜索 UDB-SX 集群中的 k-NN 模型以及如何检索这些模型的元数据,同时排除可能较大的 model_blob 字段:

GET/POST /_plugins/_knn/models/_search?pretty&_source_excludes=model_blob
{
    "query": {
         ...
     }
}

响应包含模型信息:

{
    "took" : 0,
    "timed_out" : false,
    "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
    },
    "hits" : {
      "total" : {
          "value" : 1,
          "relation" : "eq"
      },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : ".opensearch-knn-models",
        "_id" : "test-model",
        "_score" : 1.0,
        "_source" : {
          "engine" : "faiss",
          "space_type" : "l2",
          "description" : "Default",
          "model_id" : "test-model",
          "state" : "created",
          "error" : "",
          "dimension" : 128,
          "timestamp" : "2021-11-15T18:45:07.505369036Z"
        }
      }
    ]
  }
}

删除模型

您可以使用 DELETE 操作删除集群中的模型。请参见以下使用示例。

示例请求

以下示例显示如何删除 k-NN 模型:

DELETE /_plugins/_knn/models/{model_id}
{
  "model_id": {model_id},
  "acknowledged": true
}

训练模型

您可以创建和训练一个模型,用于在索引期间初始化 k-NN 原生库索引。此 API 从训练索引的 knn_vector 字段中提取训练数据,创建并训练模型,然后将其序列化到模型系统索引。训练数据必须与请求体中传递的维度匹配。此请求在训练开始时返回。要监控模型的状态,请使用 获取模型 API

查询参数

下表列出了可用的查询参数。

查询参数 描述
model_id 获取的模型的唯一标识符。如果未指定,则生成随机 ID。可选。
node_id 指定用于执行训练过程的优先节点。如果提供,并且指定节点具备必要的能力和可用资源,则将使用该节点进行训练。可选。

请求体字段

下表列出了可用的请求体字段。

请求字段 描述
training_index 从中检索训练数据的索引。
training_field training_index 中用于检索训练数据的 knn_vector 字段。此字段的维度必须与此请求中传递的 dimension 匹配。
dimension 正在训练的模型的维度。
max_training_vector_count 用于训练的训练索引中的最大向量数。默认为索引中的所有向量。可选。
search_size 使用滚动查询从训练索引中提取训练数据。此参数定义每个滚动查询返回的结果数。默认为 10000。可选。
description 用户提供的模型描述。可选。
method 用于搜索操作的近似 k-NN 方法的配置。有关可用方法的更多信息,请参阅 方法与引擎。该方法需要训练才能有效。
space_type 训练此模型所用的空间类型,例如欧几里得或余弦。请注意:此值也可以在 method 参数中设置。

示例请求

以下示例显示如何启动 k-NN 模型的训练过程:

POST /_plugins/_knn/models/{model_id}/_train?preference={node_id}
{
    "training_index": "train-index-name",
    "training_field": "train-field-name",
    "dimension": 16,
    "max_training_vector_count": 1200,
    "search_size": 100,
    "description": "My model",
    "space_type": "l2",
    "method": {
        "name":"ivf",
        "engine":"faiss",
        "parameters":{
            "nlist":128,
            "encoder":{
                "name":"pq",
                "parameters":{
                    "code_size":8
                }
            }
        }
    }
}
POST /_plugins/_knn/models/_train?preference={node_id}
{
    "training_index": "train-index-name",
    "training_field": "train-field-name",
    "dimension": 16,
    "max_training_vector_count": 1200,
    "search_size": 100,
    "description": "My model",
    "space_type": "l2",
    "method": {
        "name":"ivf",
        "engine":"faiss",
        "parameters":{
            "nlist":128,
            "encoder":{
                "name":"pq",
                "parameters":{
                    "code_size":8
                }
            }
        }
    }
}

示例响应

{
    "model_id": "dcdwscddscsad"
}