Elasticsearch Vector Search Guide – wiki基地


Elasticsearch Vector Search 深度指南:超越关键词的智能搜索

在信息爆炸的时代,如何快速、准确地找到所需信息是核心挑战。传统的基于关键词的搜索技术虽然强大,但在理解内容的含义、处理同义词、相关概念以及多模态数据(如图片、音频)方面存在固有的局限性。仅仅依靠字面匹配往往无法满足用户日益增长的对“智能”和“相关性”的需求。

正是在这样的背景下,向量搜索(Vector Search)应运而生,并迅速成为现代搜索和推荐系统的基石。通过将复杂的文本、图片、音频或其他类型的数据转换成高维空间的数值向量(称为嵌入,Embeddings),向量搜索能够基于这些向量之间的相似性来发现相关内容。这种相似性不再是简单的词汇匹配,而是基于数据的语义内在特征

Elasticsearch,作为业界领先的开源分布式搜索和分析引擎,紧跟技术发展趋势,深度集成了向量搜索能力。这使得用户不仅能够继续利用其强大的全文搜索、聚合和分析功能,还能在同一平台上构建出更加智能、语义感知的应用。

本文将作为一份详细的指南,带你深入了解 Elasticsearch 中的向量搜索:从基本概念到核心功能,从实践操作到高级优化,助你掌握在 Elasticsearch 中实现下一代智能搜索的技术。

第一章:理解向量搜索的核心概念

在深入 Elasticsearch 的具体实现之前,我们首先需要理解向量搜索背后的几个关键概念。

1. 什么是向量 (Vector)?

在数学和物理中,向量是一个既有大小又有方向的量。在数据科学领域,我们通常将向量理解为一个有序的数值列表或数组,用于表示数据点在某个多维空间中的位置。例如,一个简单的二维向量 [3, 4] 可以表示平面上的一个点,其距离原点的距离是 5,方向由 arctan(4/3) 决定。

在高维空间中,向量的几何意义变得抽象,但核心思想不变:每个数值(维度)代表数据的一个特定属性或特征,整个向量则综合地刻画了数据点的全貌。

2. 什么是嵌入 (Embedding)?

嵌入是将非结构化数据(如文本、图片、声音等)转换成固定长度数值向量的过程。这个转换是通过 机器学习模型(特别是深度学习模型,如Transformer模型) 完成的。训练有素的嵌入模型能够捕捉数据的语义信息和上下文关系。

举个例子:
* 对于文本,一个好的文本嵌入模型可以将“国王”和“女王”这两个词映射到向量空间中距离非常近的点,而将“国王”和“香蕉”映射到距离很远的点。这表明模型理解了“国王”和“女王”在某种意义上是相关的(都代表某种统治者),而与“香蕉”无关。
* 对于图片,一个图片嵌入模型可以将包含猫的图片和包含狗的图片映射到相近的向量,而将包含汽车的图片映射到较远的向量。

嵌入向量的维度通常很高(几百到几千维),模型的训练目标是使得在语义上或特征上相似的数据在向量空间中也彼此靠近,而不相似的数据则距离较远。

3. 向量相似性 (Vector Similarity)

向量搜索的核心在于找到与查询向量“最相似”的数据向量。衡量两个向量相似度的方法有很多,常用的包括:

  • 余弦相似度 (Cosine Similarity): 衡量两个向量方向上的相似度,不受向量大小影响。两个方向相同的向量余弦相似度为1,完全相反为-1,相互垂直为0。常用于文本相似性搜索,因为文本向量的大小(L2范数)可能与文档长度有关,余弦相似度能消除这种影响。
  • 点积 (Dot Product): 衡量两个向量的大小和方向的组合。如果向量是归一化的(L2范数等于1),点积就等于余弦相似度。如果向量未归一化,点积越大通常表示两个向量越相似且“能量”越大。
  • 欧几里得距离 (Euclidean Distance / L2 Norm): 衡量两个向量在空间中的直线距离。距离越小,表示越相似。通常用于度量两个数据点之间的物理或概念上的接近程度。与相似度指标相反,欧几里得距离越小越好。

选择哪种相似度指标取决于生成嵌入向量的模型以及数据的类型。大多数现代嵌入模型(如来自 OpenAI, Hugging Face, Google 等)通常推荐使用余弦相似度或点积(配合L2归一化)。

