Elasticsearch 向量搜索:余弦相似度匹配实现

1. 核心概念
  • 余弦相似度:衡量两个向量方向的相似性,计算公式: $$\cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{|\mathbf{A}| |\mathbf{B}|}$$ 其中 $\mathbf{A} \cdot \mathbf{B}$ 是点积,$|\mathbf{A}|$ 是向量模长。
  • 在 Elasticsearch 中:需使用 dense_vector 类型字段存储向量,通过脚本计算相似度。
2. 实现步骤
(1) 创建索引映射
PUT /vector_index
{
  "mappings": {
    "properties": {
      "text": { "type": "text" },   // 原始文本
      "embedding": {                // 向量字段
        "type": "dense_vector",
        "dims": 768,                // 向量维度 (如BERT输出)
        "index": true,              // 启用索引
        "similarity": "cosine"       // 指定余弦相似度
      }
    }
  }
}

(2) 插入文档(含向量)
POST /vector_index/_doc/1
{
  "text": "机器学习教程",
  "embedding": [0.12, -0.05, 0.87, ...]  // 768维向量
}

(3) 执行余弦相似度查询
GET /vector_index/_search
{
  "query": {
    "script_score": {
      "query": { "match_all": {} },
      "script": {
        "source": """
          // 计算余弦相似度
          double dot = 0.0;
          double normA = 0.0;
          double normB = 0.0;
          
          for (int i = 0; i < params.query_vector.length; ++i) {
            dot += params.query_vector[i] * doc['embedding'].get(i);
            normA += params.query_vector[i] * params.query_vector[i];
            normB += doc['embedding'].get(i) * doc['embedding'].get(i);
          }
          
          return dot / (Math.sqrt(normA) * Math.sqrt(normB));
        """,
        "params": {
          "query_vector": [0.15, -0.02, 0.91, ...]  // 查询向量
        }
      }
    }
  }
}

3. 关键参数说明
参数 作用 示例值
dense_vector 向量字段类型 必填
dims 向量维度 768 (BERT) / 512 (其他模型)
similarity 相似度算法 cosine
script_score 自定义评分查询 用于计算相似度
4. 优化建议
  • 归一化预处理:存储前将向量归一化(模长为1),可简化为点积计算: $$\cos(\theta) = \mathbf{A} \cdot \mathbf{B}$$
  • 使用knn查询(Elasticsearch 8.0+):
    {
      "knn": {
        "field": "embedding",
        "query_vector": [0.15, -0.02, 0.91, ...],
        "k": 10,
        "num_candidates": 100
      }
    }
    

  • 性能注意:超过1000维时需调整 index_options 参数
5. 典型应用场景
  1. 语义搜索(如:用BERT生成文本向量)
  2. 推荐系统(物品/用户向量匹配)
  3. 图像/音视频内容检索

提示:实际部署时建议结合Ingest Pipeline实现向量实时生成,保持数据与向量的一致性。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