机器学习推理搜索请求处理器

搜索ml_inference请求处理器用于调用已注册的机器学习 (ML) 模型,以便使用模型输出重写查询。

前提条件:
在使用ml_inference搜索请求处理器之前,您必须拥有托管在 UDB-SX集群上的本地机器学习模型,或者通过 ML Commons 插件连接到 UDB-SX 集群的外部托管模型。有关本地模型的更多信息,请参阅“在 UDB-SX 中使用机器学习模型”。有关外部托管模型的更多信息,请参阅“连接到外部托管模型”

语法

以下是ml-inference搜索请求处理器的语法:

{
  "ml_inference": {
    "model_id": "<model_id>",
    "function_name": "<function_name>",
    "full_response_path": "<full_response_path>",
    "query_template": "<query_template>",
    "model_config": {
      "<model_config_field>": "<config_value>"
    },
    "model_input": "<model_input>",
    "input_map": [
      {
        "<model_input_field>": "<query_input_field>"
      }
    ],
    "output_map": [
      {
        "<query_output_field>": "<model_output_field>"
      }
    ]
  }
}

配置参数

下表列出了ml-inference搜索请求处理器的必需参数和可选参数。

| 参数 | 数据类型 | 必填/选填 | 描述 | |:–| :— |:—|:—| | model_id| String | 必填 | 处理器使用的机器学习模型的ID。 | | query_template | String | 选填 | 用于构建包含查询字符串的新查询的查询字符串模板new_document_field,通常在将搜索查询重写为新的查询类型时使用。 | | function_name | String | 对于外部托管模型,此项为选填;

对于本地模型,此项为必填。 | 处理器中配置的机器学习模型的函数名称。对于本地模型,有效值为sparse_encoding`` <model_name><model_name> sparse_tokenize text_embedding<model_name><model_name> text_similarity。对于外部托管模型,有效值为 <model_name> remote。默认值为 <model_name> remote。| | model_config | Object | 选填 | 机器学习模型的自定义配置选项。对于外部托管的模型,如果设置了此配置,则会覆盖默认连接器参数。对于本地模型,您可以添加此配置model_config以覆盖model_input注册期间设置的模型配置。有关更多信息,请参阅对象model_config。 | | model_input | String |对于外部托管模型,此项为选填;

对于本地模型,此项为必填 | 定义模型所需输入字段格式的模板。每种本地模型类型可能使用不同的输入集。对于外部托管模型,默认值为 "{ \"parameters\": ${ml_inference.parameters} }. | | input_map | Array | 必填 | 一个数组,指定如何将查询字符串字段映射到模型输入字段。数组中的每个元素都是格式中的映射,对应文档字段的一次模型调用。如果外部托管模型未指定输入映射,则所有文档字段直接作为输入传递给模型。大小表示模型被调用的次数(即预测API请求的次数)。"<model_input_field>": "<query_input_field>"input_map | | <model_input_field> | String | 必填 | 模型输入字段名称。 | | <query_input_field> | String | 必填 | 用作模型输入的查询字段的名称或 JSON 路径。 | | output_map | Array | 格式 | 一个数组,用于指定如何将模型输出字段映射到查询字符串中的新字段。数组中的每个元素都是一个映射,格式如下 "<query_output_field>": "<model_output_field>". | | <query_output_field> | String | 必填 | model_output存储模型输出(由指定)的查询字段的名称。 | | <model_output_field> | String | 必填 | 要存储在模型输出中的字段的名称或 JSON 路径 query_output_field。 | | full_response_path | Boolean | 选填 | 如果model_output_field中包含的是指向该字段的完整 JSON 路径(而非字段名称),则将此参数设置为true。这样,模型输出将被完全解析以获取该字段的值。对于本地模型,默认值为true,而对于外部托管模型,默认值为false。 | | ignore_missing | Boolean | 选填 | 如果 true 且在 input_mapoutput_map 中定义的任何输入字段缺失,则忽略此处理器。否则,缺失字段会导致失败。默认值为 false。 | | ignore_failure | Boolean | 选填 | 指定处理器在遇到错误时是否继续执行。如果为 true,则忽略此处理器并继续搜索。如果为 false,则任何失败都会导致搜索被取消。默认值为 false。 | | max_prediction_tasks | Integer | 选填 | 在查询搜索过程中能够同时运行的模型调用的最大数量。默认值为10。 | | description | String | 选填 | 处理器的简要描述。 | | tag | String | 选填 | 处理器的标识标签。用于调试,以区分相同类型的处理器。 |

input_map映射output_map支持标准JSON 路径表示法,用于指定复杂的数据结构。

使用处理器