4. k-Nearest Neighbors (kNN)

向量搜索本质上是一种 kNN 搜索问题:给定一个查询向量,从大量的存储向量中找出与其最相似(距离最近)的 k 个向量。

  • 精确 kNN: 暴力地计算查询向量与数据库中所有向量的相似度,然后排序取出前 k 个。对于小规模数据集尚可接受,但随着数据量的增长(百万、千万、上亿),计算量呈线性增长,效率极低,无法满足实时搜索的需求。
  • 近似 kNN (Approximate kNN – Ann): 通过构建特殊的数据结构和算法,牺牲一小部分精度来换取搜索速度的大幅提升。Ann 算法能够在海量数据中快速找到与精确 kNN 结果非常接近的向量集。目前主流的 Ann 算法包括 Hierarchical Navigable Small Worlds (HNSW), annoy, Faiss 的实现等。Elasticsearch 主要采用 HNSW 算法。

第二章:Elasticsearch 对向量搜索的支持

Elasticsearch 从 7.x 版本开始引入了对向量搜索的支持,并在后续版本中不断加强,特别是在 8.x 版本中,通过原生支持 Ann 算法(HNSW)和简化的查询语法,使其向量搜索能力达到了生产级水平。

Elasticsearch 支持向量搜索的核心特性包括:

1. dense_vector 字段类型

这是专门用于存储高维浮点数向量的字段类型。在映射 (Mapping) 中定义一个 dense_vector 字段时,你需要指定向量的维度 (dims)。

json
PUT my-vector-index
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content_vector": {
"type": "dense_vector",
"dims": 768, // 指定向量维度,例如使用 Sentence-BERT 模型可能产生768维向量
"index": true, // 开启向量索引 (HNSW)
"index_options": {
"type": "hnsw", // 指定使用 HNSW 算法
"m": 16, // HNSW 参数 M: 影响索引构建时间和内存,以及搜索精度
"ef_construction": 100 // HNSW 参数 ef_construction: 影响索引构建时间和精度
},
"similarity": "cosine" // 指定默认相似度度量,可选 "l2_norm", "dot_product"
}
}
}
}

  • dims: 必需参数,指定向量的维度。所有文档在该字段中的向量必须具有相同的维度。
  • index: true: 开启向量索引。Elasticsearch 会根据 index_options 构建 Ann 数据结构(默认为 HNSW)。开启索引会显著加快搜索速度,但会增加索引构建时间和存储空间。
  • index_options: 配置 Ann 算法的参数。
    • type: 指定 Ann 算法类型,目前主要支持 hnsw
    • m: HNSW 图中每个节点连接的最大边数。更大的 M 可以提高搜索精度,但会增加内存消耗和索引构建时间。
    • ef_construction: HNSW 索引构建时的搜索宽度。更大的 ef_construction 可以提高索引质量(进而提高搜索精度),但会显著增加索引构建时间。
  • similarity: 指定该字段用于计算向量相似度的默认方法。这会在 Ann 索引构建时使用,并在搜索时作为默认值(除非查询中指定)。

2. 向量数据的索引 (Indexing)

将数据导入 Elasticsearch 时,如果文档包含向量,只需将其作为 dense_vector 字段的值包含在文档源中即可。向量通常是一个浮点数数组。

“`json
POST my-vector-index/_doc/1
{
“title”: “The quick brown fox jumps over the lazy dog”,
“content_vector”: [0.1, 0.2, …, 0.768] // 768维向量
}

POST my-vector-index/_doc/2
{
“title”: “A fast brownish canine leaps over a sluggish hound”,
“content_vector”: [0.11, 0.22, …, 0.778] // 另一个768维向量
}
``
这里的
content_vector` 需要你在索引文档之前使用外部或内置的嵌入模型生成。

为了自动化向量生成过程,你可以利用 Elasticsearch 的摄入管道 (Ingest Pipeline) 结合 Machine Learning (ML) 功能。通过在摄入管道中配置 inference 处理器,可以直接调用部署在 Elasticsearch ML 节点上的嵌入模型,在文档摄入时自动生成 dense_vector 字段。这大大简化了索引流程。

