【Elasticsearch】一文读懂ES向量搜索:原理分析与技能全景 ...

打印 上一主题 下一主题

主题 1775|帖子 1775|积分 5325

大家好,我是大任,本日给大家分享一下Elasticsearch的向量搜索技能
注:本文若未说明ES版本则为7.10,其他版本会特别标记,由于ES版本不同,部分差异较大,具体请以官方文档为准
一、向量搜索的核心原理

1.1 向量化表示的本质

现代AI技能将文本、图像等非布局化数据转化为高维向量(通常128-1024维),这些向量在数学空间中携带语义特征。如:

  • 文本嵌入(Embedding):BERT等模型天生768维向量
  • 图像特征:ResNet提取2048维特征向量
1.2 向量搜索简介

向量搜索,简单来说,就是在向量空间中进行的搜索操作。在传统的文本搜索中,我们通常基于关键词进行匹配,这种方式对于精确匹配的场景效果较好,但在处理语义理解、含糊匹配等复杂场景时显得力不从心。而向量搜索则将文本、图像、音频等各种数据转化为向量表示,通过盘算向量之间的相似度来进行搜索。这种方式能够更好地捕捉数据的语义信息,从而实现更精准、更智能的搜索。
例如,对于文本数据,我们可以使用词嵌入(Word Embedding)技能将每个单词映射为一个向量,然后将整个文本的向量表示为其包含单词向量的某种聚合(如均匀、求和等)。在搜索时,将查询文本也转化为向量,通过盘算查询向量与文档向量之间的相似度,找出与查询最相干的文档。
二、Elasticsearch两种核心向量搜索方式

Elasticsearch为了满意向量搜索的需求,在7.0版本新增了两个字段类型dense_vector 和 sparse_vector,分别是麋集向量和稀疏向量,其中 sparse_vector在7.6中被弃用,在8.0-8.10版本中是没有该字段类型的。
2.1 近似kNN(HNSW算法)

在7.10版本中,没有该方式,因此按照2025/3/1最新版本8.17版本介绍.
k-nearest neighbor(kNN)搜索通过相似性度量所测量等算法查询向量最近的k个向量。
前置条件

要使用KNN搜索,首先必须要有dense_vector或 sparse_vector字段,这些字段的维度一定要和查询的维度类似,以是一定要确定好维度。关于向量,可以在Elasticsearch中使用自然语言处理(NLP)模型创建这些向量,或者在Elasticsearch外部天生它们,比如使用阿里云的向量模型API获取文本向量后赋值到搜索参数中。

  • 首先必要显式映射一个或多个dense_vector字段。
在8.0版中添加了对近似kNN搜索的支持。在此之前,dense_vector字段不支持在映射中启用索引。假如在8.0之前的版本创建了一个包含dense_vector字段的索引,那么为了支持近似kNN搜索,必须使用设置index:true(默认选项)的新字段映射重新索引数据。
  1. PUT image-index
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "image-vector": {
  6.         "type": "dense_vector",
  7.         "dims": 3,       //向量维度
  8.         "index": true,   //8.0之前使用KNN搜索
  9.         "similarity": "l2_norm"  //获取knn相似度的函数,不设置改值默认为cosine(余弦),且只能在index设置为true时指定
  10.       },
  11.       "title-vector": {
  12.         "type": "dense_vector",
  13.         "dims": 5,
  14.         "similarity": "l2_norm"
  15.       },
  16.       "title": {
  17.         "type": "text"
  18.       },
  19.       "file-type": {
  20.         "type": "keyword"
  21.       }
  22.     }
  23.   }
  24. }
复制代码
similarity的选择有(详情可看麋集向量字段的参数):

  • l2_norm
  • dot_product
  • cosine
  • max_inner_product

  • 创建数据
  1. POST image-index/_bulk?refresh=true
  2. { "index": { "_id": "1" } }
  3. { "image-vector": [1, 5, -20], "title-vector": [12, 50, -10, 0, 1], "title": "moose family", "file-type": "jpg" }
  4. { "index": { "_id": "2" } }
  5. { "image-vector": [42, 8, -15], "title-vector": [25, 1, 4, -12, 2], "title": "alpine lake", "file-type": "png" }
  6. { "index": { "_id": "3" } }
  7. { "image-vector": [15, 11, 23], "title-vector": [1, 5, 25, 50, 20], "title": "full moon", "file-type": "jpg" }
  8. ...
复制代码

  • 使用knn选项或knn查询
  1. POST image-index/_search
  2. {
  3.   "knn": {
  4.     "field": "image-vector",
  5.     "query_vector": [-5, 9, -12],
  6.     "k": 10, //查询的数量
  7.     "num_candidates": 100
  8.   },
  9.   "fields": [ "title", "file-type" ]
  10. }
