k-NN API
OpenSearch 提供了多个 k-最近邻 (k-NN) API,用于管理、监控和优化您的向量工作负载。
统计
k-NN stats
API 提供了有关 k-NN 插件当前状态的信息,该插件实现了向量搜索功能。这包括集群级和节点级统计信息。集群级统计信息对整个集群只有一个值。节点级统计信息对集群中的每个节点有一个值。您可以通过 nodeId
和 statName
筛选查询,如下例所示。
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 | 本地库索引在节点上使用的本地内存量(以千字节为单位)。 |
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 | 对于每个具有 knn_vector 字段并开启近似 k-NN 的 OpenSearch 索引,此统计信息提供该 OpenSearch 索引拥有的本地库索引数量以及该 OpenSearch 索引使用的总 graph_memory_usage (以千字节为单位)。 |
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 | 模型系统索引的状态。有效值为 red 、yellow 和 green 。如果索引不存在,此值为 null 。 |
indexing_from_model_degraded | 布尔值,指示从模型索引是否已降级。如果 JVM 内存不足以缓存模型,则会发生这种情况。 |
ing_requests | 向节点发出的训练请求数量。 |
training_errors | 节点上发生的训练错误数量。 |
training_memory_usage | 节点上训练使用的本地内存量(以千字节为单位)。 |
training_memory_usage_percentage | 节点上训练使用的本地内存量占最大缓存容量的百分比。 |
某些统计信息名称中包含 graph。在这些情况下,graph 与 本地库索引 同义。术语 graph 反映了插件仅支持 HNSW 算法时的状态,该算法由分层图组成。
远程索引构建统计信息
3.0 版本引入
如果您配置了远程索引构建,响应将包含其他字段。下表列出了可用的远程索引构建统计信息响应正文字段。
字段 | 描述 |
---|---|
repository_stats.read_success_count | 从仓库成功读取操作的次数。 |
repository_stats.read_failure_count | 从仓库读取操作失败的次数。 |
repository_stats.successful_read_time_in_millis | 成功读取操作所花费的总时间(以毫秒为单位)。 |
repository_stats.write_success_count | 向仓库成功写入操作的次数。 |
repository_stats.write_failure_count | 向仓库写入操作失败的次数。 |
repository_stats.successful_write_time_in_millis | 成功写入操作所花费的总时间(以毫秒为单位)。 |
client_stats.build_request_success_count | 成功构建请求操作的次数。 |
client_stats.build_request_failure_count | 构建请求操作失败的次数。 |
client_stats.status_request_failure_count | 状态请求操作失败的次数。 |
client_stats.status_request_success_count | 状态请求操作成功的次数。 |
client_stats.index_build_success_count | 成功索引构建操作的次数。 |
client_stats.index_build_failure_count | 索引构建操作失败的次数。 |
client_stats.waiting_time_in_ms | 客户端等待远程构建完成的总时间(毫秒)。 |
build_stats.remote_index_build_flush_time_in_millis | 远程刷新操作的总耗时(毫秒)。 |
build_stats.remote_index_build_merge_time_in_millis | 远程合并操作的总耗时(毫秒)。 |
build_stats.remote_index_build_current_merge_operations | 当前正在进行的远程合并操作数量。 |
build_stats.remote_index_build_current_flush_operations | 当前正在进行的远程刷新操作数量。 |
build_stats.remote_index_build_current_merge_size | 当前远程合并操作的大小。 |
build_stats.remote_index_build_current_flush_size | 当前远程刷新操作的大小。 |
请求示例
以下示例演示了如何检索与 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
}
}
The total
值表示 k-NN 插件尝试预热的分片数量。响应还包括插件成功预热的分片数量和未能预热的分片数量。
此调用在预热操作完成或请求超时之前不会返回结果。如果请求超时,则操作将在集群上继续进行。要监控预热操作,请使用 OpenSearch _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 搜索或预热操作期间,本地库索引(用于 faiss
和 nmslib
(已弃用)引擎)会加载到本地内存中。目前,您可以通过删除索引或设置 k-NN 集群设置 knn.cache.item.expiry.enabled
和 knn.cache.item.expiry.minutes
来从缓存或本地内存中逐出索引,这会在索引空闲一段时间后将其从缓存中删除。但是,您无法在不删除索引的情况下从缓存中逐出索引。为了解决这个问题,您可以使用 k-NN 清除缓存 API 操作,它会从缓存中清除给定的一组索引。
k-NN 清除缓存 API 会逐出请求中指定的所有索引的所有分片(主分片和副本分片)的所有本地库文件。与 预热操作 的行为类似,k-NN 清除缓存 API 是幂等的,这意味着如果您尝试清除已从缓存中逐出的索引的缓存,它不会产生任何额外效果。
此 API 操作仅适用于使用 faiss
和 nmslib
(已弃用)引擎创建的索引。它对使用 lucene
引擎创建的索引没有影响。
请求示例
以下请求将三个索引的本地库索引从缓存中逐出
POST /_plugins/_knn/clear_cache/index1,index2,index3?pretty
{
"_shards" : {
"total" : 6,
"successful" : 6,
"failed" : 0
}
}
The 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}
响应正文字段
下表列出了可用的响应正文字段。
响应字段 | 描述 |
---|---|
模型 ID | 所获取模型的唯一标识符。 |
模型 BLOB | 序列化模型的 Base64 编码字符串。 |
状态 | 模型的当前状态,可以是 created (已创建)、failed (失败)或 training (训练中)。 |
时间戳 | 模型创建的日期和时间。 |
描述 | 用户提供的模型描述。 |
错误 | 解释模型处于失败状态的错误消息。 |
空间类型 | 模型训练所使用的空间类型,例如欧几里得或余弦。注意:此值可以在请求的顶层设置。 |
维度 | 此模型所设计的向量空间的维度。 |
引擎 | 用于创建模型的本地库,可以是 faiss 或 nmslib (已弃用)。 |
请求示例
以下示例演示了如何使用 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"
}
搜索模型
您可以使用 OpenSearch 查询在索引中搜索模型。请参阅以下使用示例。
请求示例
以下示例展示了如何在 OpenSearch 集群中搜索 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。
查询参数
下表列出了可用的查询参数。
查询参数 | 描述 |
---|---|
模型 ID | 所获取模型的唯一标识符。如果未指定,则生成一个随机 ID。可选。 |
节点 ID | 指定执行训练过程的首选节点。如果提供,并且指定节点具有必要的容量和可用资源,则将使用该节点进行训练。可选。 |
请求正文字段
下表列出了可用的请求正文字段。
请求字段 | 描述 |
---|---|
训练索引 | 检索训练数据的索引。 |
训练字段 | 从 training_index 中检索训练数据的 knn_vector 字段。此字段的维度必须与此请求中传递的 dimension 匹配。 |
维度 | 正在训练的模型的维度。 |
最大训练向量计数 | 用于训练的训练索引中的最大向量数。默认为索引中的所有向量。可选。 |
搜索大小 | 训练数据使用滚动查询从训练索引中提取。此参数定义每个滚动查询返回的结果数量。默认为 10000 。可选。 |
描述 | 用户提供的模型描述。可选。 |
方法 | 用于搜索操作的近似 k-NN 方法的配置。有关可用方法的更多信息,请参阅 方法和引擎。该方法需要训练才能生效。 |
空间类型 | 训练此模型的空间类型,例如欧几里得或余弦。注意:此值也可以在 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"
}