“`json
PUT _ingest/pipeline/text_embedding
{
“description”: “Text embedding pipeline”,
“processors”: [
{
“inference”: {
“model_id”: “sentence-transformers__all-MiniLM-L6-v2”, // 预训练或上传的模型ID
“target_field”: “content_vector”, // 将向量写入的字段
“field_map”: {
“content”: “text_field” // 从文档的哪个字段读取文本进行嵌入
}
}
}
]
}

PUT my-vector-index/_settings
{
“index.default_pipeline”: “text_embedding”
}

POST my-vector-index/_doc/3
{
“title”: “Example document with auto-embedding”,
“content”: “This is the text that will be converted into a vector.”
}
``
设置默认管道后,每次索引一个包含
content字段的文档时,摄入管道会自动调用模型生成content_vector`。

3. 向量搜索 (Vector Search)

Elasticsearch 提供了多种方式执行向量搜索:

  • knn 查询子句 (Recommended): 这是 Elasticsearch 8.x 版本引入的、专门用于执行 Ann 搜索的简洁方式。它直接针对 dense_vector 字段的 HNSW 索引进行查询。

    json
    GET my-vector-index/_search
    {
    "_source": ["title"],
    "knn": {
    "field": "content_vector", // 要搜索的向量字段
    "query_vector": [0.105, 0.215, ..., 0.773], // 查询向量
    "k": 5, // 返回最相似的前k个结果
    "num_candidates": 50, // HNSW搜索参数 ef_search: 搜索时考虑的最近邻候选数
    "boost": 1.0 // 权重,用于混合搜索
    }
    }

    * field: 必须,指定要搜索的 dense_vector 字段。该字段必须已开启 index: true
    * query_vector: 必须,一个与字段维度相同的浮点数数组,代表你的查询向量。这个向量也需要通过相同的嵌入模型生成。
    * k: 必须,指定要返回的最相似文档数量。
    * num_candidates: 必须,HNSW 搜索时的搜索宽度 (ef_search)。更大的 num_candidates 可以提高搜索精度,但会增加搜索延迟。建议 num_candidates >= k,通常设置为 k 的几倍。
    * boost: 可选,为 kNN 结果指定权重,在混合搜索中特别有用。

    knn 查询子句默认使用字段映射中指定的 similarity 度量。你也可以在 knn 子句中通过 similarity 参数覆盖它,但请注意,对于 HNSW 索引,相似度度量是在索引构建时确定的,查询时只能使用构建索引时指定的相似度类型。因此,通常不在查询中指定,而是依赖字段映射。

  • script_score 查询: 这是在旧版本(或需要精确 kNN)时使用的方法。它使用脚本(通常是 Painless 语言)计算查询向量与文档向量之间的相似度,并作为文档的得分进行排序。这种方法是精确的 kNN,但效率远低于使用 HNSW 索引的 knn 子句,对于大规模数据集几乎不可用作实时搜索。

    json
    GET my-vector-index/_search
    {
    "query": {
    "script_score": {
    "query": { "match_all": {} }, // 对所有文档进行评分
    "script": {
    "source": "cosineSimilarity(params.query_vector, 'content_vector') + 1.0", // 计算余弦相似度,+1是为了避免负值作为得分
    "params": {
    "query_vector": [0.105, 0.215, ..., 0.773]
    }
    }
    }
    },
    "sort": [
    {
    "_score": {
    "order": "desc"
    }
    }
    ],
    "size": 5
    }

    script_score 可以使用内置的向量函数如 cosineSimilarity, dotProduct, l2norm(注意 l2norm 计算的是距离,需要取倒数或用 1 / (1 + l2norm) 来表示相似度)。这种方法会扫描所有匹配 query 子句的文档(通常是所有文档,如果 querymatch_all),然后计算脚本得分,因此非常慢。在 8.x 及更高版本,强烈建议使用 knn 查询子句。

第三章:构建更强大的搜索:混合搜索 (Hybrid Search)

纯粹的向量搜索擅长捕获语义相似性,但有时会丢失精确的关键词匹配。例如,搜索“苹果手机”时,向量搜索可能会返回关于“三星手机”或“智能手机”的结果,因为它理解了概念上的相似性。但用户可能明确想要关于“苹果”和“手机”这两个词都出现的文档。

