当前位置:   article > 正文

详细教程:如何使用elasticsearch 8.x进行向量搜索_elasticsearch向量检索

elasticsearch向量检索

目录

前置知识

操作

生成向量

建立索引

查询

过滤后knn搜索

knn搜索和query混合使用

其他注意点

knn搜索api的变动

script_score精确查询

应用瓶颈

参考文章


大模型的热度使得向量数据库和embedding也成了ai领域的热门话题,有别于从头开始训练一个大模型或基于基础模型进行微调的方式,embedding检索相关上下文是对大模型进行定制的各种方法中成本最低、技术实现最便捷的方式。

从技术实现的角度,embedding检索相关上下文是预先将要检索的文本内容使用Embedding转换成向量数组,然后保存在向量数据库,检索的时候,将检索的内容也使用Embedding转换成向量数组,然后去向量数据库做相似度检索,找出最相关的前若干条内容,再和问题一起提供给大语言模型,以保证大语言模型能获取到正确的信息。

向量搜索领域,现在有很多专业的向量数据库可供选择,但在预研阶段,elasticsearch8.x提供的向量搜索功能已足够我们进行试验探索。接下来将对 如何基于es 8.x进行向量搜索进行介绍。

前置知识

elasticsearch早在7.2.0版本就引入了dense_vector字段类型,支持存储高维向量数据,如词嵌入或文档嵌入,可以利用向量函数使用script_score查询来执行精确knn。

从8.0版本开始,新增了KNN向量近邻检索可以使用近似knn搜索,此外通过python Eland库,支持用户自定义上传机器学习模型至es,使用pipeline自动生成指定字段向量(白金版功能,免费版不可用)。

dense_vector:用于存储浮点类型的密集向量,其最大维度为2048。该字段不支持聚合和排序

knn搜索:一种分类和回归方法,是监督学习方法里的一种常用方法。k近邻算法假设给定一个训练数据集,其中的实例类别已定。分类时,对新的实例,根据其k个最近邻的训练实例类别,通过多数表决等方式进行预测。k近邻法三要素:距离度量、k值的选择和分类决策规则。其中,k值和距离度量在es参数中可设置调整。

操作

生成向量

根据需要,可以借助BERT模型、GloVe 、Word2vec或者chatgpt embedding api等将文本转为向量,网络上很多相关文章,这里就不赘述了

建立索引

  1. PUT test-index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "title-vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": true,
  9. "similarity": "l2_norm"
  10. },
  11. "title": {
  12. "type": "text"
  13. },
  14. "file-type": {
  15. "type": "keyword"
  16. }
  17. }
  18. }
  19. }

注意:1.使用近似knn,dense_vector字段必须开启索引,即 index要设置为true;

2.similarity用来定义文档间的相似度算法,l2_norm为欧式距离,其他可选项可参见官方文档;

3.dims是向量维度大小,当index为true时,不能超过1024,当index为false,不能超过2048。且该值必须与后续写入的向量维度一致!!需根据事先确定生成好的向量维度来定义dims

查询

  1. POST test-index/_search
  2. {
  3. "knn": {
  4. "field": "title-vector",
  5. "query_vector": [-5, 9, -12],
  6. "k": 10,
  7. "num_candidates": 100
  8. },
  9. "fields": [ "title", "file-type" ]
  10. }

文档的分数由查询和文档的向量决定,具体怎么计算,参考similarity参数。

knn api 会先去每个分片找num_candidates个最近邻候选者,然后每个分片计算最优的k个。最后把每个分片的结果合并,在计算出k个全局最优。

每个分片要考虑的最近邻候选者的数量,不能超过 10000。num_candidates往往可以提高最后k个结果的精确度,但是更好的结果会带来更多的消耗。k值必须比num_candidates要小

过滤后knn搜索

  1. POST test-index/_search
  2. {
  3. "knn": {
  4. "field": "title-vector",
  5. "query_vector": [54, 10, -2],
  6. "k": 5,
  7. "num_candidates": 50,
  8. "filter": {
  9. "term": {
  10. "file-type": "article"
  11. }
  12. }
  13. },
  14. "fields": ["title"],
  15. "_source": false
  16. }

knn搜索和query混合使用

  1. POST test-index/_search
  2. {
  3. "query": {
  4. "match": {
  5. "title": {
  6. "query": "mountain lake",
  7. "boost": 0.9
  8. }
  9. }
  10. },
  11. "knn": {
  12. "field": "title-vector",
  13. "query_vector": [54, 10, -2],
  14. "k": 5,
  15. "num_candidates": 50,
  16. "boost": 0.1
  17. },
  18. "size": 10
  19. }