按照以下步骤来使用流水线中的处理器。在创建处理器时,您必须提供模型 ID、input_mapoutput_map。在使用处理器测试流水线之前,请确保模型已成功部署。您可以使用获取模型 API 来检查模型状态。

对于本地模型,您必须提供一个model_input字段,该字段用于指定模型的输入格式。将model_config中的任何输入字段添加到model_input中。

对于外部托管的模型,model_input 字段是可选的,其默认值是"{ \"parameters\": ${ml_inference.parameters} }

设置

创建一个名为index的索引my_index,并索引两个文档:

POST /my_index/_doc/1
{
  "passage_text": "I am excited",
  "passage_language": "en",
  "label": "POSITIVE",
  "passage_embedding": [
    2.3886719,
    0.032714844,
    -0.22229004
    ...]
}
POST /my_index/_doc/2
{
  "passage_text": "I am sad",
  "passage_language": "en",
  "label": "NEGATIVE",
  "passage_embedding": [
    1.7773438,
    0.4309082,
    1.8857422,
    0.95996094,
    ...]
}

当您在未使用搜索管道的情况下对已创建的索引运行词项查询时,该查询会搜索包含查询中指定确切词项的文档。以下查询不会返回任何结果,因为查询文本与索引中的任何文档都不匹配:

GET /my_index/_search
{
  "query": {
    "term": {
      "passage_text": {
        "value": "happy moments",
        "boost": 1
      }
    }
  }
}

通过使用模型,搜索流程可以根据模型推断结果动态重写词值,从而增强或改变搜索结果。这意味着模型会接收来自搜索查询的初始输入,对其进行处理,然后更新查询词以反映模型推断结果,从而有可能提高搜索结果的相关性。

示例:外部托管模型

以下示例配置了一个ml_inference具有外部托管模型的处理器。

步骤 1:创建管道

本示例演示如何为外部托管的情感分析模型创建搜索管道,该模型会重写词查询值。该模型需要一个inputs字段,并在一个字段中生成结果label。由于function_name未指定,因此默认值为remote,表示外部托管模型。

查询词值会根据模型的输出进行重写。ml_inference搜索请求中的处理器需要一个input_map用于检索模型输入的查询字段值,以及一个output_map用于将模型输出赋值给查询字符串的函数。

在这个例子中,ml_inference搜索请求处理器用于处理以下词项查询:

 {
  "query": {
    "term": {
      "label": {
        "value": "happy moments",
        "boost": 1
      }
    }
  }
}

以下请求会创建一个搜索管道,该管道会重写前面的词项查询:

PUT /_search/pipeline/ml_inference_pipeline
{
  "description": "Generate passage_embedding for searched documents",
  "processors": [
    {
      "ml_inference": {
        "model_id": "<your model id>",
        "input_map": [
          {
            "inputs": "query.term.label.value"
          }
        ],
        "output_map": [
          {
            "query.term.label.value": "label"
          }
        ]
      }
    }
  ]
}

当向外部托管模型发出 Predict API 请求时,所有必要的字段和参数通常都包含在一个parameters对象中:

POST /_plugins/_ml/models/cleMb4kBJ1eYAeTMFFg4/_predict
{
  "parameters": {
    "inputs": [
      {
        ...
      }
    ]
  }
}

因此,要使用外部托管的情感分析模型,请按以下格式发送 Predict API 请求:

POST /_plugins/_ml/models/cywgD5EB6KAJXDLxyDp1/_predict
{
  "parameters": {
    "inputs": "happy moments"
  }
}

该模型处理输入文本,并根据输入文本的情感倾向生成预测结果。在本例中,情感倾向为正面:

{
  "inference_results": [
    {
      "output": [
        {
          "name": "response",
          "dataAsMap": {
            "label": "POSITIVE",
            "score": "0.948"
          }
        }
      ],
      "status_code": 200
    }
  ]
}

在为外部托管模型指定字段时input_map,可以直接引用该inputs字段,而无需提供其点路径parameters.inputs

"input_map": [  
  {
    "inputs": "query.term.label.value"
  }
]

步骤 2:运行管道

创建搜索管道后,您可以使用该搜索管道运行相同的词项查询:

GET /my_index/_search?search_pipeline=my_pipeline_request_review
{
  "query": {
    "term": {
      "label": {
        "value": "happy moments",
        "boost": 1
      }
    }
  }
}

根据模型的输出结果,查询词的值会被重写。模型判断查询词的情感倾向为正面,因此重写的查询如下所示:

{
  "query": {
    "term": {
      "label": {
        "value": "POSITIVE",
        "boost": 1
      }
    }
  }
}

响应中包含一个文档,该文档的某个label字段具有以下值POSITIVE