反过来,纯粹的关键词搜索难以处理同义词或概念相关的查询。搜索“大楼”可能找不到包含“摩天大楼”或“高层建筑”的文档。

混合搜索结合了关键词搜索和向量搜索的优势,能够提供更全面、更相关的结果。Elasticsearch 允许你在同一个查询中结合传统的 matchquery_string 查询与 knn 查询子句。

最常见的方法是将关键词查询和 knn 查询放入一个 bool 查询的 should 子句中,并结合 Reciprocal Rank Fusion (RRF) 对结果进行融合和排序。

1. Reciprocal Rank Fusion (RRF)

当一个查询同时包含多个子查询(例如,一个关键词查询子句和一个向量查询子句)时,每个子查询都会返回一个独立的文档排序结果。RRF 是一种有效的算法,用于合并这些来自不同搜索方法的排序结果,生成一个最终的排序。

RRF 的基本思想是:如果一个文档在某个子查询的排序结果中排名靠前,它在最终融合结果中的得分就会越高。排名越靠前(秩 R 越小),分数越高,具体计算公式通常是 1 / (k + R),其中 k 是一个可调参数(默认为60),R 是文档在子查询结果中的排名(从1开始)。最终得分是该文档在所有子查询中的 RRF 分数之和。

在 Elasticsearch 中实现混合搜索和 RRF,你可以在 _search 请求中使用 rank 字段:

json
GET my-vector-index/_search
{
"_source": ["title"],
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "apple phone", // 关键词查询
"boost": 1.0 // 关键词查询的权重
}
}
}
]
}
},
"knn": {
"field": "content_vector",
"query_vector": [0.15, 0.25, ..., 0.79], // 向量查询(代表“苹果手机”的语义向量)
"k": 10,
"num_candidates": 100,
"boost": 1.0 // 向量查询的权重
},
"rank": {
"fusion": {
"rrf": {
"window_size": 50, // 考虑每个子查询的前50个结果
"rank_constant": 60 // RRF公式中的k值
}
}
},
"size": 10 // 返回最终融合排序后的前10个结果
}

在这个例子中:
* query 部分执行传统的关键词搜索。
* knn 部分执行向量搜索。
* rank 部分指定使用 fusion,类型为 rrf
* window_size: 指定 RRF 在计算每个子查询的排名时,只考虑前 window_size 个结果。这可以提高效率。
* rank_constant: RRF 公式中的平滑参数 k。更大的值会减小排名差异对最终得分的影响。
* size: 指定最终通过 RRF 融合和重新排序后,返回的文档数量。

使用 rank: { fusion: { rrf: {} } } 的方式,Elasticsearch 会并行执行 queryknn 中的子查询,然后使用 RRF 算法合并它们的结果,并根据融合得分进行最终排序。这种方式既能利用关键词的精确性,又能受益于向量的语义理解,通常能提供比单一搜索方法更好的用户体验。

第四章:实践:构建和优化向量搜索

成功构建高性能的 Elasticsearch 向量搜索需要考虑多个方面。

1. 选择合适的嵌入模型

  • 模型类型: 根据数据类型选择合适的模型。文本数据用文本嵌入模型(如 BERT, Sentence-BERT, OpenAI Ada 等),图片数据用图片嵌入模型(如 CLIP, ResNet 等)。
  • 模型大小与性能: 更大的模型通常能生成质量更高的嵌入,但生成速度慢,占用的内存和磁盘空间也更大。选择时需要在效果、速度和资源消耗之间权衡。
  • 预训练模型 vs. 微调模型: 可以使用公开可用的预训练模型,也可以根据自己的特定领域数据对模型进行微调,以获得更符合业务需求的嵌入。
  • 多语言支持: 如果需要处理多种语言,确保选择支持多语言的嵌入模型。
  • 模型来源: 可以使用像 Hugging Face Transformers 这样的库在自己的基础设施上生成嵌入,使用 OpenAI API 或其他云服务商提供的嵌入 API,或者利用 Elasticsearch 的 ML 节点部署模型并通过 Inference API/摄入管道生成嵌入。Elasticsearch 的内置选项可以简化架构和管理。

