3.5 Elasticsearch-向量搜索:dense_vector + cosineSimilarity(8.0+)

Elasticsearch 8.0+向量搜索实战

在这里插入图片描述

3.5 Elasticsearch-向量搜索:dense_vector + cosineSimilarity(8.0+)

3.5.1 为什么需要向量搜索

文本、图像、音频一旦被 Embedding 模型映射成固定维度的稠密向量,「语义相似」就等价于「向量空间中距离相近」。Elasticsearch 从 7.x 开始提供 dense_vector 字段,8.0 之后正式引入基于 HNSW 的近似最近邻(ANN)检索,把原来只能暴力循环的 script_score 模式推进到毫秒级响应,使 ES 从「全文检索引擎」升级为「混合语义检索引擎」。

3.5.2 字段设计:index or not index

dense_vector 有两种使用方式,选型直接影响吞吐与精度:

  1. 不建索引(index: false)
    仅当存储,搜索阶段用 script_score 暴力计算 cosineSimilarity,实现精确但 O(N) 的「暴力 kNN」。适合万级以下、低频查询或实验室场景。

    PUT product
    {
      "mappings": {
        "properties": {
          "title": { "type": "text" },
          "title_vector": {
            "type": "dense_vector",
            "dims": 768,
            "index": false
          }
        }
      }
    }
    
  2. 建 HNSW 索引(index: true,8.0+ 默认)
    在写入时构建多层导航图,查询走近似 kNN,复杂度降至 O(logN)。必须同时指定 similarity,否则无法建索引。

    PUT product
    {
      "mappings": {
        "properties": {
          "title_vector": {
            "type": "dense_vector",
            "dims": 768,
            "index": true,
            "similarity": "cosine"
          }
        }
      }
    }
    

    注意:

    • 维度≤1024(float 型)
    • 相似度可选 l2_normdot_productcosinecosine 会在入库时自动将向量归一化,查询侧无需再处理
    • 若用 bit 元素类型做超高维场景,维度必须是 8 的倍数,相似度固定为 hamming
3.5.3 写入数据:让 ES 帮你归一化

similarity: cosine 时,ES 会在索引阶段自动计算 L2 范数并把向量归一化,因此客户端可直接送入原始浮点数组,省去额外的归一化步骤。

POST product/_bulk
{"index":{}}
{"title":"轻便夏季背包","title_vector":[0.12,-0.33,...,0.45]}
3.5.4 近似 kNN 查询:knn 段
POST product/_search
{
  "knn": {
    "field": "title_vector",
    "query_vector": [0.11,-0.30,...,0.44],
    "k": 10,
    "num_candidates": 100
  },
  "_source": ["title", "_score"]
}
  • k:最终返回的 Top-K
  • num_candidates:在 HNSW 图中选取的候选集大小,越大越准也越慢,通常取 k*10~20 做权衡
  • 结果 _score 已归一化到 [0,1],值越大越相似
3.5.5 混合评分:向量 + 布尔过滤

向量查询往往伴随业务过滤(类目、库存、上下架)。ES 8 允许在 knn 同级写 filter,先过滤再 ANN,大幅减少候选集:

POST product/_search
{
  "knn": {
    "field": "title_vector",
    "query_vector": [...],
    "k": 10,
    "num_candidates": 100,
    "filter": { "term": { "on_sale": true } }
  }
}
3.5.6 精确 kNN:script_score 保底

对超小表或需要 100% 精确的场景,仍可用 script_score 暴力计算。注意把 cosineSimilarity 结果 +1.0 消除负分,以便与其他评分函数统一尺度:

POST product/_search
{
  "query": {
    "script_score": {
      "query": { "match_all": {} },
      "script": {
        "source": "cosineSimilarity(params.q, 'title_vector') + 1.0",
        "params": { "q": [...] }
      }
    }
  }
}

经验:

  • 若数据>5 万条,延迟会肉眼可见,建议切到 HNSW
  • 向量维度>300 时,开启 index:true 的召回率下降通常<2%,却带来 10~50 倍提速
3.5.7 性能调优清单
  1. 维度控制:embedding 模型输出 768/1024 即可,再高手动 PCA 降维
  2. 段合并:ANN 性能与段数负相关,写入后定时 POST /product/_forcemerge?max_num_segments=1
  3. 缓存:kNN 结果默认不走 Query Cache,若查询向量重复率高,可在客户端做向量→结果映射缓存
  4. 并行分片routing=user_id 把同一用户数据写到一个分片,减少广播
  5. 硬件:HNSW 对内存带宽敏感,建议 1 GB 堆外内存/50 万 768 维向量做预算,使用大页内存 vm.max_map_count=262144
3.5.8 常见坑
  • 维度不一致直接拒绝写入;先检查模型升级后是否改了输出维数
  • cosineSimilarity 入参向量未归一化会导致 dotProductcosine 混用结果偏差——让 ES 做归一化即可
  • 使用 script_score 时忘记 +1.0,结果出现负分,与后续 function_score 累加时产生倒序
  • 8.0 之前老集群误用 knn 查询会报 no such query,需升级或继续用 script_score
3.5.9 小结

借助 dense_vector + cosineSimilarity,Elasticsearch 8.0+ 在原生倒排索引之上叠加了 HNSW 向量索引,实现「毫秒级近似语义检索」。上线流程可简化为:

  1. 建模→index:true+similarity:cosine
  2. 写入→ES 自动归一化
  3. 查询→knn 段带业务过滤
  4. 调优→维度、段合并、内存
    当数据量或 QPS 继续膨胀,可再叠加向量压缩、分片裁剪、缓存等手段,把 ES 打造成兼顾全文、结构化、向量三位一体的统一检索引擎。
    更多技术文章见公众号: 大城市小农民
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔丹搞IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值