向量检索深入学习

向量检索通过将文本映射为高维空间中的向量,实现语义搜索,解决传统关键词搜索的局限性。Elasticsearch支持向量检索,包括生成向量、索引向量和查询向量三个步骤,需使用嵌入模型和HNSW算法优化性能。混合检索结合关键词搜索和向量搜索,通过RRF算法融合结果,提升搜索质量。

作品集: Elastic Stack
作者头像
LumiBee
15 天前 · 85 1
分享

Elasticsearch 向量检索深入学习

传统的搜索引擎是“字面匹配”的专家,但它们很难理解文字背后的“真实含义”。例如,搜索“苹果手机”,它可能不会返回一篇只写了“iPhone”的文章。向量检索(或称语义搜索)的诞生,就是为了解决这个问题。它让搜索引擎能够像人一样,理解概念和上下文,是构建下一代智能搜索应用的核心技术。

1. 核心思想

让我们用一个比喻来理解向量检索。

  1. 传统图书馆(关键词搜索): 想象一个巨大的图书馆,所有的书都按照书名首字母(A-Z)排列。当我们想找关于“快速的猫科动物”的书时,只能去“K”区找“快 (Kuai)”或者去“M”区找“猫 (Mao)”。那我们将永远找不到那本标题为**《猎豹》**的书,尽管它的内容完全符合您的需求。这就是关键词搜索的局限性。

  2. “意义”图书馆(向量搜索): 现在,想象一个神奇的图书馆。这里的书不是按字母,而是按照**“意义”**漂浮在一个巨大的三维空间里。

    • 所有关于“猫科动物”的书,比如《老虎》、《狮子》、《猎豹》,都聚集在这个空间的同一个区域。
    • 所有关于“科技公司”的书,比如《苹果传》、《谷歌的故事》,则聚集在另一个遥远的区域。
    • 在这个空间里,**《猎豹》这本书和《老虎》这本书的物理距离非常近,但它们离《苹果传》**这本书非常非常远。

    当我们想找“快速的猫科动物”时,图书管理员(AI模型)会理解我们的意图,然后直接飞到“猫科动物”这个区域,为我们取回离我们“意图”这个点最近的几本书,其中自然就包括了《猎豹》。

    在这个比喻中:

    • 每一本书,就是一个文档
    • 书在空间中的坐标(例如 [x:0.8, y:1.2, z:-0.5]),就是一个**向量 **。
    • 图书管理员,就是一个深度学习模型,它的工作就是阅读一句话或一篇文章,然后计算出它在“意义空间”中的精确坐标。
    • 寻找最近的书,就是 K-近邻 (k-Nearest Neighbors, kNN) 搜索算法。

2. 端到端的完整工作流程

实现向量检索主要分为三步:生成向量 -> 索引向量 -> 查询向量

2.1 文本嵌入-生成向量

这是在 Elasticsearch 外部完成的,也是整个流程的起点。

  • 首先需要一个预训练好的文本嵌入模型(通常由 Google, OpenAI, Hugging Face 等机构提供),对于中文,一些流行的开源模型包括 bge-large-zh, m3e-base 等。
  • 生成和查询:
    1. 索引阶段: 当我们有一篇新的博客文章需要存入 ES 时,需要先用这个模型去“阅读”它的标题和内容,模型会输出一个由几百个数字组成的数组(例如一个包含 768 个浮点数的数组),这就是这篇文章的内容向量
    2. 查询阶段: 当用户在搜索框输入“如何学习ES”时,我们同样需要用这个模型去处理用户的查询,得到一个查询向量

> 关键原则: 索引文档和查询用户输入时,必须使用同一个嵌入模型,否则它们的“坐标系”不同,无法进行比较。

2.2 索引向量 - 将向量存入 Elasticsearch

  1. 设计 Mapping: 我们需要一个 dense_vector 类型的字段来存储向量。最关键的是,为了实现高性能的近似近邻搜索 (ANN),需要在映射中为这个字段开启索引。

    PUT /blog_posts_vector
    {
      "mappings": {
        "properties": {
          "title": { "type": "text" },
          "content": { "type": "text" },
          "content_vector": {
            "type": "dense_vector",
            "dims": 768, // 必须指定向量的维度,与您的模型输出一致
            "index": true, // 关键!开启向量索引
            "similarity": "cosine", // 指定相似度计算方法,cosine很常用
            "index_options": { // HNSW 算法的配置
              "type": "hnsw",
              "m": 16,
              "ef_construction": 100
            }
          }
        }
      }
    }
    
    • index: true: 告诉 ES 为这个向量字段构建一个特殊的索引结构(通常是 HNSW 图),从而能够极快地找到近似的邻居。如果不开启,ES 只能进行暴力扫描,性能极差。

    • similarity: 定义了如何计算两个向量之间的“距离”。常用的有 l2_norm (欧氏距离) 和 cosine (余弦相似度)。选择的嵌入模型通常会推荐使用哪种。

      1. HNSW 索引参数的通俗解释与权衡
      • "m" (Max Connections): 可以理解为在构建 HNSW 图时,每个节点的“社交圈”大小。m 值越大,图的连接越紧密,路径选择更多,召回率(精度)更高,但索引构建更慢,占用内存也更大。16 是一个很常见的默认值。
      • "ef_construction" (Construction Effect): 这是在索引构建时的搜索范围参数。为了给新节点找到最合适的 m 个邻居,算法会在一个大小为 ef_construction 的动态候选列表中进行搜索。这个值越大,邻居找得越准,索引质量更高,但索引速度越慢
      1. 相似度 similarity 的选择
      • cosine (余弦相似度): 它只关心向量的方向,不关心大小(模长)。这使得它对于文本长度变化不敏感,因此在文本语义检索中是最常用和最推荐的。例如,“AI”和“人工智能是未来的趋势”这两句话的向量长度可能不同,但它们的方向非常接近。
      • l2_norm (欧氏距离): 它计算空间中两个点的直线距离,对向量的方向和大小都敏感。它在人脸识别、图像搜索等领域更常用。
  2. 索引文档: 将文章内容和它对应的向量一起存入 ES。

    POST /blog_posts_vector/_doc
    {
      "title": "猎豹的速度与习性",
      "content": "猎豹是陆地上跑得最快的动物...",
      "content_vector": [0.85, -0.12, 0.99, ... , -0.45] // 这是由模型生成的向量
    }
    