2. 索引设计和映射配置

  • 字段类型: 必须使用 dense_vector 类型。
  • 维度: 确保 dims 参数与你使用的嵌入模型输出的向量维度一致。
  • HNSW 参数 (m, ef_construction): 这些参数对索引构建时间和搜索性能/精度有显著影响。
    • m: 影响 HNSW 图的连接密度。更大的 M (例如 32, 64) 会增加索引大小和构建时间,但可能提高搜索精度并略微加快搜索速度。较小的 M (例如 16, 24) 适用于内存或磁盘空间受限的场景。
    • ef_construction: 影响索引构建时的搜索深度。更大的 ef_construction (例如 100, 200) 会显著增加索引构建时间,但能构建出更高质量的 HNSW 图,从而带来更高的搜索精度。这是影响索引构建时间和精度的最重要参数之一。
    • 选择这些参数需要在索引时间和空间与搜索精度和速度之间找到平衡点。通常建议从默认值开始,根据实际数据和需求进行调整。
  • 相似度度量 (similarity): 根据生成嵌入模型推荐的相似度度量进行配置(cosine, dot_product, l2_norm)。HNSW 索引是针对特定的相似度度量构建的,无法在查询时更改。

3. 索引过程优化

  • 批量索引: 使用 Bulk API 批量索引文档,效率远高于单文档索引。
  • 硬件资源: HNSW 索引的构建过程需要大量的 CPU 和内存资源。确保 Elasticsearch 集群节点有足够的计算能力。
  • refresh_interval: 索引大量文档时,可以暂时增加 refresh_interval 来减少刷新的频率,从而提高索引吞吐量(但会增加文档可被搜索到的延迟)。
  • 摄入管道 vs. 外部生成: 利用摄入管道和 ML 节点可以简化流程,但需要在 ML 节点上投入资源。外部生成向量然后在摄入时直接包含 dense_vector 可以将计算负载转移到其他地方。选择哪种方式取决于你的基础设施和偏好。

4. 搜索性能优化

  • HNSW 搜索参数 (num_candidates/ef_search): 这是影响 Ann 搜索速度和精度的最重要参数。
    • num_candidates: 影响搜索时的搜索深度。更大的 num_candidates (例如 50, 100, 甚至更大) 会增加搜索延迟,但能探索 HNSW 图更广的范围,从而提高搜索精度(更接近精确 kNN 的结果)。
    • 与索引构建参数 ef_construction 类似,更大的 num_candidates 带来更高的精度,但代价是更高的延迟。
    • 通常建议 num_candidates > k。通过实验确定一个能在精度和延迟之间达到平衡的值。
  • 硬件资源: 搜索操作是计算密集型的,特别是对于高维向量和大的 num_candidates。确保数据节点有足够的 CPU 资源。
  • 缓存: Elasticsearch 会缓存 HNSW 图的一部分到内存中,提高搜索速度。足够的内存对性能至关重要。
  • 过滤 (Filtering): 如果你的查询包含过滤条件(例如,只搜索特定类别或日期的文档),将这些过滤器放在 bool 查询的 filter 子句中。Elasticsearch 会先执行过滤,然后在过滤后的文档集合上进行向量搜索,这可以显著减少需要比较的向量数量,提高搜索速度。请注意,Elasticsearch 8.10+ 版本开始支持对 knn 查询进行前过滤 (pre-filtering),这比后过滤(先 kNN 再过滤结果)效率更高。确保使用支持前过滤的版本并正确构造查询。
  • 分片策略: 确保索引分片数量合理,避免过度分片或分片过大。每个分片都需要加载 HNSW 图的一部分到内存中。

5. 混合搜索优化

  • RRF 参数 (window_size, rank_constant): 根据实际搜索结果调整 RRF 参数,以获得最佳的融合效果。
  • 权重 (boost): 在混合搜索中,可以通过调整关键词查询和 knn 查询的 boost 值来控制哪种搜索方法的贡献更大。

第五章:高级主题与用例

1. Elasticsearch ML 节点与 Inference API

