混合检索(Hybrid Search)是一种综合运用多种搜索技术的智能检索方法,通过结合不同检索范式的优势来提升搜索效果,它可以帮助大模型快速筛选出最相关、最有价值的数据,更精准地满足用户复杂多样的搜索需求。随着大模型技术的不断发展和应用场景的日益拓展,混合检索的重要性也愈发凸显。
当前的 OpenSearch 集群中,主要支持两种查询方式:
两种查询方式各有优点,看起来是一种互为补充的关系,如果能将两种查询结合在一起,直观上查询效果将会得到提升。一种直观的方式是类似预先查询语句,即将两个查询语句的返回结果分数进行加权求和并返回。
// 加权求和的混合查询: { "query": { "bool": { "should": [ { "constant_score": { "${关键词查询}", "boost": 0.4 } }, { "constant_score": { "${向量查询}", "boost": 0.6 } } ] } } }
但这种查询方式比较简单,但是也存在一些不足:
为解决上述的缺陷,云搜索在原先的两阶段查询中,原生支持分数归一化和加权求和两个步骤,这样便可以充分结合多路查询的优势,达到互补的效果。
同时为了能够更加显著地提升用户搜索结果的相关性,云搜索服务混合检索功能除了支持现有的向量和文本融合打分之外,还支持可插拔的rerank
模型重排阶段,允许用户根据自身的实际需求和特定场景,调用不同类型的模型(自定义模型、内置模型)对返回结果执行进一步的调优,整个查询过程得到了进一步的拓展和完善。
rerank
模型重排阶段:将查询结果进一步传给rerank
模型,得到进一步的调优结果。归一化有多种不同的算法,云搜索服务当前支持的算法如下:
计算当前所有数据中的最小值x_min
,以及最大值x_max
,然后将每条数据减去最小值并除以区间范围,转化成目标数据。归一化后的数据范围固定为[0, 1]。

特点:
计算当前所有数据的 L2 范数norm
,然后将每个数据除以 L2 范数,转化成目标数据。归一化后的数据范围固定为[0, 1]。

特点:
统计每条数据,在不同的序列中对应的排序位置r(d)
,然后将排序分数加上固定的参数值K
后,取倒数并相加,最终得到目标数据。

计算示例:
说明
为便于计算,此处取 K=0。
Query 1 结果排序 | Query 2 结果排序 | RRF 结果打分 |
---|---|---|
A 1 | E 1 | A:1 / 1 + 1 / 3 = 1.3 |
B 2 | C 2 | |
C 3 | A 3 | |
D 4 | B 4 | |
E 5 | 无 |
特点:
K=60
。计算当前所有数据中的平均值μ
,以及样本标准差σ
,然后将每条数据进行正态分布处理,转化成目标数据。结果数据大于 0 表示正相关,小于 0 则表示负相关,归一化后的数据范围不固定(在实现时,会将小于 0 的分数,赋予一个大于 0 的较小值,比如 0.001)。

特点:
min_max
和l2
,对异常点的处理效果更好,适用于最大最小值未知的场景。无特殊要求,一般选择arithmetic_mean
即可。
每个结果序列,授予的权重为:
每条数据与对应的权重相乘并求和,然后除以权重的总和,得到结果:

每条数据取对数之后,与对应的权重相乘并求和,然后除以权重的总和,再通过指数函数得到结果:

每条数据取倒数之后,与对应的权重相乘后求和,然后再用权重的总和除以前面的运算,得到结果:

