向量数据库之如何使用Elasticsearch实现向量数据存储与搜索

 更新时间:2023年06月02日 11:03:38   作者:马超的博客  
这篇文章主要介绍了向量数据库之如何使用Elasticsearch实现向量数据存储与搜索,在向量函数的计算过程中,会对所有匹配的文档进行线性扫描,因此,查询预计时间会随着匹配文档的数量线性增长,本文给大家讲解的非常详细,需要的朋友参考下吧

Here’s the table of contents:

向量数据库:使用Elasticsearch实现向量数据存储与搜索

一、简介

  Elasticsearch在7.x的版本中支持 向量检索 。在向量函数的计算过程中,会对所有匹配的文档进行线性扫描。因此,查询预计时间会随着匹配文档的数量线性增长。出于这个原因,建议使用查询参数来限制匹配文档的数量(类似二次查找的逻辑,先使用match query检索到相关文档,然后使用向量函数计算文档相关度)。

  访问dense_vector的推荐方法是通过cosinessimilarity, dotProduct, 1norm或l2norm函数。但是需要注意,每个DSL脚本只能调用这些函数一次。例如,不要在循环中使用这些函数来计算文档向量和多个其他向量之间的相似性。如果需要该功能,可以通过直接访问向量值来重新实现这些函数。

二、实验前准备

2.1 创建索引设置向量字段

  创建一个支持向量检索的mapping,字段类型为dense_vector

// 7.x 支持的 dims 最大为 1024。
PUT index3
{
  "mappings": {
    "properties": {
      "my_vector": {
        "type": "dense_vector",
        "dims": 3
      },
      "my_text" : {
        "type" : "keyword"
      }
    }
  }
}

2.2 写入数据

PUT index3/_doc/1
{
  "my_text" : "text1",
  "my_vector" : [0.5, 10, 6]
}
PUT index3/_doc/2
{
  "my_text" : "text2",
  "my_vector" : [-0.5, 10, 10]
}

三、向量计算函数

3.1 余弦相似度:cosineSimilarity

  cosinessimilarity函数计算给定查询向量和文档向量之间的余弦相似性度量。

POST index3/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "source": "cosineSimilarity(params.queryVector, doc['my_vector'])+1.0",
        "params": {
          "queryVector": [-0.5, 10, 6]
        }
      }
    }
  }
}
  • 要限制script_score计算的文档数量,需要提供一个过滤器 (query)。
  • script脚本在cosineSimilarity上增加了1.0,以防止得分为负。
  • 为了更好的利用DSL优化器,可以使用参数的方式提供一个查询向量。
  • 检查缺失值:如果文档中没有用于执行向量函数的向量字段的值,会抛出错误。
  • 可以使用doc['my_vector'].size() == 0来检查文档是否有my_vector字段的值。

脚本样例:

"source": 
"
doc['my_vector'].size() == 0 ? 0 : 
cosineSimilarity(params.queryVector, 'my_vector')
"

  如果文档的dense_vector字段与查询的向量维度不同,就会抛出异常。

3.2 计算点积:dotProduct

  dotProduct函数计算给定查询向量和文档向量之间的点积度量。

POST index3/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "source": """
        double value = dotProduct(params.queryVector,doc['my_vector']);
        return sigmoid(1, Math.E, -value);
        """,
        "params": {
          "queryVector": [
            -0.5,
            10,
            6
          ]
        }
      }
    }
  }
}

使用标准的sigmoid函数可以防止分数为负。

3.3 曼哈顿距离:l1norm

  l1norm函数计算给定查询向量和文档向量之间的L1距离(曼哈顿距离)。

POST index3/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "source":"1 / (1 + l1norm(params.queryVector, doc['my_vector']))",
        "params": {
          "queryVector": [-0.5, 10, 6]
        }
      }
    }
  }
}

1.与表示相似性的余弦相似度不同,1norml2norm表示距离或差异。这意味着,向量越相似,由1norml2norm函数产生的分数就越低。因此,当我们需要相似的向量来获得更高的分数时,我们将1norml2norm的输出反过来。另外,为了避免在文档向量与查询完全匹配时被除0,在分母中加了1。