Elasticsearch Machine Learning 功能不仅支持异常检测和分类等传统 ML 任务,还支持部署 PyTorch 或 ONNX 格式的深度学习模型。这意味着你可以将文本、图片等嵌入模型直接部署到 ML 节点上。然后,通过:

  • 摄入管道 (Ingest Pipeline): 如前所述,在文档索引时自动调用模型生成向量。
  • Inference API: 在搜索时或其他场景下,直接调用模型对文本或数据生成向量。这对于临时的向量生成或调试非常有用。

json
POST _ml/inference/text_embedding_model/_infer
{
"input": [
{
"text_field": "Example sentence to embed"
}
]
}

这种能力将向量生成与搜索平台紧密集成,简化了整体架构,降低了运维复杂度。

2. 多模态搜索

通过将不同类型的数据(如图片、文本、音频)都嵌入到同一个向量空间中,可以实现跨模态搜索。例如,用一张图片搜索相关的文本描述,或用一段文本描述搜索相关的图片。这只需要使用一个经过多模态训练的嵌入模型(如 CLIP),将不同类型的数据都映射到兼容的向量空间。然后在 Elasticsearch 中存储不同数据类型的向量,并使用查询向量进行搜索。

3. 典型的向量搜索用例

  • 语义搜索: 允许用户使用自然语言查询,返回语义相关的结果,即使关键词不完全匹配。例如,搜索“户外活动的服装”可能返回“登山服”、“徒步鞋”等商品。
  • 推荐系统: 找到与用户当前浏览商品或历史兴趣最相似的其他商品、文章或用户。
  • 内容去重: 识别和查找与现有内容高度相似的新内容,用于新闻去重、抄袭检测等。
  • 异常检测: 在日志、网络流量等数据中,查找与已知正常模式向量距离较远的异常向量。
  • 图片/音频搜索: 通过上传图片或一段音频作为查询,搜索相似的图片或音频。
  • 问答系统: 将问题和知识库中的问答对都嵌入到向量空间,通过搜索与问题向量最相似的问答对来找到答案。

第六章:Elasticsearch 在向量数据库领域的定位

虽然市面上出现了专门的向量数据库(如 Milvus, Pinecone, Weaviate 等),但 Elasticsearch 作为集搜索、分析、存储于一体的平台,其向量搜索能力具有独特的优势:

  • 统一平台: 无需维护单独的向量数据库,可以在同一个集群中处理全文搜索、结构化数据过滤、向量搜索、聚合分析等多种任务。这大大简化了架构和运维。
  • 强大的生态系统: 利用 Kibana 进行可视化和探索,使用 Logstash 或 Beats 进行数据采集,利用 Elastic Stack 的其他组件。
  • 成熟的扩展性和可靠性: Elasticsearch 作为分布式系统,具有成熟的集群管理、扩展、故障转移和数据恢复能力。
  • 混合搜索优势: Elasticsearch 天生支持结合关键词和向量搜索,并提供了 RRF 等强大的融合能力,这对于许多实际应用场景至关重要。

选择 Elasticsearch 还是专门的向量数据库取决于你的具体需求。如果你的应用需要强大的全文搜索和结构化数据过滤能力,并且希望将向量搜索作为其增强功能,那么 Elasticsearch 是一个非常有吸引力的选择。如果你的核心需求是纯粹的海量向量存储和检索,且对其他搜索/分析功能需求较少,或者需要某些向量数据库特有的高级功能(如特定的Ann算法、图数据库能力等),则可能考虑专门的向量数据库。然而,对于大多数常见的智能搜索应用,Elasticsearch 提供的向量搜索能力已经非常强大和全面。

结论

Elasticsearch 对向量搜索的深度集成,使其从一个强大的关键词搜索引擎演进为一个能够理解和处理数据语义的智能搜索平台。通过 dense_vector 字段、高效的 HNSW 索引、灵活的 knn 查询以及强大的混合搜索和 RRF 功能,Elasticsearch 为开发者提供了构建下一代智能搜索、推荐和内容理解应用的坚实基础。结合其成熟的生态系统和运维能力,Elasticsearch 无疑是实现语义搜索和向量检索的优秀选择。

掌握本文中介绍的概念、配置和实践技巧,你将能够在 Elasticsearch 中解锁全新的搜索维度,为用户带来更智能、更相关的搜索体验。随着技术的不断发展,Elasticsearch 在向量搜索领域的投入也将持续深化,未来可期。


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部