复制代码

  • 原理
为了收集结果,kNN搜索API在每个分片上找到num_candidates数目标近似最近邻候选。搜索盘算这些候选向量与查询向量的相似度,选择k个最相似的结果。然后,搜索未来自 每个分片返回全局前k个最近邻向量。
可以增加num_candidates以获得更正确的结果,但代价是搜索速率变慢。num_candidates值比较较高的搜索 会从每个分片中思量更多的候选者。会花费更多的时间,但也会提高搜索真正的k个最接近的向量的概率。
2.2精确暴力搜索

盘算查询向量与所有过滤后的文档向量的余弦/欧式距离,包管100%召回率但盘算成本高。使用精确KNN搜索的话,必要使用带有vector函数的script_score查询。

  • 首先必要显式映射一个或多个dense_vector字段。假如不计划将该字段使用近似kNN搜索,可以将索引映射选项设置为false。这可以明显提高索引速率。
  1. PUT product-index
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "product-vector": {
  6.         "type": "dense_vector",
  7.         "dims": 5,
  8.         "index": false
  9.       },
  10.       "price": {
  11.         "type": "long"
  12.       }
  13.     }
  14.   }
  15. }
复制代码

  • 创建数据
  1. POST product-index/_bulk?refresh=true
  2. { "index": { "_id": "1" } }
  3. { "product-vector": [230.0, 300.33, -34.8988, 15.555, -200.0], "price": 1599 }
  4. { "index": { "_id": "2" } }
  5. { "product-vector": [-0.5, 100.0, -13.0, 14.8, -156.0], "price": 799 }
  6. { "index": { "_id": "3" } }
  7. { "product-vector": [0.5, 111.3, -13.0, 14.8, -156.0], "price": 1099 }
  8. ...
复制代码

  • 使用search API运行包含向量函数的script_score查询。
    向量函数的类型有:

    • cosineSimilarity-盘算余弦相似度
    • dotProduct-盘算点积
    • l1 norm-盘算L1距离
    • Hamming-盘算Hamming距离
    • l2 norm-盘算L2距离
    • doc[].vectorValue-以浮点数组的形式返回向量的值
    • doc[].magnitude-返回向量的大小
      接下来以cosineSimilarity为例,这是一个通过盘算两个向量的余弦大小来判断向量相似度的函数。我们通过传入的参数向量queryVector,这个名称是自界说的,但是必要与source的脚本中params.queryVector一致,下面方法将会查询所有文档

  1. POST product-index/_search
  2. {
  3.   "query": {
  4.     "script_score": {
  5.       "query" : {
  6.         "match_all" : {}
  7.        },
  8.       "script": {
  9.         "source": "cosineSimilarity(params.queryVector, 'product-vector') + 1.0",
  10.         "params": {
  11.           "queryVector": [-0.5, 90.0, -10, 14.8, -156.0]
  12.         }
  13.       }
  14.     }
  15.   }
  16. }
复制代码
但是使用match_all查询来全量匹配所有文档会明显增加搜索延迟,为了限定传递给vector函数的匹配文档的数目,可以在script_score.query参数中指定一个过滤查询。例如下面示例:
  1. POST product-index/_search
  2. {
  3.   "query": {
  4.     "script_score": {
  5.       "query" : {
  6.         "bool" : {
  7.           "filter" : {
  8.             "range" : {
  9.               "price" : {
  10.                 "gte": 1000
  11.               }
  12.             }
  13.           }
  14.         }
  15.       },
  16.       "script": {
  17.         "source": "cosineSimilarity(params.queryVector, 'product-vector') + 1.0",
  18.         "params": {
  19.           "queryVector": [-0.5, 90.0, -10, 14.8, -156.0]
  20.         }
  21.       }
  22.     }
  23.   }
  24. }
复制代码
2.3 两种搜索的对比

原理差异


  • 精确暴力搜索:在进行搜索时,精确暴力搜索会遍历数据集中的每一个向量,逐一盘算查询向量与它们之间的相似度(如欧几里得距离、余弦相似度等),然后根据相似度的大小对所有向量进行排序,最后选取最相似的k个向量作为结果返回。这种方法简单直接,能够包管搜索结果的精确性,但在数据量较大时,盘算量会非常庞大。
  • 近似 k - NN 搜索:近似 k - NN 搜索则采用了一些优化计谋来减少盘算量。例如,使用上述提到的 KD - Tree、HNSW 等索引布局,通过构建数据的层次化表示或图布局,在搜索时能够快速定位到大概包含相似向量的地区,而无需遍历整个数据集。以 HNSW 为例,它通过多层图布局,在高层图中快速跳过大量不相干的向量,仅在底层图中对局部地区进行更精确的搜索,从而在包管一定搜索精度的前提下,大大提高了搜索服从。