2.3 查询向量 - 使用 kNN 进行搜索

现在,我们可以用用户的查询向量来查找最相似的文档了。

GET /blog_posts_vector/_search
{
  "knn": {
    "field": "content_vector",
    "query_vector": [0.81, -0.15, 0.95, ... , -0.41], // 这是用户查询“快速的猫科动物”后生成的向量
    "k": 5, // 查找最相似的 5 个邻居
    "num_candidates": 100 // 在100个候选者中进行精确计算,这个值越大越精确,但性能越低
  }
}
  • k: 希望返回的最相似结果的数量。
  • num_candidates: ES 会先从 HNSW 图中快速找出 num_candidates 个“可能”最相似的候选者,然后再对这批候选者进行精确的距离计算,最后返回前 k 个。

3. 混合检索

向量搜索非常擅长理解语义,但它可能对关键词不敏感。例如,搜索一个特定的产品型号 "iPhone 15 Pro Max",传统的关键词搜索可能比向量搜索更精确。

混合检索就是将关键词搜索 (BM25)向量搜索 (kNN) 结合起来,取长补短,得到最佳的搜索结果。

需求: 用户搜索“学习 Elasticsearch 的好资源”,我们希望结果既包含语义上相似的文章(比如讲 OpenSearch 的好文章),也精确匹配那些标题里就写着“Elasticsearch”的文章。

GET /blog_posts_vector/_search
{
  "query": {
    "match": { // 关键词搜索部分
      "content": "Elasticsearch"
    }
  },
  "knn": { // 向量搜索部分
    "field": "content_vector",
    "query_vector": [ ... ], // "学习 Elasticsearch 的好资源" 的查询向量
    "k": 5,
    "num_candidates": 100
  },
  "rank": { // 结果融合策略
    "rrf": {}
  }
}
  • 工作流程: Elasticsearch 会分别执行 match 查询和 knn 查询,得到两个结果列表。
  • rank.rrf: Reciprocal Rank Fusion (RRF) 是一种先进的算法,它会智能地将这两个结果列表融合在一起,综合考虑关键词匹配度和语义相似度,生成一个最终的、更高质量的排名。

总结

向量检索是一项变革性的技术。要精通它,我们需要掌握:

  1. 核心思想: 将文本的“意义”映射为高维空间中的“坐标”(向量)。
  2. 端到端流程: 在外部使用嵌入模型生成向量,在 ES 中使用 dense_vector 类型索引向量,使用 knn 查询向量
  3. 性能关键: 必须在 Mapping 中为向量字段设置 index: true 来启用 HNSW 等近似搜索算法。
  4. 实战升华: 使用混合检索,将 knn 与传统的 match 查询结合,并通过 RRF 进行结果融合,以达到最佳的搜索效果。
阅读量: 85

评论区

登录后发表评论

正在加载评论...
相关阅读

Elasticsearch 入门指南

# Elasticsearch 入门指南:从零到一构建搜索引擎 在成功部署了 Elasticsearch 和 Kibana 后,如果还有不会安装的可以查看这篇[文章](https://hive...

164
1

Elasticsearch 关联关系处理指南

# **Elasticsearch 关联关系处理指南** 当我们将数据从 MySQL 等关系型数据库迁移到 Elasticsearch 时,遇到的第一个挑战往往就是如何处理表与表之间的关联关系...

81
0

Elastic Stack 日志监控入门指南

# Elastic Stack 日志监控入门指南 ## 0. 核心概念:理解现代 Elastic 可观测性架构 在开始部署之前,我们必须先理解几个核心概念,这能帮助我们明白每一步操作背后的“...

65
1

Redis04_数据类型

# 五大数据类型 ![image-20250506173728272](https://p.ipic.vip/iq69f6.png) ## Redis-Key ```bash 127.0....

81
0

Java单列集合学习

# Collection Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的 * List接口的实现类 * ArrayList:动态数组实现,允许重复元素 ...

93
1

Elasticsearch 相关性控制的艺术

# Elasticsearch 相关性控制的艺术 我们可以通过控制相关性的得分使得用户最想要的结果排在最前面。本文所举的例子依旧是建设博客的搜索引擎。 ## 1. boosting 查询 ...

104
1