Link Search Menu Expand Document Documentation Menu

混合搜索

2.11 版引入

混合搜索结合了关键词搜索和语义搜索,以提高搜索相关性。要实现混合搜索,您需要设置一个在搜索时运行的搜索管道。该搜索管道在中间阶段拦截搜索结果,并应用处理来规范化和组合文档分数。

混合搜索有两种可用的处理器类型

  • 归一化处理器(2.10 版本引入):一种基于分数的处理器,用于归一化和组合来自多个查询子句的文档分数,使用所选的归一化和组合技术对文档进行重新评分。
  • 分数排名器处理器(2.19 版本引入):一种基于排名的处理器,使用排名融合来组合和重新排序来自多个查询子句的文档。

先决条件
要遵循此示例,您必须设置一个文本嵌入模型。更多信息请参见选择模型。如果您已生成文本嵌入,请跳到步骤 3

配置混合搜索有两种方式

  • 自动化工作流(推荐用于快速设置):以最少的配置自动创建摄入管道、索引和搜索管道。
  • 手动设置(推荐用于自定义配置):手动配置每个组件以获得更大的灵活性和控制。

自动化工作流

OpenSearch 提供了一个工作流模板,可自动创建摄入管道、索引和搜索管道。创建工作流时,您必须提供已配置模型的模型 ID。请查阅混合搜索工作流模板的默认值,以确定是否需要更新任何参数。例如,如果模型维度与默认值(1024)不同,请在 output_dimension 参数中指定模型的维度。要创建默认的混合搜索工作流,请发送以下请求

POST /_plugins/_flow_framework/workflow?use_case=hybrid_search&provision=true
{
"create_ingest_pipeline.model_id": "mBGzipQB2gmRjlv_dOoB"
}

OpenSearch 会为创建的工作流返回一个工作流 ID:

{
  "workflow_id" : "U_nMXJUBq_4FYQzMOS4B"
}

要检查工作流状态,请发送以下请求:

GET /_plugins/_flow_framework/workflow/U_nMXJUBq_4FYQzMOS4B/_status

工作流完成后,state 将变为 COMPLETED。该工作流创建以下组件

  • 一个名为 nlp-ingest-pipeline 的摄入管道
  • 一个名为 my-nlp-index 的索引
  • 一个名为 nlp-search-pipeline 的搜索管道

您现在可以继续步骤 4 和 5,将文档摄入到索引中并搜索索引。

手动设置

要手动配置混合搜索,请遵循以下步骤

  1. 创建摄入管道.
  2. 创建用于摄取的索引.
  3. 配置搜索管道.
  4. 将文档摄取到索引中.
  5. 使用混合搜索搜索索引.

步骤 1:创建摄入管道

要生成向量嵌入,您需要创建一个包含 text_embedding 处理器摄入管道,该处理器会将文档字段中的文本转换为向量嵌入。处理器的 field_map 决定了从中生成向量嵌入的输入字段以及存储嵌入的输出字段。

以下示例请求创建了一个摄入管道,它将 passage_text 中的文本转换为文本嵌入,并将嵌入存储在 passage_embedding

PUT /_ingest/pipeline/nlp-ingest-pipeline
{
  "description": "A text embedding pipeline",
  "processors": [
    {
      "text_embedding": {
        "model_id": "bQ1J8ooBpBj3wT4HVUsb",
        "field_map": {
          "passage_text": "passage_embedding"
        }
      }
    }
  ]
}

步骤 2:创建用于摄取的索引

为了使用管道中定义的文本嵌入处理器,请创建一个向量索引,并将上一步中创建的管道添加为默认管道。确保 field_map 中定义的字段映射为正确的类型。继续这个示例,passage_embedding 字段必须映射为维度与模型维度匹配的 k-NN 向量。同样,passage_text 字段应映射为 text

以下示例请求创建了一个设置了默认摄入管道的向量索引

