# 使用搜索大模型实现OpenSearch AI搜索
通过接入搜索大模型提供的Embedding能力，OpenSearch可在文档写入时自动生成向量，在查询时通过语义相似性检索或混合检索实现精确匹配与语义理解。
#### 应用场景
传统关键词搜索（BM25）基于词项精确匹配，无法理解同义词、近义词或语义关联，导致用户用不同表述方式查询时难以召回相关文档。例如，用户查询"没有更新文件的资格该怎么办"，而文档中实际描述的是"受到限制而无法执行"或"修改被拒绝"，关键词搜索无法匹配。
通过接入搜索大模型提供的Embedding能力，OpenSearch可以在文档写入时自动将文本转换为向量嵌入，在查询时通过语义相似性检索（neural查询）实现"理解意图"式的搜索，提升搜索的准确性和召回率。进一步地，通过混合检索将关键词搜索与语义检索融合，兼顾精确匹配与语义理解，实现更全面的搜索效果。
OpenSearch AI搜索适用于RAG（Retrieval-Augmented Generation，检索增强生成）知识库、企业文档搜索、商品检索、智能问答等需要语义理解的搜索场景。
#### 方案架构
OpenSearch AI搜索的核心组件包括：
- **搜索大模型**：提供Embedding与Rerank模型服务，支持CSS搜索大模型独享版集群（受限使用阶段）、MaaS服务或其他外部模型服务三种来源，通过内网或公网地址访问。
- **ML Commons插件**：OpenSearch内置的机器学习插件，支持注册外部模型、创建连接器、管理模型组。
- **连接器（Connector）**：定义与外部模型服务的连接方式，包括访问协议、输入输出格式、认证鉴权等。
- **写入管道（Ingest Pipeline）**：在文档写入时自动调用Embedding模型，将文本字段转换为向量嵌入。
- **语义检索（neural查询）**：查询时自动调用Embedding模型将查询文本转换为向量，执行kNN（k-Nearest Neighbors，k近邻）语义检索。
- **混合检索（hybrid查询）**：结合关键词搜索与语义检索，通过搜索管道归一化组合分数，综合两种检索方式的优势。
图1架构图   
![](https://support.huaweicloud.com/usermanual-css/figure/zh-cn_image_0000002706756117.png "点击放大")
方案流程如下：
1. 准备搜索大模型，获取模型服务访问地址。
2. 准备OpenSearch集群并进行初始配置。
3. 注册模型组、创建连接器、注册并部署Embedding模型。
4. 创建写入管道，关联Embedding模型实现自动向量化。
5. 创建包含文本字段和向量字段的索引，关联写入管道。
6. 将文档写入到索引中，写入管道自动生成向量嵌入。
7. 执行语义检索（neural查询）和混合检索（hybrid查询）。
如果是内网搜索大模型建议与OpenSearch集群部署在同一VPC内，通过内网地址通信，不暴露公网。如果是公网模型服务，则需通过HTTPS协议和认证密钥确保通信安全。连接器通过"credential"字段配置认证密钥，确保仅授权的OpenSearch集群可以调用模型服务。
#### 方案优势
- 语义理解：传统关键词搜索无法理解同义词和语义关联，通过Embedding模型将文本转换为语义向量，实现基于意图的搜索，突破关键词匹配的局限。
- 自动向量化：传统向量检索需要预先计算并存储向量数据，通过写入管道与Embedding模型联动，文档写入时自动生成向量嵌入，简化数据处理流程。
- 双路召回：纯语义检索可能遗漏关键词完全匹配的文档，纯关键词搜索缺乏语义理解，混合检索同时利用两种方式，覆盖更多相关文档，提升召回率。
- 灵活加权：不同业务场景对关键词匹配和语义理解的侧重不同，通过"weights"参数灵活调整两种检索方式的权重占比，适应不同业务需求。
- 端到端集成：传统方案需要额外的中间件协调模型调用和检索流程，本方案从模型注册到数据写入再到检索查询，全链路通过OpenSearch原生能力实现，降低系统复杂度。
 
#### 约束限制
- OpenSearch集群版本号要求为3.4.0。
- 混合查询中的每个子查询独立执行，建议子查询数量不超过5个，避免性能开销增大。
- 向量字段的维度"dimension"必须与Embedding模型输出维度一致。
- 连接器的"pre_process_function"和"post_process_function"必须正确设置，否则无法嵌入到写入管道和搜索管道中，但不影响单独调用**_predict**接口。
- 文档写入时调用Embedding模型会增加写入延迟，单条文档写入延迟增加约50\~200ms，取决于模型服务响应时间。建议批量写入时控制批量大小，避免写入管道积压。
- 混合检索中的每个子查询独立执行，子查询数量越多，检索延迟越高。建议生产环境中通过测试确定合适的k值和子查询数量。
 
#### 资源和成本规划
表1资源和成本规划 
| 资源            | 资源说明                                                                 | 数量 | 费用说明 |
|:---|:---|:---|:---|
| 搜索大模型       | 提供Embedding与Rerank模型服务。独享版集群可以通过内网访问，MaaS服务和其他外部模型由模型部署环境决定通过公网或内网访问。 | 1   | 按需计费 |
| OpenSearch集群 | OpenSearch 3.4.0，用于运行ML Commons插件、写入管道、搜索管道等组件，执行数据写入和搜索。             | 1   | 按需计费    |
   
#### 操作流程
表2操作流程 
| 步骤                                                                    | 描述                                        |
|:---|:---|
| [步骤一：创建模型组]     | 为搜索大模型创建逻辑组，便于权限管理。仅安全集群需要对模型进行细粒度权限控制时才涉及。 |
| [步骤二：创建模型连接器]   | 定义OpenSearch与搜索大模型的连接方式。                 |
| [步骤三：注册并部署模型] | 通过连接器注册远程模型并部署。                           |
| [步骤四：测试模型可用性]     | 通过_predict接口验证模型配置是否正确。                    |
| [步骤五：创建写入管道]     | 创建写入管道，配置文档写入时自动调用Embedding模型生成向量嵌入。       |
| [步骤六：创建向量索引]     | 创建包含"knn_vector"字段和文本字段的索引。                |
| [步骤七：写入文档数据]  | 写入管道自动将写入的文档生成向量嵌入。                       |
| [步骤八：执行语义检索]       | 通过neural查询验证语义检索效果。                        |
| [步骤九：创建搜索管道]       | 创建搜索管道，对来自不同查询子句的文档分数进行归一化和加权组合。仅混合检索涉及。 |
| [步骤十：执行混合检索]     | 通过hybrid查询结合关键词搜索与语义检索。                   |
   
#### 前提条件
- 已准备搜索大模型，支持以下三种来源（任选其一）：
  - 搜索大模型独享版集群：选择"text-embedding-rank"模型版本，提供Embedding与Rerank功能。 搜索大模型独享版集群处于受限使用阶段，如需使用请提交[工单](https://console.huaweicloud.com/ticket/?locale=zh-cn#/ticketindex/serviceTickets)申请开通。
    
  
  - MaaS服务：在MaaS订阅Embedding与Rerank模型，获取API访问地址和认证信息。
  
  - 外部模型服务：自行部署的Embedding与Rerank模型（如通过vLLM部署开源模型），确保模型服务提供符合OpenAI兼容格式的"/v1/embeddings"接口。
  
  
  无论选择哪种部署方式，均需记录模型服务的访问地址、端口号、模型标识（名称）和认证密钥，后续配置连接器时需要使用。
  
- 已创建OpenSearch集群，集群版本号为3.4.0，且集群状态为"可用"。
- 如果使用内网模型服务，需与OpenSearch集群在同一VPC内，安全组入方向规则已放通模型服务端口（搜索大模型独享版集群默认为18088端口，MaaS服务或其他外部模型服务以实际端口为准）和9200端口（OpenSearch集群通信端口）。如果使用公网模型服务，需确保OpenSearch集群可访问公网。
 
#### 登录OpenSearch Dashboards
登录OpenSearch Dashboards进入命令执行页面。OpenSearch集群支持多种客户端访问，本文仅以CSS服务集成的OpenSearch Dashboards为例介绍配置指导。
1. 登录[云搜索服务管理控制台](https://console.huaweicloud.com/elasticsearch/)。
2. 在左侧导航栏，选择"集群管理 \> OpenSearch"。
3. 在集群列表，选择目标集群，单击操作列的"Dashboards"，登录OpenSearch Dashboards。
4. 在OpenSearch Dashboards左侧导航栏选择"Dev Tools"，进入操作页面。 控制台左侧是命令输入框，其右侧的三角形图标为执行按钮，右侧区域则显示执行结果。
   
 
 #### 步骤一：创建模型组
模型组用于将多个同类模型或同一模型的多个版本组织为一个逻辑组，便于权限管理。模型组可以赋予Backend roles，通过security插件管理该模型组的访问权限。
- 非安全集群（集群的"安全模式"为"未开启"）不涉及权限管控，可跳过该步骤。
- 安全集群（集群的"安全模式"为"启用"）创建模型组为可选操作，不创建时模型按ML Commons插件默认权限访问；创建模型组后可通过Backend roles实现更细粒度的权限控制（通过Backend roles限制谁可以访问该模型）。
执行以下命令，创建Embedding模型组。
```
POST /_plugins/_ml/model_groups/_register
{
  "name": "embedding_model_group",
  "description": "A model group for external embedding models"
}
```
表3模型组配置参数说明 
| 参数          | 说明               | 示例值                                          |
|:---|:---|:---|
| name        | 自定义模型组名称。     | embedding_model_group                     |
| description | 模型组的描述信息，方便识别。 | A model group for external embedding models |
   
返回示例：
```
{
  "model_group_id": "DHCWnZgBEIau0nVrgXDm",
  "status": "CREATED"
}
```
记录返回的"model_group_id"，后续注册模型时需要使用。
 #### 步骤二：创建模型连接器
连接器用于定义OpenSearch与搜索大模型之间的连接方式，包括访问协议、输入输出格式和认证鉴权。
- 执行以下命令，创建Embedding连接器。
  ```
  POST /_plugins/_ml/connectors/_create
  {
    "name": "embedding connector",
    "description": "The connector to public embedding models",
    "version": 1,
    "protocol": "http",
    "parameters": {
      "endpoint": "<搜索大模型地址>:<端口>",
      "model": "query2doc"
    },
    "credential": {
      "api_key": "abc"
    },
    "actions": [
      {
        "action_type": "predict",
        "method": "POST",
        "url": "http://${parameters.endpoint}/v1/embeddings",
        "headers": {
          "Content-Type": "application/json"
        },
        "request_body": "{ \"input\": ${parameters.input}, \"model\": \"${parameters.model}\" }",
        "pre_process_function": "connector.pre_process.openai.embedding",
        "post_process_function": "connector.post_process.openai.embedding"
      }
    ]
  }
  ```
  
- 执行以下命令，创建Rerank连接器。
  ```
  POST /_plugins/_ml/connectors/_create
  {
    "name": "pangu rerank connector",
    "description": "The connector to public rerank models",
    "version": 1,
    "protocol": "http",
    "parameters": {
      "endpoint": "<搜索大模型地址>:<端口>",
      "model": "rerank",
      "response_filter": "$.results"
    },
    "credential": {
      "api_key": "abc"
    },
    "actions": [
      {
        "action_type": "predict",
        "method": "POST",
        "url": "http://${parameters.endpoint}/v1/rerank",
        "headers": {
          "Content-Type": "application/json"
        },
        "request_body": "{ \"documents\":${parameters.documents}, \"query\": \"${parameters.query}\", \"model\": \"${parameters.model}\", \"top_n\": ${parameters.top_n}}",
        "pre_process_function": "connector.pre_process.default.rerank",
        "post_process_function": "connector.post_process.default.rerank"
      }
    ]
  }
  ```
  
表4连接器配置参数说明 
| 参数                               | 说明                                                                                                                  | 示例值（Embedding）                               |
|:---|:---|:---|
| name                                | 自定义连接器名称。                                                                                                          | pangu embedding connector                     |
| description                       | 连接器的描述信息，方便识别。                                                                                                       | The connector to public embedding models      |
| protocol                          | 连接器访问模型服务的协议，取值为http或https，取决于模型服务端支持的协议。                                                                            | http                                       |
| parameters.endpoint               | 模型服务的访问地址和端口，从模型服务端获取。 独享版集群的默认端口为18088，MaaS服务或其他外部模型服务以实际端口为准。      | 10.10.1.117:18088                          |
| parameters.model                     | 模型标识，从模型服务端获取。 独享版集群为创建时选择的模型版本标识，MaaS服务为订阅时的模型名称，其他外部模型服务为部署时指定的名称。 | query2doc                                   |
| credential.api_key                 | 调用模型服务的认证密钥。当模型服务要求鉴权时（如MaaS服务）必填；当模型服务无鉴权要求时（如独享版集群内网访问）省略此参数。                                                       | abc                                          |
| actions\[0\].url                  | 模型服务的请求URL，引用parameters中的endpoint变量。                                                                                   | http://${parameters.endpoint}/v1/embeddings |
| actions\[0\].pre_process_function | 预处理函数，将输入数据转换为模型所需的格式。                                                                                               | connector.pre_process.openai.embedding    |
| actions\[0\].post_process_function | 后处理函数，将模型返回结果转换为OpenSearch所需格式。                                                                                     | connector.post_process.openai.embedding    |
   
![](https://support.huaweicloud.com/usermanual-css/public_sys-resources/caution_3.0-zh-cn.png)
- "pre_process_function"和"post_process_function"必须设置，否则后续对接写入管道和搜索管道时会因输入输出格式不匹配而报错。配置指导请参见[Connector blueprints - OpenSearch Documentation](https://docs.opensearch.org/3.4/ml-commons-plugin/remote-models/blueprints#built-in-pre--and-post-processing-functions)。
- 连接Embedding和Rerank模型时，OpenSearch内置了OpenAI格式的Embedding和Rerank处理函数，如果模型接口格式不同，可使用Painless语法自定义处理函数。
 
返回示例：
```
{
  "connector_id": "23CmnZgBEIau0nVrGHCp"
}
```
记录返回的"connector_id"，后续注册模型时需要使用。
 #### 步骤三：注册并部署模型
通过连接器注册远程模型并立即部署，使其可供写入管道和搜索查询调用。
- 执行以下命令，注册并部署Embedding模型。
  ```
  POST /_plugins/_ml/models/_register?deploy=true
  {
    "name": "embedding model",
    "function_name": "remote",
    "model_group_id": "<模型组ID>",
    "description": "embedding model",
    "connector_id": "<连接器ID>"
  }
  ```
  
- 执行以下命令，注册并部署Rerank模型。
  ```
  POST /_plugins/_ml/models/_register?deploy=true
  {
    "name": "rerank model",
    "function_name": "remote",
    "model_group_id": "<模型组ID>",
    "description": "rerank model",
    "connector_id": "<连接器ID>"
  }
  ```
  
表5模型注册参数说明 
| 参数           | 说明                                                                                                                                                                                          | 示例值（Embedding）      |
|:---|:---|:---|
| deploy          | URL参数，指定注册后立即部署模型。                                                                                                                                                                        | true                 |
| name          | 自定义注册模型的名称，即模型在OpenSearch中显示的名称。                                                                                                                                                          | embedding model       |
| function_name | 模型类型，通过连接器访问外部模型服务时固定为"remote"。                                                                                                                                                             | remote                |
| model_group_id | 模型组ID，即[步骤一：创建模型组]返回的"model_group_id"。 可选参数，安全集群创建模型组后填写以实现权限管控；非安全集群或未创建模型组时省略此参数。 | DHCWnZgBEIau0nVrgXDm    |
| description  | 注册模型的描述信息，方便识别。                                                                                                                                                                            | embedding model        |
| connector_id  | 连接器ID，即[步骤二：创建模型连接器]返回的"connector_id"。                                                                                                | 23CmnZgBEIau0nVrGHCp |
   
返回示例：
```
{
  "task_id": "cHCxnZgBEIau0nVrb3G_",
  "status": "CREATED",
  "model_id": "aEJ7P58BSQOU_3XGorlP"
}
```
![](https://support.huaweicloud.com/usermanual-css/public_sys-resources/note_3.0-zh-cn.png)
模型部署为异步操作，返回"task_id"后需要等待部署完成，预计等待时间约1\~10秒。可通过GET /_plugins/_ml/tasks/<task_id>查询部署状态，"state"为"COMPLETED"表示部署完成。
记录返回的"model_id"，后续创建写入管道和执行检索时需要使用。
 #### 步骤四：测试模型可用性
通过_predict接口测试模型是否配置正确，验证模型服务连通性和输出格式。
- 执行以下命令，测试Embedding模型的可用性。
  ```
  POST /_plugins/_ml/models/<model_id>/_predict
  {
    "parameters": {
      "input": ["太阳", "晴天"]
    }
  }
  ```
  表6模型测试参数说明 
  | 参数      | 说明                                                                                                  | 示例值                |
  |:---|:---|:---|
  | model_id | 模型ID，即[步骤三：注册并部署模型]返回的Embedding模型的"model_id"。 | aEJ7P58BSQOU_3XGorlP |
     
  返回示例（部分）：
  ```
  {
    "inference_results": [
      {
        "output": [
          {
            "name": "response",
            "dataAsMap": {
              "embeddings": [
                {
                  "values": [0.0123, -0.0456, 0.0789, ...]
                }
              ]
            }
          }
        ]
      }
    ]
  }
  ```
  结果验证：如果成功返回包含浮点数数组的向量嵌入结果，则表示模型配置正确，可以继续后续步骤。如果返回错误，请检查连接器配置中的"endpoint"地址是否正确、安全组是否放通模型服务端口和9200端口。
  
- 执行以下命令，测试Rerank模型的可用性。
  ```
  POST /_plugins/_ml/models/<model_id>/_predict
  {
    "parameters": {
      "query": "小学数学难不难？",
      "top_n": 4,
      "documents": [
        "小学数学主要学习加减乘除，难度不大，是基础阶段。",
        "初中数学开始引入代数和几何，难度逐渐增加。",
        "大学数学涉及微积分和线性代数，难度较大。",
        "小学语文主要学习拼音和识字。"
      ]
    }
  }
  ```
  返回示例：
  ```
  {
    "inference_results": [
      {
        "output": [
          {
            "name": "similarity",
            "data_type": "FLOAT32",
            "shape": [
              1
            ],
            "data": [
              0.9980276
            ]
          },
          {
            "name": "similarity",
            "data_type": "FLOAT32",
            "shape": [
              1
            ],
            "data": [
              0.5402266
            ]
          },
          {
            "name": "similarity",
            "data_type": "FLOAT32",
            "shape": [
              1
            ],
            "data": [
              0.03015741
            ]
          },
          {
            "name": "similarity",
            "data_type": "FLOAT32",
            "shape": [
              1
            ],
            "data": [
              0.01433703
            ]
          }
        ],
        "status_code": 200
      }
    ]
  }
  ```
  结果验证：如果成功返回结果，则表示模型配置正确，可以继续后续步骤。
  
 
 #### 步骤五：创建写入管道
创建写入管道，在文档写入时自动调用模型，将文本字段转换为向量嵌入。
执行以下命令，创建Embedding模型的写入管道nlp-ingest-pipeline。
```
PUT /_ingest/pipeline/nlp-ingest-pipeline
{
  "description": "A text embedding pipeline",
  "processors": [
    {
      "text_embedding": {
        "model_id": "<Embedding模型ID>",
        "field_map": {
          "passage_text": "passage_embedding"
        }
      }
    }
  ]
}
```
表7写入管道配置参数说明 
| 参数                   | 说明                                                                                                                   | 示例值                                   |
|:---|:---|:---|
| *nlp-ingest-pipeline* | 自定义写入管道的名称。                                                                                                         | nlp-ingest-pipeline                    |
| description          | 写入管道的描述信息。                                                                                                           | A text embedding pipeline             |
| text_embedding         | OpenSearch写入管道的固定处理器名称。文档写入时，管道会自动运行text_embedding处理器，将passage_text字段的文本转换为向量嵌入并存储在passage_embedding字段中，实现数据自动向量化。 | -                                       |
| model_id              | Embedding模型ID，即[步骤三：注册并部署模型]返回的Embedding模型的"model_id"。       | aEJ7P58BSQOU_3XGorlP                   |
| field_map             | 字段映射关系，左侧为输入文本字段名，右侧为输出向量字段名。                                                                                       | {"passage_text": "passage_embedding"} |
   
结果验证：返回结果包含""acknowledged": true"则表示执行成功。
 #### 步骤六：创建向量索引
创建同时包含文本字段和向量字段的索引，并将创建的写入管道关联为默认管道。
执行以下命令，创建向量索引my-nlp-index。
```
PUT /my-nlp-index
{
  "settings": {
    "index.knn": true,
    "default_pipeline": "nlp-ingest-pipeline"
  },
  "mappings": {
    "properties": {
      "passage_embedding": {
        "type": "knn_vector",
        "dimension": 768,
        "method": {
          "engine": "faiss",
          "space_type": "innerproduct",
          "name": "hnsw"
        }
      },
      "passage_text": {
        "type": "text"
      }
    }
  }
}
```
表8索引配置参数说明 
| 参数                                  | 说明                                                                                                               | 示例值                 |
|:---|:---|:---|
| *my-nlp-index*                     | 自定义索引名称。                                                                                                         | my-nlp-index       |
| index.knn                            | 启用k-NN检索功能，固定为"true"。                                                                                           | true               |
| default_pipeline                   | 关联的默认写入管道名称，与[步骤五：创建写入管道]的管道名称一致。在文档写入时自动调用模型，将文本字段转换为向量嵌入。 | nlp-ingest-pipeline |
| passage_embedding.type               | 向量字段类型，固定为"knn_vector"。                                                                                          | knn_vector           |
| passage_embedding.dimension          | 向量维度，必须与Embedding模型的输出维度一致。                                                                                      | 768                  |
| passage_embedding.method.engine    | 向量检索引擎，可选择faiss或lucene，根据模型特性和业务需求选择。                                                                           | faiss               |
| passage_embedding.method.space_type | 距离度量方式，可选择l2（欧氏距离）或innerproduct（内积），根据模型特性和业务需求选择。使用内积空间类型时，需要先将向量归一化。                                          | innerproduct         |
| passage_embedding.method.name      | 索引算法名称，固定为"hnsw"。                                                                                                | hnsw              |
| passage_text.type                   | 文本字段类型，固定为"text"。                                                                                                 | text              |
   
结果验证：返回结果包含""acknowledged": true"则表示执行成功。
 #### 步骤七：写入文档数据
将文档写入到索引中。由于索引已关联写入管道，只需提供passage_text字段，向量嵌入会由写入管道自动生成。
- 执行以下命令，写入单条数据。
  ```
  POST /my-nlp-index/_doc/1
  {
    "passage_text": "系统报错403：用户缺乏管理员权限。请检查IAM角色中的policy权限策略配置。"
  }
  ```
  
- 执行以下命令，写入多条数据。
  ```
  POST /my-nlp-index/_bulk
  {"index": {"_id": 2}}
  {"passage_text": "如果遇到无法保存文件或者修改被拒绝的情况，请确认您是否被分配了编辑和修改内容的资格。"}
  {"index": {"_id": 3}}
  {"passage_text": "财务部正式发布上季度财务报告声明。本声明详细阐述了公司在政策（policy）补贴以及税务合规方面的资金支出状况。"}
  {"index": {"_id": 4}}
  {"passage_text": "如果在更新文档时系统提示由于受到限制而无法执行，应当向团队负责人申请，开通针对该内容的变更和操作授权。"}
  ```
  
在文档被写入到索引之前，写入管道会在文档上运行"text_embedding"处理器，为passage_text字段生成文本嵌入。索引后的文档将同时包含原始文本的passage_text字段和向量嵌入的passage_embedding字段。
结果验证：
- 执行以下命令，如果返回的文档数量与写入数量一致，则表示数据写入成功。
  ```
  GET /my-nlp-index/_count
  ```
  
- 执行以下命令，查看写入的文档以及文档被转换后的向量内容，确认写入管道生效。
  ```
  GET /my-nlp-index/_search
  ```
  返回示例（部分）：
  ```
  "hits": {
      "total": {
        "value": 4,
        "relation": "eq"
      },
      "max_score": 1,
      "hits": [
         {
          "_index": "my-nlp-index-2",
          "_id": "4",
          "_score": 1,
          "_source": {
            "passage_embedding": [
              -0.10803223,
              -0.31982422,
              0.023406982,
              ......
            ],
            "passage_text": "如果在更新文档时系统提示由于受到限制而无法执行，应当向团队负责人申请，开通针对该内容的变更和操作授权。"
          }
        },
         ......
      ]
    }
  ```
  passage_text是写入的文本信息，passage_embedding是文本转换后的向量数据。
  
 
 #### 步骤八：执行语义检索
通过neural查询进行语义检索。neural查询会自动调用Embedding模型将查询文本转换为向量，然后执行kNN检索。
执行以下命令，进行语义检索。
```
GET /my-nlp-index/_search
{
  "_source": {
    "excludes": ["passage_embedding"]
  },
  "query": {
    "neural": {
      "passage_embedding": {
        "query_text": "没有更新文件的资格该怎么办",
        "model_id": "<Embedding模型ID>",
        "k": 1
      }
    }
  }
}
```
表9neural查询参数说明 
| 参数               | 说明                                                                                                          | 示例值                    |
|:---|:---|:---|
| _source.excludes | 从返回结果中排除指定字段，避免返回大维度向量数据影响可读性。                                                                               | \["passage_embedding"\] |
| neural         | 语义检索子句，基于向量近邻搜索进行语义匹配。passage_embedding为索引中的向量字段名。                                                             | -                       |
| neural.query_text | 语义查询文本，由Embedding模型自动转换为向量进行搜索。                                                                               | 没有更新文件的资格该怎么办           |
| neural.model_id | Embedding模型ID，即[步骤三：注册并部署模型]返回的Embedding模型的"model_id"。 | aEJ7P58BSQOU_3XGorlP   |
| neural.k         | 返回最相似的文档数量。                                                                                                   | 1                        |
   
返回示例：
```
{
  "took": 21,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 104.77277,
    "hits": [
      {
        "_index": "my-nlp-index",
        "_id": "4",
        "_score": 104.77277,
        "_source": {
          "passage_text": "如果在更新文档时系统提示由于受到限制而无法执行，应当向团队负责人申请，开通针对该内容的变更和操作授权。"
        }
      },
      {
        "_index": "my-nlp-index",
        "_id": "2",
        "_score": 103.32463,
        "_source": {
          "passage_text": "如果遇到无法保存文件或者修改被拒绝的情况，请确认您是否被分配了编辑和修改内容的资格。"
        }
      }
    ]
  }
}
```
结果验证：如果成功返回语义相关的结果，则表示语义检索配置成功。
结果分析：从返回示例可以看出，语义检索成功召回与查询意图最相关的文档4和文档2。尽管查询文本"没有更新文件的资格该怎么办"与文档4、2的表述方式不同，但Embedding模型捕捉到了语义相似性，实现了基于意图的搜索。这是传统关键词搜索无法做到的。
 #### 步骤九：创建搜索管道
执行混合检索前，需要先创建搜索管道，用于对混合检索的结果进行归一化和组合。
混合搜索有两种可用的处理器类型：
- 归一化处理器（normalization-processor），基于分数归一化和组合。
- 分数排名器处理器（score-ranker processor），基于排名融合来组合和重排序。
混合搜索时，支持在搜索管道中添加Rerank处理器，将搜索过程分两个阶段处理结果：phase_results_processors中的归一化处理器先对多子查询分数进行组合，response_processors中的Rerank处理器再对组合后的结果进行二次精排。
- 执行以下命令，使用归一化处理器创建搜索管道my-search-pipeline。
  ```
  PUT /_search/pipeline/my-search-pipeline
  {
    "description": "Post processor for hybrid search",
    "phase_results_processors": [
      {
        "normalization-processor": {
          "normalization": {
            "technique": "min_max"
          },
          "combination": {
            "technique": "arithmetic_mean",
            "parameters": {
              "weights": [
                0.3,
                0.7
              ]
            }
          }
        }
      }
    ]
  }
  ```
  
- 执行以下命令，使用归一化处理器+Rerank处理器创建搜索管道my-search-pipeline。
  ```
  PUT /_search/pipeline/my-search-pipeline
  {
    "description": "Post processor for hybrid search",
    "phase_results_processors": [
      {
        "normalization-processor": {
          "normalization": {
            "technique": "min_max"
          },
          "combination": {
            "technique": "arithmetic_mean",
            "parameters": {
              "weights": [
                0.3,
                0.7
              ]
            }
          }
        }
      }
    ],
    "response_processors": [
      {
        "rerank": {
          "ml_opensearch": {
            "model_id": "<Rerank模型ID>"
          },
          "context": {
            "document_fields": [ "passage_text" ]
          }
        }
      }
    ]
  }
  ```
  
表10搜索管道配置参数说明 
| 参数                              | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | 示例值                             |
|:---|:---|:---|
| *my-search-pipeline*             | 自定义搜索管道的名称。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | my-search-pipeline             |
| description                      | 搜索管道的描述信息。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Post processor for hybrid search |
| normalization-processor         | 处理器类型名称，normalization-processor是归一化处理器。                                                                                                                                                                                                                                                                                                                                                                                                                                                            | -                               |
| normalization.technique        | 归一化技术，将各子查询的分数归一化到\[0, 1\]区间。 取值范围： - min_max：线性映射，将最大分数映射为1、最小分数映射为0，其他按比例计算。  - l2：L2范数归一化，每个分数除以所有分数平方和的平方根。                                                                                          | min_max                        |
| combination.technique           | 组合技术，对归一化后的分数进行加权组合。 取值范围： - arithmetic_mean：算术平均加权。  - geometric_mean：几何平均加权。  - harmonic_mean：调和平均加权。   | arithmetic_mean                |
| combination.parameters.weights | 权重数组，以小数百分比形式指定每个查询子句的权重。 数组长度与hybrid查询中queries数组的子句数量一致，顺序对应，第一个权重对应queries数组中的第一个查询子句，第二个权重对应第二个查询子句。 权重数组的配置建议请参见[问题1：创建搜索管道时，如何调整混合检索权重]。                                                                                                                                                                                                          | \[0.3, 0.7\]                   |
| rerank                           | Rerank处理器名称，固定关键字，配置在response_processors中，在归一化处理器完成后执行，对初步排序结果进行二次精排。                                                                                                                                                                                                                                                                                                                                                                                                                              | -                               |
| rerank.ml_opensearch            | Rerank模型配置块，固定关键字。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | -                               |
| rerank.ml_opensearch.model_id   | Rerank模型ID，即[步骤三：注册并部署模型]返回的Rerank模型的"model_id"。                                                                                                                                                                                                                                                                                                                                                                                            | bFJ7P58BSQOU_3XGorlR           |
| rerank.context                 | Rerank上下文配置块，指定发送给Rerank模型的数据来源。                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | -                              |
| rerank.context.document_fields | 参与Rerank的文档字段列表，Rerank模型将读取这些字段的文本内容与查询文本进行语义相关性打分。                                                                                                                                                                                                                                                                                                                                                                                                                                               | \["passage_text"\]                |
   
 #### 步骤十：执行混合检索
混合检索通过搜索管道对来自不同查询子句的文档分数进行归一化和加权组合，实现更全面的搜索效果。本节提供多种混合检索方案：
- **方案一：组合关键词搜索与语义向量检索** （搜索管道不带Rerank处理器）
  执行以下命令，使用hybrid查询结合关键词搜索（match）与语义向量检索（neural），并通过search_pipeline参数指定新建的搜索管道。
  ```
  GET /my-nlp-index/_search?search_pipeline=my-search-pipeline
  {
    "_source": {
      "excludes": ["passage_embedding"]
    },
    "query": {
      "hybrid": {
        "queries": [
          {
            "match": {
              "passage_text": "没有更新文件的资格该怎么办"
            }
          },
          {
            "neural": {
              "passage_embedding": {
                "query_text": "没有更新文件的资格该怎么办",
                "model_id": "<Embedding模型ID>",
                "k": 5
              }
            }
          }
        ]
      }
    }
  }
  ```
  表11hybrid查询参数说明（match+neural） 
  | 参数                                 | 说明                                                                                                                                                                                                                                                       | 示例值                      |
  |:---|:---|:---|
  | search_pipeline                     | URL参数，指定搜索管道名称，与[步骤九：创建搜索管道]的管道名称一致，用于对混合检索结果进行归一化和加权组合。 支持设置默认搜索管道，避免每次查询都指定该参数，配置方式请参见[问题2：如何设置默认搜索管道]。 | my-search-pipeline         |
  | _source.excludes                    | 从返回结果中排除指定字段，避免返回大维度向量数据影响可读性                                                                                                                                                                                                                             | \["passage_embedding"\] |
  | hybrid.queries                         | 查询子句数组，包含一个或多个查询子句，各子句的分数由搜索管道归一化后按weights权重组合。数组顺序与搜索管道中"weights"数组的顺序一一对应。                                                                                                                                                                                | -                        |
  | match                                | 关键词搜索子句，基于BM25算法进行全文检索。                                                                                                                                                                                                                                   | -                          |
  | match.passage_text                  | passage_text为索引中的文本字段名，查询值为关键词文本。                                                                                                                                                                                                                          | 没有更新文件的资格该怎么办            |
  | neural                               | 语义检索子句，基于向量近邻搜索进行语义匹配。passage_embedding为索引中的向量字段名。                                                                                                                                                                                                        | -                         |
  | neural.passage_embedding.query_text | 语义查询文本，由Embedding模型自动转换为向量进行检索。                                                                                                                                                                                                                           | 没有更新文件的资格该怎么办             |
  | neural.passage_embedding.model_id    | Embedding模型ID，即[步骤三：注册并部署模型]返回的"model_id"。                                                                                                                                                           | aEJ7P58BSQOU_3XGorlP       |
  | neural.passage_embedding.k          | 返回最相似的文档数量。                                                                                                                                                                                                                                              | 5                       |
     
  返回示例：
  ```
  {
    "took": 24,
    "timed_out": false,
    "_shards": {
      "total": 1,
      "successful": 1,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": {
        "value": 4,
        "relation": "eq"
      },
      "max_score": 1,
      "hits": [
        {
          "_index": "my-nlp-index",
          "_id": "4",
          "_score": 1,
          "_source": {
            "passage_text": "如果在更新文档时系统提示由于受到限制而无法执行，应当向团队负责人申请，开通针对该内容的变更和操作授权。"
          }
        },
        {
          "_index": "my-nlp-index",
          "_id": "2",
          "_score": 0.7050488,
          "_source": {
            "passage_text": "如果遇到无法保存文件或者修改被拒绝的情况，请确认您是否被分配了编辑和修改内容的资格。"
          }
        },
        {
          "_index": "my-nlp-index",
          "_id": "3",
          "_score": 0.083689965,
          "_source": {
            "passage_text": "财务部正式发布上季度财务报告声明。本声明详细阐述了公司在政策（policy）补贴以及税务合规方面的资金支出状况。"
          }
        },
        {
          "_index": "my-nlp-index",
          "_id": "1",
          "_score": 0.001,
          "_source": {
            "passage_text": "系统报错403：用户缺乏管理员权限。请检查IAM角色中的policy权限策略配置。"
          }
        }
      ]
    }
  }
  ```
  验证方法：如果成功返回按归一化组合分数排序的结果，且max_score为1.0（min_max归一化的最大值），则表示混合检索配置成功。
  结果分析：查询"没有更新文件的资格该怎么办"时，混合检索返回4条结果，如[表12]所示。
   表12混合检索排名（match+neural） 
  | 排名  | 文档ID | 归一化分数  | 内容摘要                        | 匹配分析            |
  |:---|:---|:---|:---|:---|
  | 1  | 4    | 1.0    | 更新文档时受限制，应申请变更和操作授权。     | 语义高度匹配，关键词部分匹配。   |
  | 2 | 2 | 0.705  | 无法保存文件或修改被拒绝，应确认资格。       | 语义匹配，关键词部分匹配。    |
  | 3 | 3    | 0.084 | 财务报告涉及政策（policy）补贴。         | 仅关键词弱匹配，语义不相关。    |
  | 4   | 1   | 0.001 | 系统报错403，IAM角色policy权限策略。 | 仅关键词弱匹配，语义不相关。 |
     
  与纯语义检索（[步骤八：执行语义检索]）相比，混合检索具有以下优势：
  - 保留语义匹配优势：文档4和文档2凭借语义相似性排在前两位，与纯语义检索结果一致。
  
  - 关键词匹配补充召回：文档3和文档1因包含"policy"等关键词被召回，尽管语义相关性较低，但丰富了检索覆盖范围。
  
  - 归一化分数有效排序：语义不相关的文档（文档3、1）获得较低分数，排在后两位，兼顾了召回率和精确率。
   
- **方案二：组合关键词搜索与精准匹配** （搜索管道不带Rerank处理器）
  此方案仅通过搜索管道对两个文本查询子句的分数进行归一化组合，适用于需要融合多种文本匹配策略、但不依赖语义向量的场景。
  执行以下命令，使用hybrid查询结合关键词搜索（match）与精准匹配（term），并通过search_pipeline参数指定新建的搜索管道。
  ```
  GET /my-nlp-index/_search?search_pipeline=my-search-pipeline
  {
    "_source": {
      "excludes": ["passage_embedding"]
    },
    "query": {
      "hybrid": {
        "queries": [
          {
            "match": {
              "passage_text": "权限"
            }
          },
          {
            "term": {
              "passage_text": {
                "value": "policy"
              }
            }
          }
        ]
      }
    }
  }
  ```
  表13hybrid查询参数说明（match+term） 
  | 参数                    | 说明                                                                                                                                                                                                                                                         | 示例值                      |
  |:---|:---|:---|
  | search_pipeline         | URL参数，指定搜索管道名称，与[步骤九：创建搜索管道]的管道名称一致，用于对混合检索结果进行归一化和加权组合。 支持设置默认搜索管道，避免每次查询都指定该参数，配置方式请参见[问题2：如何设置默认搜索管道]。 | my-search-pipeline        |
  | _source.excludes        | 从返回结果中排除指定字段，避免返回大维度向量数据影响可读性                                                                                                                                                                                                                                 | \["passage_embedding"\] |
  | hybrid.queries           | 查询子句数组，包含一个或多个查询子句，各子句的分数由搜索管道归一化后按weights权重组合。数组顺序与搜索管道中"weights"数组的顺序一一对应。                                                                                                                                                                               | -                         |
  | match                    | 关键词搜索子句，基于BM25算法进行全文检索。                                                                                                                                                                                                                                        | -                     |
  | match.passage_text      | passage_text为索引中的文本字段名，查询值为关键词文本。                                                                                                                                                                                                                           | 权限                     |
  | term                    | 精确匹配子句，对指定字段进行精确词项匹配。                                                                                                                                                                                                                                        | -                      |
  | term.passage_text.value | passage_text为索引中的文本字段名，value为精确匹配的词项。                                                                                                                                                                                                                          | policy                |
     
  返回示例：
  ```
  {
    "took": 10,
    "timed_out": false,
    "_shards": {
      "total": 1,
      "successful": 1,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": {
        "value": 3,
        "relation": "eq"
      },
      "max_score": 1,
      "hits": [
        {
          "_index": "my-nlp-index",
          "_id": "1",
          "_score": 1,
          "_source": {
            "passage_text": "系统报错403：用户缺乏管理员权限。请检查IAM角色中的policy权限策略配置。"
          }
        },
        {
          "_index": "my-nlp-index",
          "_id": "3",
          "_score": 0.5,
          "_source": {
            "passage_text": "财务部正式发布上季度财务报告声明。本声明详细阐述了公司在政策（policy）补贴以及税务合规方面的资金支出状况。"
          }
        },
        {
          "_index": "my-nlp-index",
          "_id": "4",
          "_score": 0.3,
          "_source": {
            "如果在更新文档时系统提示由于受到限制而无法执行，应当向团队负责人申请，开通针对该内容的变更和操作授权。"
          }
        }
      ]
    }
  }
  ```
  验证方法：如果成功返回按归一化组合分数排序的结果，且max_score为1.0，则表示混合检索配置成功。
  结果分析：查询"权限"（match）和"policy"（term）时，混合检索返回3条结果，如表所示。
  表14混合检索排名（match+term） 
  | 排名   | 文档ID | 归一化分数 | 内容摘要                     | 匹配分析                                     |
  |:---|:---|:---|:---|:---|
  | 1 | 1   | 1.0    | 系统报错403，IAM角色policy权限策略。 | match匹配"权限"，term精确匹配"policy"。          |
  | 2 | 3 | 0.5 | 财务报告涉及政策（policy）补贴。    | term匹配"policy"，match未匹配"权限"。             |
  | 3   | 4 | 0.3 | 更新文档时受限制，应申请变更和操作授权。     | match匹配"权限"（"授权"语义近似），term未匹配"policy"。 |
     
  
- **方案三：组合关键词搜索与语义向量检索** （搜索管道带Rerank处理器）
  执行以下命令，使用hybrid查询结合关键词搜索（match）与语义向量检索（neural），并通过search_pipeline参数指定带Rerank处理器的搜索管道。
  ```
  GET /my-nlp-index/_search?search_pipeline=my-search-pipeline
  {
    "_source": {
      "excludes": ["passage_embedding"]
    },
    "query": {
      "hybrid": {
        "queries": [
          {
            "match": {
              "passage_text": "没有更新文件的资格该怎么办"
            }
          },
          {
            "neural": {
              "passage_embedding": {
                "query_text": "没有更新文件的资格该怎么办",
                "model_id": "<Embedding模型ID>",
                "k": 5
              }
            }
          }
        ]
      }
    },
    "ext": {
      "rerank": {
        "query_context": {
          "query_text": "没有更新文件的资格该怎么办"
        }
      }
    }
  }
  ```
  表15hybrid查询中rerank参数说明 
  | 参数                       | 说明                                 | 示例值            |
  |:---|:---|:---|
  | query_context.query_text | Rerank模型接收的query值。建议和query查询中的值一致。 | 没有更新文件的资格该怎么办 |
     
  验证方法与结果分析：返回结果的排序与未配置Rerank处理器时不同，且_score值发生变化（Rerank分数替代了归一化组合分数）。
  
 
#### 常见问题
- **问题1：创建搜索管道时，如何调整混合检索权重？**
  根据业务场景调整weights参数，可以改变关键词搜索和向量检索的影响力：
  - 偏重语义匹配：增大向量检索的权重，如\[0.2, 0.8\]，适用于同义词丰富、语义理解优先的场景。
  
  - 偏重关键词匹配：增大关键词搜索的权重，如\[0.7, 0.3\]，适用于术语精确匹配优先的场景。
  
  - 均衡组合：权重设为\[0.5, 0.5\]，两种检索方式等权组合。
   
- **问题2：如何设置默认搜索管道？**
  可以为索引设置默认搜索管道，避免每次查询时都需要指定"search_pipeline"参数。
  执行以下命令，为索引my-nlp-index设置默认搜索管道my-search-pipeline。
  ```
  PUT /my-nlp-index/_settings
  {
    "index.search.default_pipeline": "my-search-pipeline"
  }
  ```
  设置后，对该索引的查询将自动应用搜索管道。
  
- **问题3：** **写入文档时报错"vector dimension mismatch"**
  **原因**：索引中knn_vector字段的dimension参数与Embedding模型实际输出维度不一致。
  **解决**：通过_predict接口获取模型输出向量，确认向量维度，然后重新创建索引，将dimension参数设置为与模型输出维度一致的值。
  
- **问题4：** **写入管道或搜索管道报错"input/output format mismatch"**
  **原因**：连接器未设置pre_process_function或post_process_function，导致输入输出格式与管道要求不匹配。
  **解决**：在连接器配置中添加OpenAI格式的预处理和后处理函数（connector.pre_process.openai.embedding和connector.post_process.openai.embedding）。如果模型接口格式与OpenAI格式不同，需使用Painless语法自定义处理函数。
  
 
#### 相关文档
- [OpenSearch AI search](https://docs.opensearch.org/3.4/vector-search/ai-search/index/)：OpenSearch社区语义搜索官方文档，介绍neural查询和hybrid查询的详细语法。
- [OpenSearch Machine learning](https://docs.opensearch.org/latest/ml-commons-plugin/)：OpenSearch社区ML Commons插件官方文档，介绍连接器、模型注册和部署的完整API。
- [CSS向量数据库](https://support.huaweicloud.com/usermanual-css/css_01_0143.html)：了解CSS支持的向量索引算法和参数配置。
 