性能体现


  • 搜索时间:精确暴力搜索的搜索时间与数据集的大小成正比,数据量越大,搜索时间越长。在大规模数据集上,搜索大概必要很长时间才气完成。而近似 k - NN 搜索借助索引布局,能够明显减少搜索过程中必要盘算相似度的向量数目,搜索时间相对较短,尤其在处理海量数据时,优势更为显着。
  • 内存使用:精确暴力搜索不必要额外的内存来存储索引布局,仅需存储数据集本身。然而,近似 k - NN 搜索必要构建和维护索引布局,这会占用额外的内存空间。例如,HNSW 索引在构建过程中会天生多层图布局,每个节点都必要存储一定的连接信息,因此会斲丧更多的内存。
实用场景


  • 精确暴力搜索:实用于数据集较小、对搜索结果的精确性要求极高且对搜索时间没有严格限定的场景。例如,在一些数据量有限的科研项目中,研究人员大概更关注搜索结果的正确性,而不太在意搜索时间,此时精确暴力搜索可以满意需求。
  • 近似 k - NN 搜索:在实际应用中,尤其是面对大规模数据集时,近似 k - NN 搜索更为实用。例如,在图像搜索引擎中,大概必要处理数百万甚至数十亿张图像的向量数据,假如使用精确暴力搜索,搜索服从将极低。而近似 k - NN 搜索能够在较短的时间内返回近似最优的结果,满意用户对实时性的需求

  • 用精确搜索的情况


  • 公司只有200份合同,必要100%确保找到所有相干文件
  • 医疗诊断体系,不能容忍任何漏诊大概

  • 用近似搜索的情况


  • 淘宝有10亿商品图片,用户想快速找到相似款衣服
  • 抖音保举视频,答应少量误差但要求毫秒级相应
精确的强力kNN包管了正确的结果,但无法很好地扩展大型数据集。假如必须要使用精确暴力搜索,您可以通过使用查询参数来限定传递给函数的匹配文档的数目。假如过滤数据到一个小的文档子集,就可以得到很好的搜索结果。
三、Elasticsearch支持的其他语义搜索方式

Elasticsearch使用自然语言处理(NLP)和向量搜索提供各种语义搜索功能。使用NLP模型使您能够从文本中提取文本嵌入。嵌入是提供文本的数字表示的向量。具有相似含义的内容片断具有相似的表示。
Elasticsearch中的semantic_text字段也支持语义文本搜索。在使用时只必要将文档的字段设置为semantic_text, 不必要指定如何为数据天生嵌入,或者如何对其进行索引。推理端点自动确定要使用的嵌入天生,索引和查询。

翻译   告诫:此功能处于测试阶段,大概会发生变化。设计和代码不如官方GA功能成熟,并且按原样提供,没有任何包管。Beta版功能不受正式GA功能的支持SLA的限定。使用时必要注意风险
使用


  • 创建Index Mapping
    默认是使用预设置的.elser-2-elasticsearch端点,使用以下API哀求设置semantic_text:
  1. PUT semantic-embeddings
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "content": {
  6.         "type": "semantic_text"
  7.         //"inference_id": "my-elser-endpoint", 默认是使用预配置的``.elser-2-elasticsearch``端点,也可以自己设置推理端点
  8.       }
  9.     }
  10.   }
  11. }
复制代码

  • 加载数据
    将文档添加到索引时,Elasticsearch 会自动使用指定的推理端点盘算嵌入,并将其存储在 semantic_text 字段中。您无需手动天生嵌入向量。以下是索引文档的示例:
  1. PUT semantic-embeddings/_doc/1
  2. {
  3.   "content": "Elasticsearch 8.17 introduces semantic search capabilities."
  4. }
复制代码

  • 语义搜索
  1. GET semantic-embeddings/_search
  2. {
  3.   "query": {
  4.     "semantic": {
  5.       "field": "content",
  6.       "query": "如何在跑步时避免肌肉酸痛?"
  7.     }
  8.   }
  9. }
复制代码
使用嵌入丰富数据集之后,可以使用语义搜索查询数据。在语义查询类型中提供semantic_text字段名称和查询文本。用于为semantic_text字段天生嵌入的推理端点将用于处理查询文本。
通过上述步骤,您可以在 Elasticsearch 8.17 中使用 semantic_text 字段实现高效的语义搜索功能。该功能使搜索更加智能,能够理解查询的意图和上下文,从而提供更相干的搜索结果。
向量搜索典型应用场景


  • 基于自然语言处理(NLP)算法的相干性排序
  • 产品保举和保举引擎
  • 图像或视频的相似性搜索

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

民工心事

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表