注意!!!

knn搜索和DSL语法混合使用,采用的是多路归并的思路,即分别检索标签和向量再进行结果合并。虽可以解决部分问题,但多数情况下结果不甚理想。主要原因在于,向量检索无范围性,其目标是尽可能保证 TOPK 的准确性,TOPK 很大时,准确性容易下降,造成归并结果的不准确甚至为空的情况。

以列出的混合查询语句为例,这个查询是先得到全局5个最相邻结果,然后将他们与匹配查询匹配的结果组合,选出得分最高的前10个返回。分数的计算采取:

score = 0.9 * match_score + 0.1 * knn_score

近似knn还可以搭配聚合,它聚合的是top k个邻近文档的结果。如果还有query,那么聚合的是混合查询的结果。

其他注意点

knn搜索api的变动

在8.4版本前,es短暂提供过knn搜索api

POST test-index/_knn_search

但在8.4版本后,统一将knn搜索调整为搜索api _search的参数

  1. POST test-index/_search
  2. {
  3. "knn": {
  4. "field": "test-vector",
  5. "query_vector": [-5, 9, -12],
  6. "k": 10,
  7. "num_candidates": 100
  8. },
  9. "fields": [ "title", "file-type" ]
  10. }

所以如果在网络文章上看到该api但在搜索集群上无法使用请不要惊讶,搜索集群是8.7.0的,之前的_knn_search用法已经被取消了

script_score精确查询

在上述的操作过程中,我都默认使用了近似knn搜索而没有提及基于script_score的精确knn,这是因为精确knn本质上是使用脚本来重新定义score的计算方式,在分数中引入向量匹配的部分,script_score查询将扫描每个匹配的文档来计算向量函数。也自然会有使用脚本的最普遍问题:极易导致慢查询,搜索性能变差。

有效的改善方式是使用query来限制传递给向量函数的匹配文档集。但在实际业务应用中很难把性能提高到满意的程度,因此在大多数情况下不建议使用精确knn。

  1. POST test-index/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term": {
  9. "file-type": "article"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": "cosineSimilarity(params.queryVector, 'title-vector') + 1.0",
  16. "params": {
  17. "queryVector": [90.0, -10, 14.8]
  18. }
  19. }
  20. }
  21. }
  22. }
应用瓶颈

将Embedding和 LLM 结合来解决上下文长度限制、私有数据安全等问题的应用有很多,例如ChatPDF应用、langchain开源框架、bloop.ai产品、Supabase技术文档等,大模型出现后很多ai产品都采用这套原理。

但正如网络上很多声量所讨论的那样,embedding或者说向量数据库的引入更多是一种工程层面的辅助,是迫于当前大模型的瓶颈(比如输入token长度的限制)而进行的“打补丁”操作。

embedding这一技术本身并不是新鲜事物,所以在使用时,会面临embedding固有的一些问题,最根本的就是 搜不准。embedding检索是基于语义的检索,与传统搜索基于关键词的检索相当不同。

举一个例子是:

假设数据库里有一段文字 “老鼠在寻找食物”。用户输入了"'奶酪’”的查询。文本搜索根本无法识别这段话,它不包含任何重叠部分。

但是通过Embedding,这两段文字都变成了向量,然后可以对这段文字进行相似性搜索。因为“老鼠”和“奶酪”在某种程度上是相关的,所以尽管缺乏匹配的词,用户还是能够得到该段落的结果。

它的局限性在于,如果你在一段不相干的文字中突然记了一句“老鼠在寻找食物”,用向量很可能输入“老鼠”也搜不出来,而关键词又能找出来。

在embedding的具体使用中,文本转向量模型选择的不同和相似度搜索时nn选择的不同都会与向量搜索出的结果产生很大影响,表现在搜索结果上,就是在人看来风马牛不相及的内容会出现在结果集里。或许,将embedding搜索与传统搜索互补结合,能在一定程度上弥补这一问题,这也需要进一步探索了。

最后,尽管本文是介绍在es中使用向量搜索,但当前开源生态中最热门的向量数据存储工具应该是PostgreSQL的拓展模块pg-vector,如果你想了解更多关于向量数据库的内容,推荐阅读:[向量数据库 ] 向量数据库

参考文章

[Search API | Elasticsearch Guide [8.7] | Elastic] Search API | Elasticsearch Guide [8.7] | Elastic

[ES-KNN搜索-CSDN博客] ES-KNN搜索_es knn-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/916300
推荐阅读
相关标签
  

闽ICP备14008679号