欢迎光临
我们一直在努力

Elasticsearch 向量搜索详解:如何利用 HNSW 索引实现语义检索

引言:为什么需要向量搜索?

传统的 Elasticsearch 搜索基于倒排索引,通过关键词匹配(BM25算法)来计算相关性。但在处理“语义”或“意图”时,这种方法往往力不从心。例如,搜索“大型犬”,但文档中只提到了“藏獒”。基于向量的语义搜索则通过将文本转化为高维空间中的向量(Embedding),利用向量之间的距离(如余弦相似度)来衡量语义上的相似度。

Elasticsearch 8.x 版本后引入了原生的向量搜索能力,其中核心是利用 HNSW (Hierarchical Navigable Small World) 算法进行高效的近似最近邻(ANN)查找。

什么是 HNSW?

HNSW 是一种图搜索算法,它通过构建多层级的跳跃图来快速定位最近邻居。它牺牲了极小的搜索准确性(近似)来换取巨大的性能提升,尤其在高维向量和大规模数据集下表现优异。

下面我们将通过三个实操步骤,演示如何在 Elasticsearch 中配置和运行 HNSW 向量搜索。

第一步:创建支持 HNSW 的索引映射

要使用 HNSW,我们需要定义 dense_vector 字段,并在 index_options 中指定 hnsw 算法及其参数。

HNSW 核心参数说明:

  • dims: 向量的维度(必须与模型生成的 Embedding 维度一致)。
  • similarity: 相似度度量,常用 cosine(余弦相似度)或 l2(欧氏距离)。
  • m: HNSW 图中每个节点连接的最大邻居数,影响内存使用和准确性,推荐 16 或 32。
  • ef_construction: 索引构建时的搜索候选集大小,值越大,索引质量越高,但构建速度越慢。推荐 100 到 200。

以下是创建索引的示例(假设我们使用一个维度为 128 的向量):

PUT /semantic_hnsw_index
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0 
  },
  "mappings": {
    "properties": {
      "description": {
        "type": "text"
      },
      "title_vector": {
        "type": "dense_vector",
        "dims": 128, 
        "index": true,
        "similarity": "cosine",
        "index_options": {
          "type": "hnsw",
          "m": 16,
          "ef_construction": 100
        }
      }
    }
  }
}

第二步:索引数据(写入向量)

在实际应用中,你需要使用深度学习模型(如 BERT, BGE, OpenAI Embeddings 等)将文本内容转换为 128 维的浮点数向量。这里我们用一个简化的 128 维数组来模拟数据写入。

POST /semantic_hnsw_index/_bulk?pretty
{ "index" : { "_id" : "1" } }
{ "description": "地球是太阳系第三颗行星,拥有生命", "title_vector": [...128 个浮点数...] }
{ "index" : { "_id" : "2" } }
{ "description": "火星是第四颗行星,也被称为红色星球", "title_vector": [...128 个浮点数...] }
{ "index" : { "_id" : "3" } }
{ "description": "太空旅行和星际探索的新闻", "title_vector": [...128 个浮点数...] }

// 简化示例,使用 4 维向量代替 128 维
POST /semantic_hnsw_index/_doc/4
{
  "description": "关于猫和狗的可爱故事",
  "title_vector": [0.8, 0.1, 0.9, 0.2]
}
POST /semantic_hnsw_index/_doc/5
{
  "description": "宠物医生解答常见问题",
  "title_vector": [0.9, 0.05, 0.75, 0.1]
}

注意: 由于向量太长,这里使用了 […] 占位。在实际操作中,你需要提供精确的浮点数数组。

第三步:执行 KNN 向量搜索

使用 knn 查询块来执行近似最近邻搜索。你需要提供待查询的向量 (query_vector),并指定返回结果的数量 k

搜索参数说明:

  • query_vector: 用户查询语句经过 Embedding 模型转换后的向量。
  • k: 用户希望返回的精确结果数量。
  • num_candidates: HNSW 搜索过程中,算法在底层图中实际检查的邻居数量。num_candidates 越大,准确率越高,但搜索速度越慢。通常设置为 k 的 5 到 10 倍。

假设用户查询“动物宠物”,其向量是 [0.75, 0.15, 0.8, 0.08],我们希望返回 2 个结果:

GET /semantic_hnsw_index/_search
{
  "knn": {
    "field": "title_vector",
    "query_vector": [0.75, 0.15, 0.8, 0.08],
    "k": 2,
    "num_candidates": 50
  },
  "_source": ["description"]
}

结果分析:

Elasticsearch 将利用 HNSW 图快速定位语义上最接近 [0.75, 0.15, 0.8, 0.08] 的文档。如果我们的向量设置得当,文档 4 和 5(关于猫、狗和宠物医生)将被返回,因为它们与查询向量在语义空间上距离最近。

总结与性能优化建议

利用 HNSW 索引,Elasticsearch 能够在大规模数据集上实现亚秒级的向量搜索,为构建现代语义检索系统提供了强大的基础。

性能优化要点:

  1. 参数平衡: 调整 mef_construction(索引阶段)和 num_candidates(查询阶段)。更高的值可以提高召回率和准确性,但会增加资源消耗。
  2. 过滤与混合查询: 在实际应用中,通常需要结合传统关键词过滤(如 termmatch)和 knn 查询。Elasticsearch 支持通过 filter 子句对 knn 结果进行后过滤,或者使用 bool 查询结合 knn 和传统查询进行混合搜索(Hybrid Search)。
【本站文章皆为原创,未经允许不得转载】:汤不热吧 » Elasticsearch 向量搜索详解:如何利用 HNSW 索引实现语义检索
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址