{
  "took": 288,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.00009405752,
    "hits": [
      {
        "_index": "my_index",
        "_id": "3",
        "_score": 0.00009405752,
        "_source": {
          "passage_text": "I am excited",
          "passage_language": "en",
          "label": "POSITIVE"
        }
      }
    ]
  }
}

示例:本地模型

以下示例向您展示如何配置ml_inference具有本地模型的处理器,以将词项查询重写为 k-NN 查询。

步骤 1:创建管道

以下示例展示了如何为huggingface/sentence-transformers/all-distilroberta-v1本地模型创建搜索管道。该模型是一个预训练的句子转换器模型,托管在您的 UDB-SX 集群中。

如果使用 Predict API 调用模型,则请求如下所示:

POST /_plugins/_ml/_predict/text_embedding/cleMb4kBJ1eYAeTMFFg4
{
  "text_docs": [
    "today is sunny"
  ],
  "return_number": true,
  "target_response": [
    "sentence_embedding"
  ]
}

使用此方案,model_input按如下方式指定:

 "model_input": "{ \"text_docs\": ${input_map.text_docs}, \"return_number\": ${model_config.return_number}, \"target_response\": ${model_config.target_response} }"

在映射中input_map,将query.term.passage_embedding.value查询字段映射text_docs到模型期望的字段:

"input_map": [
  {
    "text_docs": "query.term.passage_embedding.value"
  } 
]

因为您将要转换为嵌入的字段指定为一个 JSON 路径,所以您需要将 full_response_path 设置为 true。然后会解析整个 JSON 文档,以获取输入字段。

"full_response_path": true

该字段中的文本query.term.passage_embedding.value将用于生成词嵌入:

{
  "text_docs": "happy passage"
}

Predict API 请求返回以下响应:

{
  "inference_results": [
    {
      "output": [
        {
          "name": "sentence_embedding",
          "data_type": "FLOAT32",
          "shape": [
            768
          ],
          "data": [
            0.25517133,
            -0.28009856,
            0.48519906,
            ...
          ]
        }
      ]
    }
  ]
}

该模型在$.inference_results.*.output.*.data字段中生成嵌入向量。并将output_map该字段映射到查询模板中的查询字段:

"output_map": [
  {
    "modelPredictionOutcome": "$.inference_results.*.output.*.data"
  }
]

要使用ml_inference本地模型配置搜索请求处理器,请function_name显式指定。在本例中,为function_nametext_embedding有关有效值的信息function_name,请参阅配置参数

以下是ml_inference处理器与本地模型的最终配置:

PUT /_search/pipeline/ml_inference_pipeline_local
{
  "description": "searchs reviews and generates embeddings",
  "processors": [
    {
      "ml_inference": {
        "function_name": "text_embedding",
        "full_response_path": true,
        "model_id": "<your model id>",
        "model_config": {
          "return_number": true,
          "target_response": [
            "sentence_embedding"
          ]
        },
        "model_input": "{ \"text_docs\": ${input_map.text_docs}, \"return_number\": ${model_config.return_number}, \"target_response\": ${model_config.target_response} }",
        "query_template": """{
        "size": 2,
        "query": {
          "knn": {
            "passage_embedding": {
              "vector": ${modelPredictionOutcome},
              "k": 5
              }
            }
           }
          }""",
        "input_map": [
          {
            "text_docs": "query.term.passage_embedding.value"
          }
        ],
        "output_map": [
          {
            "modelPredictionOutcome": "$.inference_results.*.output.*.data"
          }
        ],
        "ignore_missing": true,
        "ignore_failure": true
      }
    }
  ]
}

步骤 2:运行管道

运行以下查询,并在请求中提供管道名称:

GET /my_index/_search?search_pipeline=ml_inference_pipeline_local
{
"query": {
  "term": {
    "passage_embedding": {
      "value": "happy passage"
      }
    }
  }
}

该响应证实处理器运行了 k-NN 查询,返回了得分更高的文档 1:

{
  "took": 288,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.00009405752,
    "hits": [
      {
        "_index": "my_index",
        "_id": "1",
        "_score": 0.00009405752,
        "_source": {
          "passage_text": "I am excited",
          "passage_language": "en",
          "label": "POSITIVE",
          "passage_embedding": [
            2.3886719,
            0.032714844,
            -0.22229004
            ...]
        }
      },
      {
        "_index": "my_index",
        "_id": "2",
        "_score": 0.00001405052,
        "_source": {
          "passage_text": "I am sad",
          "passage_language": "en",
          "label": "NEGATIVE",
          "passage_embedding": [
            1.7773438,
            0.4309082,
            1.8857422,
            0.95996094,
            ...
          ]
        }
      }
    ]
  }
}