PUT /my-nlp-index
{
  "settings": {
    "index.knn": true,
    "default_pipeline": "nlp-ingest-pipeline"
  },
  "mappings": {
    "properties": {
      "id": {
        "type": "text"
      },
      "passage_embedding": {
        "type": "knn_vector",
        "dimension": 768,
        "method": {
          "engine": "lucene",
          "space_type": "l2",
          "name": "hnsw",
          "parameters": {}
        }
      },
      "passage_text": {
        "type": "text"
      }
    }
  }
}

有关创建向量索引和使用支持方法的更多信息,请参见创建向量索引

步骤 3:配置搜索管道

要使用 normalization-processor 配置搜索管道,请使用以下请求。处理器中的归一化技术设置为 min_max,组合技术设置为 arithmetic_meanweights 数组以小数百分比形式指定分配给每个查询子句的权重。

PUT /_search/pipeline/nlp-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
            ]
          }
        }
      }
    }
  ]
}

步骤 4:将文档摄取到索引中

要将文档摄取到上一步创建的索引中,请发送以下请求:

PUT /my-nlp-index/_doc/1
{
  "passage_text": "Hello world",
  "id": "s1"
}

PUT /my-nlp-index/_doc/2
{
  "passage_text": "Hi planet",
  "id": "s2"
}

在文档被摄入到索引中之前,摄入管道会在文档上运行 text_embedding 处理器,为 passage_text 字段生成文本嵌入。索引文档包括包含原始文本的 passage_text 字段,以及包含向量嵌入的 passage_embedding 字段。

要在您的索引上执行混合搜索,请使用 hybrid 查询,它结合了关键词搜索和语义搜索的结果。

示例:组合神经查询和匹配查询

以下示例请求结合了两个查询子句——一个 neural 查询和一个 match 查询。它将上一步中创建的搜索管道指定为查询参数。

GET /my-nlp-index/_search?search_pipeline=nlp-search-pipeline
{
  "_source": {
    "exclude": [
      "passage_embedding"
    ]
  },
  "query": {
    "hybrid": {
      "queries": [
        {
          "match": {
            "passage_text": {
              "query": "Hi world"
            }
          }
        },
        {
          "neural": {
            "passage_embedding": {
              "query_text": "Hi world",
              "model_id": "aVeif4oB5Vm0Tdw8zYO2",
              "k": 5
            }
          }
        }
      ]
    }
  }
}

或者,您可以为 my-nlp-index 索引设置一个默认搜索管道。更多信息请参见默认搜索管道

响应包含匹配的文档

{
  "took" : 36,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.2251667,
    "hits" : [
      {
        "_index" : "my-nlp-index",
        "_id" : "1",
        "_score" : 1.2251667,
        "_source" : {
          "passage_text" : "Hello world",
          "id" : "s1"
        }
      }
    ]
  }
}

示例:组合匹配查询和术语查询

以下示例请求结合了两个查询子句——一个 match 查询和一个 term 查询。它将上一步中创建的搜索管道指定为查询参数。

GET /my-nlp-index/_search?search_pipeline=nlp-search-pipeline
{
  "_source": {
    "exclude": [
      "passage_embedding"
    ]
  },
  "query": {
    "hybrid": {
      "queries": [
           {
             "match":{
                 "passage_text": "hello"
              }
           },
           {
             "term":{
              "passage_text":{
                 "value":"planet"
              }
             }
           }
      ]
    }
  }
}

响应包含匹配文档:

{
    "took": 11,
    "timed_out": false,
    "_shards": {
        "total": 2,
        "successful": 2,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 0.7,
        "hits": [
            {
                "_index": "my-nlp-index",
                "_id": "2",
                "_score": 0.7,
                "_source": {
                    "id": "s2",
                    "passage_text": "Hi planet"
                }
            },
            {
                "_index": "my-nlp-index",
                "_id": "1",
                "_score": 0.3,
                "_source": {
                    "id": "s1",
                    "passage_text": "Hello world"
                }
            }
        ]
    }
}

后续步骤

  • 浏览我们的教程,了解如何构建 AI 搜索应用程序。

相关文章