创建 Search Pipeline 和索引。
rerank
模型地址。
// 创建Search Pipeline PUT /_search/pipeline/min-max-search-pipeline { "description": "Post processor for hybrid search", "phase_results_processors": [ { "normalization-processor": { "normalization": { "technique": "min_max", // 归一化方法 "parameters": { } }, "combination": { "technique": "arithmetic_mean", // 加权求和方法 "parameters": { "weights": [ 0.4, 0.6 ] } } } } ], "response_processors": [ // rerank 重排配置(可选) { "remote_rerank": { "ml_opensearch": { "remote_config": { "method": "POST", "url": "", // rerank 模型地址 "headers": { "Content-Type": "application/json" }, "advance_request_body": { "model": "" // 模型名称 } } }, "context": { "document_fields": [ "size" // 重排字段信息 ] } } } ] }
// 创建索引 PUT products-shirts { "settings": { "index": { "knn": true, "knn.algo_param.ef_search": 100, "number_of_shards": 1, "number_of_replicas": 0, "search.default_pipeline": "min-max-search-pipeline" // 对应的Search Pipeline名称 } }, "mappings": { "properties": { "item_vector": { "type": "knn_vector", "dimension": 3, "method": { "name": "hnsw", "space_type": "l2", "engine": "lucene", "parameters": { "ef_construction": 100, "m": 16 } } } } } }
写入数据。
使用向量写入数据。
// 写入数据 POST _bulk { "index": { "_index": "products-shirts", "_id": "1" } } { "item_vector": [5.2, 4.4, 8.4], "size" : "large", "rating" : 5 } { "index": { "_index": "products-shirts", "_id": "2" } } { "item_vector": [5.2, 3.9, 2.9], "size" : "small", "rating" : 4 } { "index": { "_index": "products-shirts", "_id": "3" } } { "item_vector": [4.9, 3.4, 2.2], "size" : "xlarge", "rating" : 9 } { "index": { "_index": "products-shirts", "_id": "4" } } { "item_vector": [4.2, 4.6, 5.5], "size" : "large", "rating" : 6} { "index": { "_index": "products-shirts", "_id": "5" } } { "item_vector": [3.3, 4.5, 8.8], "size" : "medium", "rating" : 8 } { "index": { "_index": "products-shirts", "_id": "6" } } { "item_vector": [6.4, 3.4, 6.6], "size" : "small", "rating" : 9 } { "index": { "_index": "products-shirts", "_id": "7" } } { "item_vector": [4.2, 6.2, 4.6], "size" : "small", "rating" : 5 } { "index": { "_index": "products-shirts", "_id": "8" } } { "item_vector": [2.4, 4.0, 3.0], "size" : "small", "rating" : 8 } { "index": { "_index": "products-shirts", "_id": "9" } } { "item_vector": [1.4, 3.2, 9.0], "size" : "small", "rating" : 5 } { "index": { "_index": "products-shirts", "_id": "10" } } { "item_vector": [7.0, 9.9, 9.0], "size" : "xlarge", "rating" : 9 } { "index": { "_index": "products-shirts", "_id": "11" } } { "item_vector": [3.0, 2.3, 2.0], "size" : "large", "rating" : 6 } { "index": { "_index": "products-shirts", "_id": "12" } } { "item_vector": [5.0, 1.0, 4.0], "size" : "large", "rating" : 3 }
// 混合查询 GET products-shirts/_search?search_pipeline=min-max-search-pipeline //可指定 Search Pipeline名称 { "size": 5, "query": { "hybrid": { "queries": [ { "match": { "size": { "query": "large" } } }, { "knn": { "item_vector": { "vector": [ // 查询向量 2, 3, 3 ], "k": 3, "filter": { "bool": [ { "term": { "filed": "a" } }, { "range": { "age": { "gte": 20 } } } ] } } } } ] } }, "ext": { // rerank重排配置(Optional) "remote_rerank": { "query_context": { "query_text": "rerank test" // rerank查询问题 } } } }
可在每次查询时灵活配置不同的权重。
// 混合查询 GET products-shirts/_search { "size": 5, "query": { "hybrid": { "queries": [ { "match": { "size": { "query": "large" } } }, { "knn": { "item_vector": { "vector": [ // 查询向量 2, 3, 3 ], "k": 3, "filter": { "bool": [ { "term": { "filed": "a" } }, { "range": { "field": { } } }, { "geo_point" { } } ] } } } } ] } }, "ext": { // rerank 重排配置(可选) "remote_rerank": { "query_context": { "query_text": "rerank test" // rerank 查询问题 } } }, "search_pipeline" : { // 临时 search_pipeline "phase_results_processors": [ { "normalization-processor": { "normalization": { "technique": "min_max", // 归一化方法 "parameters": { } }, "combination": { "technique": "arithmetic_mean", // 加权求和方法 "parameters": { "weights": [ 0.4, 0.6 ] } } } } ] } }
创建 Pipeline 和索引。
// 创建写入的 default_pipeline PUT _ingest/pipeline/remote_embedding { "description": "text embedding pipeline for remote inference", "processors": [ { "remote_embedding": { "remote_config": { "method": "POST", "url": "https://xxxx", "" "params": { //主要是在 http url 中注入 token 密钥等(openstudio) "token": "" }, "headers" : { //主要是在 http header 里面注入信息例如 token user等等 "Content-Type" : "application/json" }, "advance_request_body" : { //这个对应 OpenAi 协议中的 model "model" : "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" } }, "field_map": { "name": "name_knn", "desc": "desc_knn" } } } ] }
rerank
模型地址。
// 创建 Search Pipeline PUT /_search/pipeline/min-max-search-pipeline { "description": "Post processor for hybrid search", "request_processors": [ // 向量转化算子 { "remote_embedding": { "remote_config": { "method": "POST", "url": "https://xxxx", "" "params": { //主要是在 http url 中注入 token 密钥等(openstudio) "token": "" }, "headers" : { //主要是在 http header 里面注入信息,例如 token user 等 "Content-Type" : "application/json" }, "advance_request_body" : { //对应 OpenAi 协议中的 model "model" : "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" } } } } ], "phase_results_processors": [ // 归一化和加权算子 { "normalization-processor": { "normalization": { "technique": "min_max", // 归一化方法 "parameters": { } }, "combination": { "technique": "arithmetic_mean", // 加权求和方法 "parameters": { "weights": [ 0.4, 0.6 ] } } } } ], "response_processors": [ // rerank 重排配置(可选) { "remote_rerank": { "ml_opensearch": { "remote_config": { "method": "POST", "url": "", // rerank 模型地址 "headers": { "Content-Type": "application/json" }, "advance_request_body": { "model": "" // rerank 模型名称 } } }, "context": { "document_fields": [ "desc" // 重排字段信息 ] } } } ] }
// 创建索引 PUT remote_semantic { "settings": { "index": { "knn": true, "knn.algo_param.ef_search": 100, "number_of_shards": 1, "number_of_replicas": 0, "default_pipeline": "remote_embedding", // 对应的Ingest Pipeline名称 "search.default_pipeline": "min-max-search-pipeline" // 对应的Search Pipeline名称 } }, "mappings": { "properties": { "desc_knn": { "type": "knn_vector", "dimension": 384, "method": { "name": "hnsw", "engine": "nmslib", "space_type": "cosinesimil" } }, "name_knn": { "type": "knn_vector", "dimension": 384, "method": { "name": "hnsw", "engine": "nmslib", "space_type": "cosinesimil" } }, "desc": { "type": "text" }, "name": { "type": "text" } } } }
写入数据。
使用自然语言写入数据。
// 写入数据 POST remote_semantic/_doc?refresh { "desc": "red", "name": "t-shirt" }
// 混合查询 GET remote_semantic/_search?search_pipeline=min-max-search-pipeline //可指定 Search Pipeline 名称 { "size": 5, "query": { "hybrid": { "queries": [ { "match": { "size": { "query": "large" } } }, { "remote_neural": { "desc_knn": { // 搜索的 knn 域 "query_text": "yellow", // 搜索的内容 "k": 3 } } } ] } }, "ext": { // rerank 重排配置(可选) "remote_rerank": { "query_context": { "query_text": "rerank test" // rerank 查询问题 } } } }
可以在每次查询时灵活配置不同的权重。
// 混合查询 GET remote_semantic/_search { "size": 5, "query": { "hybrid": { "queries": [ { "match": { "size": { "query": "large" } } }, { "remote_neural": { "desc_knn": { // 搜索的 knn 域 "query_text": "yellow", // 搜索的内容 "k": 3 } } } ] } }, "ext": { // rerank 重排配置(可选) "remote_rerank": { "query_context": { "query_text": "rerank test" // rerank 查询问题 } } }, "search_pipeline" : { // 临时 search_pipeline "phase_results_processors": [ { "normalization-processor": { "normalization": { "technique": "min_max", // 归一化方法 "parameters": { } }, "combination": { "technique": "arithmetic_mean", // 加权求和方法 "parameters": { "weights": [ 0.4, 0.6 ] } } } } ] } }
随机选取不同规模的数据集,以 NDCG 为衡量指标,使用 BEIR 评估框架进行相关性评估,分别对简单的 bool(向量+文本)查询和不同归一化算法下的 Hybrid 混合查询进行实验,测试结果如下表所示。
说明
数据集 | 方式|指标 | bool 向量+文本 | Hybrid - min_max | Hybrid -min_max 对比 bool 结合 | Hybrid - rrf | Hybrid-rrf对比 bool 结合 | Hybrid - zscore | Hybrid-zscore 对比 bool 结合 |
---|---|---|---|---|---|---|---|---|
NFCorpus | NDCG@5 | 0.3398 | 0.3604 | 6.1% | 0.3626 | 6.7% | 0.3604 | 6.1% |
NDCG@10 | 0.3123 | 0.3271 | 4.7% | 0.3327 | 6.5% | 0.3288 | 5.3% | |
NDCG@100 | 0.282 | 0.2968 | 5.2% | 0.306 | 8.5% | 0.2963 | 5.1% | |
FIQA | NDCG@5 | 0.2194 | 0.2644 | 20.5% | 0.2712 | 23.6% | 0.298 | 35.8% |
NDCG@10 | 0.2446 | 0.289 | 18.2% | 0.3017 | 23.3% | 0.3281 | 34.1% | |
NDCG@100 | 0.3004 | 0.3522 | 17.2% | 0.3738 | 24.4% | 0.3883 | 29.3% | |
Quora | NDCG@5 | 0.7262 | 0.8028 | 10.5% | 0.8138 | 12.1% | 0.8512 | 17.2% |
NDCG@10 | 0.746 | 0.8189 | 9.8% | 0.83 | 11.3% | 0.8666 | 16.2% | |
NDCG@100 | 0.7721 | 0.8402 | 8.8% | 0.8506 | 10.2% | 0.8804 | 14.0% |
基于云搜索服务的混合检索和重排序实践--云搜索服务-火山引擎