Elasticsearch 向量检索深入学习
传统的搜索引擎是“字面匹配”的专家,但它们很难理解文字背后的“真实含义”。例如,搜索“苹果手机”,它可能不会返回一篇只写了“iPhone”的文章。向量检索(或称语义搜索)的诞生,就是为了解决这个问题。它让搜索引擎能够像人一样,理解概念和上下文,是构建下一代智能搜索应用的核心技术。
1. 核心思想
让我们用一个比喻来理解向量检索。
-
传统图书馆(关键词搜索): 想象一个巨大的图书馆,所有的书都按照书名首字母(A-Z)排列。当我们想找关于“快速的猫科动物”的书时,只能去“K”区找“快 (Kuai)”或者去“M”区找“猫 (Mao)”。那我们将永远找不到那本标题为**《猎豹》**的书,尽管它的内容完全符合您的需求。这就是关键词搜索的局限性。
-
“意义”图书馆(向量搜索): 现在,想象一个神奇的图书馆。这里的书不是按字母,而是按照**“意义”**漂浮在一个巨大的三维空间里。
- 所有关于“猫科动物”的书,比如《老虎》、《狮子》、《猎豹》,都聚集在这个空间的同一个区域。
- 所有关于“科技公司”的书,比如《苹果传》、《谷歌的故事》,则聚集在另一个遥远的区域。
- 在这个空间里,**《猎豹》这本书和《老虎》这本书的物理距离非常近,但它们离《苹果传》**这本书非常非常远。
当我们想找“快速的猫科动物”时,图书管理员(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
等。 - 生成和查询:
- 索引阶段: 当我们有一篇新的博客文章需要存入 ES 时,需要先用这个模型去“阅读”它的标题和内容,模型会输出一个由几百个数字组成的数组(例如一个包含 768 个浮点数的数组),这就是这篇文章的内容向量。
- 查询阶段: 当用户在搜索框输入“如何学习ES”时,我们同样需要用这个模型去处理用户的查询,得到一个查询向量。
> 关键原则: 索引文档和查询用户输入时,必须使用同一个嵌入模型,否则它们的“坐标系”不同,无法进行比较。
2.2 索引向量 - 将向量存入 Elasticsearch
-
设计 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
(余弦相似度)。选择的嵌入模型通常会推荐使用哪种。- HNSW 索引参数的通俗解释与权衡
"m"
(Max Connections): 可以理解为在构建 HNSW 图时,每个节点的“社交圈”大小。m
值越大,图的连接越紧密,路径选择更多,召回率(精度)更高,但索引构建更慢,占用内存也更大。16
是一个很常见的默认值。"ef_construction"
(Construction Effect): 这是在索引构建时的搜索范围参数。为了给新节点找到最合适的m
个邻居,算法会在一个大小为ef_construction
的动态候选列表中进行搜索。这个值越大,邻居找得越准,索引质量更高,但索引速度越慢。
- 相似度
similarity
的选择
cosine
(余弦相似度): 它只关心向量的方向,不关心大小(模长)。这使得它对于文本长度变化不敏感,因此在文本语义检索中是最常用和最推荐的。例如,“AI”和“人工智能是未来的趋势”这两句话的向量长度可能不同,但它们的方向非常接近。l2_norm
(欧氏距离): 它计算空间中两个点的直线距离,对向量的方向和大小都敏感。它在人脸识别、图像搜索等领域更常用。
-
-
索引文档: 将文章内容和它对应的向量一起存入 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) 是一种先进的算法,它会智能地将这两个结果列表融合在一起,综合考虑关键词匹配度和语义相似度,生成一个最终的、更高质量的排名。
总结
向量检索是一项变革性的技术。要精通它,我们需要掌握:
- 核心思想: 将文本的“意义”映射为高维空间中的“坐标”(向量)。
- 端到端流程: 在外部使用嵌入模型生成向量,在 ES 中使用
dense_vector
类型索引向量,使用knn
查询向量。 - 性能关键: 必须在 Mapping 中为向量字段设置
index: true
来启用 HNSW 等近似搜索算法。 - 实战升华: 使用混合检索,将
knn
与传统的match
查询结合,并通过 RRF 进行结果融合,以达到最佳的搜索效果。
评论区
请登录后发表评论