3.4 欧几里得距离:l2norm

  l2norm函数计算给定查询向量和文档向量之间的L2距离(欧几里德距离)。

POST index3/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "source": "1 / (1 + l2norm(params.queryVector, doc['my_vector']))",
        "params": {
          "queryVector": [
            -0.5,
            10,
            6
          ]
        }
      }
    }
  }
}

3.5 自定义计算函数

  使用函数访问向量的值,自定义实现向量余弦相似度计算。ES 中向量检索 doc[].vectorValue 函数是在 Elasticsearch 7.8.0 版本开始支持的,在ES 7.5.1 或 7.8.0 以下版本会运行失败。

  可以通过以下函数直接访问向量值:

  • doc[<field>].vectorValue – 以浮点数数组的形式返回向量的值。
  • doc[<field>].magnitude – 将向量的大小作为浮点数返回(对于7.5版本之前创建的向量,其向量的大小不会被存储)。所以这个函数每次被调用时都会进行重新计算。
POST index3/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "source": """
          float[] v = doc['my_vector'].vectorValue;
          float vm = doc['my_vector'].magnitude;
          float dotProduct = 0;
          for (int i = 0; i < v.length; i++) {
            dotProduct += v[i] * params.queryVector[i];
          }
          return dotProduct / (vm * (float) params.queryVectorMag);
        """,
        "params": {
          "queryVector": [
            -0.5,
            10,
            6
          ],
          "queryVectorMag": 5.25357
        }
      }
    }
  }
}

到此这篇关于向量数据库之如何使用Elasticsearch实现向量数据存储与搜索的文章就介绍到这了,更多相关Elasticsearch向量数据存储与搜索内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java单链表的实现代码

    Java单链表的实现代码

    这篇文章主要介绍了Java单链表的实现代码的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-07-07
  • Java Comparable和Comparator对比详解

    Java Comparable和Comparator对比详解

    这篇文章主要介绍了Java Comparable和Comparator对比详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Mockito mock Kotlin Object类方法报错解决方法

    Mockito mock Kotlin Object类方法报错解决方法

    这篇文章主要介绍了Mockito mock Kotlin Object类方法报错解决方法,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • 详解SpringBoot时间参数处理完整解决方案

    详解SpringBoot时间参数处理完整解决方案

    这篇文章主要介绍了详解SpringBoot时间参数处理完整解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 通过jenkins发布java项目到目标主机上的详细步骤

    通过jenkins发布java项目到目标主机上的详细步骤

    这篇文章主要介绍了通过jenkins发布java项目到目标主机上的详细步骤,发布java项目的步骤很简单,通过拉取代码并打包,备份目标服务器上已有的要发布项目,具体内容详情跟随小编一起看看吧
    2021-10-10
  • Java-Redis-Redisson分布式锁的功能使用及实现

    Java-Redis-Redisson分布式锁的功能使用及实现

    这篇文章主要介绍了Java-Redis-Redisson-分布式锁的功能使用及实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • 基于SpringBoot实现自定义插件的流程详解

    基于SpringBoot实现自定义插件的流程详解

    在SpringBoot中,插件是一种扩展机制,它可以帮助我们在应用程序中快速地添加一些额外的功能,在本文中,我们将介绍如何使用 SpringBoot实现自定义插件,需要的朋友可以参考下
    2023-06-06
  • Java四种访问控制修饰符知识点总结

    Java四种访问控制修饰符知识点总结

    本篇文章给大家详细分析了Java四种访问控制修饰符的相关知识点,有兴趣的朋友可以参考学习下。
    2018-03-03
  • Spring Boot项目获取resources目录下文件并返回给前端的方案

    Spring Boot项目获取resources目录下文件并返回给前端的方案

    我们在项目中经常碰到需要读取固定文件的场景,如模板文件,一般做法是将文件放在resources目录下,程序通过多种方式可以顺利读取文件,这篇文章主要给大家介绍了关于Spring Boot项目获取resources目录下文件并返回给前端的相关资料,需要的朋友可以参考下
    2024-07-07
  • Java开发常见异常及解决办法详解

    Java开发常见异常及解决办法详解

    这篇文章主要介绍了java程序常见异常及处理汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-09-09

最新评论