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

Elasticsearch中单文档多向量的余弦相似度查询实现

Elasticsearch单文档多向量的余弦相似度查询实现

完全可以实现单文档多向量场景下的余弦相似度查询,核心思路是遍历文档内所有向量计算相似度,取最大值作为文档的最终得分,或者通过嵌套字段优化性能。以下是两种常用方案:

方案一:脚本实时计算最大相似度(适合向量数量少的场景)

如果每个文档的向量数量不多,可以直接在查询时用脚本遍历所有向量,计算每个向量与查询向量的余弦相似度,取最大值作为文档得分。

1. 索引结构示例

假设你的documents索引中,embeddings字段是存储多个向量的数组(维度以128为例):

PUT /documents
{
  "mappings": {
    "properties": {
      "text_fragment": { "type": "text" },
      "embeddings": { 
        "type": "dense_vector",
        "dims": 128,
        "index": true,
        "similarity": "cosine"
      }
    }
  }
}

2. 查询DSL

使用function_score结合脚本计算每个文档的最大相似度得分:

GET /documents/_search
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "functions": [
        {
          "script_score": {
            "script": {
              "source": """
                float maxScore = -1;
                for (def vec : params._source.embeddings) {
                  float score = cosineSimilarity(vec, params.queryVector);
                  if (score > maxScore) {
                    maxScore = score;
                  }
                }
                return maxScore;
              """,
              "params": {
                "queryVector": [0.1, 0.2, ..., 0.128] // 替换为你的查询向量
              }
            }
          }
        }
      ],
      "score_mode": "max",
      "boost_mode": "replace"
    }
  },
  "sort": [
    { "_score": { "order": "desc" } }
  ]
}

方案二:嵌套字段优化性能(适合向量数量多的场景)

如果每个文档包含大量向量,推荐将每个向量与对应子文本片段存为嵌套文档,利用Elasticsearch的向量索引优化查询性能,同时能直接返回最相似的子片段。

1. 修改索引映射

将向量字段改为嵌套类型:

PUT /documents
{
  "mappings": {
    "properties": {
      "text_fragment": { "type": "text" },
      "vector_entries": {
        "type": "nested",
        "properties": {
          "embedding": {
            "type": "dense_vector",
            "dims": 128,
            "index": true,
            "similarity": "cosine"
          },
          "sub_fragment": { "type": "text" } // 对应该向量的子文本片段
        }
      }
    }
  }
}

2. 查询DSL

通过nested查询匹配最相似的向量,并用inner_hits返回对应的子片段:

GET /documents/_search
{
  "query": {
    "nested": {
      "path": "vector_entries",
      "query": {
        "script_score": {
          "query": { "match_all": {} },
          "script": {
            "source": "cosineSimilarity(params.queryVector, 'vector_entries.embedding') + 1.0",
            "params": {
              "queryVector": [0.1, 0.2, ..., 0.128] // 替换为你的查询向量
            }
          }
        }
      },
      "inner_hits": {
        "_source": ["vector_entries.sub_fragment"],
        "sort": [
          { "_score": { "order": "desc" } }
        ]
      }
    }
  },
  "sort": [
    { "_score": { "order": "desc" } }
  ]
}

方案选择

  • 若每个文档的向量数量较少(比如个位数),方案一简单直接,无需修改现有索引结构;
  • 若向量数量较多(数十个及以上),方案二能利用Elasticsearch的近似最近邻(ANN)优化,查询性能更优,还能精准定位到最相似的子文本片段。

内容的提问来源于stack exchange,提问作者Francesco Pettini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:48:15