You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化ElasticSearch script_score查询 避免Python循环计算物品相似度

Elasticsearch 批量相似度查询优化方案

你可以通过Elasticsearch的批量搜索API一次性提交所有相似度查询请求,完全避免Python端循环发起HTTP请求的网络开销,核心优化思路如下:

优化方案1:使用_msearch批量执行相似度查询

_msearch是ES原生提供的批量查询接口,可以在单次请求中打包多个独立的查询条件,ES会并行处理所有查询后统一返回结果,和原逻辑的查询结果完全一致,但网络IO次数从N+1(N为输入ID数量)降到固定2次。

改造后的代码如下:

from typing import List, Dict
from elasticsearch import Elasticsearch

def query_es_for_similar_items(es: Elasticsearch, item_ids: List[int], index: str, n=100) -> Dict[int, List[Dict]]:
    # 第一步:批量查询所有输入ID对应的向量,和原逻辑一致
    id_query = {"query": {"ids": {"type": "_doc", "values": item_ids}}}
    id_resp = es.search(index=index, body=id_query)
    item_vectors = {}
    for hit in id_resp["hits"]["hits"]:
        item_id = int(hit["_id"])
        item_vectors[item_id] = hit["_source"]["embeddings"]
    
    # 第二步:构造msearch批量查询请求,避免循环调用search
    msearch_body = []
    for item_id, vector in item_vectors.items():
        # 每个查询前先指定查询的索引
        msearch_body.append({"index": index})
        # 每个相似度查询的具体逻辑和原逻辑完全一致
        msearch_body.append({
            "size": n,
            "query": {
                "script_score": {
                    "query": {"bool": {"must_not": [{"ids": {"values": [item_id]}}]}},
                    "script": {
                        "source": "cosineSimilarity(params.query_value, doc[params.field]) + 1",
                        "params": {
                            "field": "embeddings",
                            "query_value": vector,
                        },
                    },
                }
            }
        })
    
    # 执行批量查询
    msearch_resp = es.msearch(body=msearch_body)
    
    # 处理返回结果,格式和原返回值完全一致
    d_res = {}
    for idx, item_id in enumerate(item_vectors.keys()):
        resp = msearch_resp["responses"][idx]
        ranked_scores = [
            {
                "item_id": hit["_id"],
                "similarity": hit["_score"] / 2
            } for hit in resp["hits"]["hits"]
        ]
        d_res[item_id] = ranked_scores
    return d_res

优化方案2:升级使用原生KNN查询(可选,ES 7.10+版本支持)

如果你使用的Elasticsearch版本≥7.10,推荐用原生的knn查询替代script_score计算余弦相似度,ES底层对向量检索做了专项优化,还可以开启HNSW向量索引大幅提升高维向量的检索速度,配合msearch使用效率提升会更明显,单条查询的结构可以调整为:

{
  "size": n,
  "knn": {
    "field": "embeddings",
    "query_vector": vector,
    "k": n,
    "num_candidates": n * 10, # 可根据召回精度需求调整
    "filter": {"bool": {"must_not": [{"ids": {"values": [item_id]}}]}}
  }
}

注意事项

  • 单次msearch打包的查询数量建议控制在1000以内,避免请求体过大导致ES处理超时
  • 如果输入ID的数量特别大,可以拆分多批msearch请求执行

内容的提问来源于stack exchange,提问作者Carl Rynegardh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 22:36:05