【向量数据库】搜索算法

最近几年,一种叫做向量数据库的产品,正趁着AI的热潮开始崭露头角。伴随着AI时代的到来,向量将成为一种重要的数据形式,而传统数据库并不适合用来存储和检索向量数据,因此我们大约需要一种专门设计的数据库来处理这些问题。

和存储数据表,然后用查询语句进行精准搜索的传统数据库不同,向量数据库存储的是向量数据,而查询过程则是从库中搜索出和查询向量最为相似的一些向量,具有一定的模糊性。

相似度计算

计算向量相似度的方法有很多,常用的有余弦相似度、欧几里得距离等

余弦相似度 (Cosine Similarity)

  • 二维示意图

测量两个向量之间角度的余弦值。它的值范围从 -1 到 1,其中 1 表示向量完全相同,0 表示向量正交,-1 表示向量完全相反,当拥有的数据中向量的模长很重要,余弦相似度就不合适。
在这里插入图片描述

  • 计算公式

余弦相似度指两个向量之间夹角的余弦值,反映了它们的方向相似性。余弦相似度的取值范围是[-1, 1],1表示方向完全相同,-1表示方向完全相反。

sim ( a , b ) = a ⋅ b ∥ a ∥ ∥ b ∥ \text{sim}(a, b) = \frac{a \cdot b}{\|a\| \|b\|} sim(a,b)=a∥∥bab

欧式距离 (Euclidean Distance)

  • 二维示意图

测量两个向量之间的直线距离。它的值范围从 0 到无穷大,其中 0 表示向量完全相同,较大的值表示向量越来越不相似。欧氏距离对大小敏感,向量包含与计数或度量有关的信息时,它非常有用。
在这里插入图片描述

  • 计算公式

欧几里得距离表示两个向量在空间中的直线距离,距离越小,则表示两个向量之间越相似。

d ( a , b ) = ( a 1 − b 1 ) 2 + ( a 2 − b 2 ) 2 + … + ( a n − b n ) 2 d(a, b) = \sqrt{(a_1 - b_1)^2 + (a_2 - b_2)^2 + \ldots + (a_n - b_n)^2} d(a,b)=(a1b1)2+(a2b2)2++(anbn)2

点积(Dot product)

测量两个向量的模长乘积以及它们之间角度的余弦值。它的值范围从负无穷到正无穷,正值表示向量指向相同方向,0 表示向量正交,负值表示向量指向相反方向。

  • 计算公式

a ⋅ b = ∑ i = 1 n a i b i a \cdot b = \sum_{i=1}^{n} a_i b_i ab=i=1naibi

不同的相似度计算方法适用场景不同,需要考虑向量的特性和具体的应用场景,来选择合适的相似度计算方法。

  • 余弦形似度
    适用于高维且稀疏的向量的计算,因为它只关注向量的方向,不关注向量的大小。常用于信息检索中文本相似度的计算。

  • 欧几里得距离
    适用于低维且密集的向量的计算,因为它直接反应向量之间的几何距离。常用于图像特征向量相似度的计算。

相似性搜索

向量数据库的一大特点就是其高效的相似性搜索能力,能够快速的检索出与查询向量最相似的向量

最近邻搜索算法

通过以上这些例子不难看出,向量数据库的主要应用场景就是:给定一个查询向量,然后从众多向量中找到最为相似的一些,这就是所谓的最近邻问题。而能实现这一点的则称之为最近邻搜索算法。

在这里插入图片描述

暴力搜索

一种最容易想到的方法可能就是"暴力搜索",也叫平坦搜索,就是直接一路平推过去,依次比较所有向量和查询向量的相似度,挑选出相似度最高的几个。
在这里插入图片描述

显然,如果库中的向量过多,这种毫无技术含量的暴力方法将导致极高的搜索时间。但这种方法也有其他方法永远无法达到的一个好处:搜索质量是完美的,因为它真的比较了每一个向量。所以如果库中数据规模较小,遍历全部向量的时间可以接受,这也不失为一种好的方法。

然而实际应用中的数据规模往往都不会太小,所以必须要找出一些方法进行优化。有一种朴素的想法指出了优化的大致思路,可以用一个寻人的例子来说明。
假如已经知道照片上这人在A城市,现在请你想一个办法把他找出来。爆搜相当于去找A城市的每一个人逐一比较,这样一定能找到,但要花费海量的时间。但通过胸前的红领巾知道他是一名小学生,所以就把寻找范围缩小到A市的所有小学,如此就可能将千万级别的查找次数降到只有几十万的级别。
在这里插入图片描述

近似最近邻搜索(ANN)

近似最近邻搜索 - Approximate Nearest Neighbor

暴力搜索的问题在于它需要遍历所有的数据,那么可以考虑在搜索范围上去做优化,减少搜索的范围,来提升效率。

俗话说,物以类聚。相似度高的向量在坐标轴上的距离会更相近,而相似度低的向量直接则相距甚远。于是,可以根据向量的相似情况,将它们划分为若干个类别,每个类别可以计算出一个聚类中心。在搜索时,我们先找到与检索向量最相近的聚类中心,然后只需要在这个类别中检索最相似的内容即可。这样就大大减少了搜索的范围。

当然,这种搜索方式得到的结果不一定是最准确的,因为,缩小搜索范围的同时,也可能错过了一些正确的结果。
不过,搜索的质量和速度本身就是矛盾的关系,提升质量也就意味着需要消耗更多的时间,所以,保证质量可接受的前提下,牺牲一部分质量,换取更快的速度是值得的,这就是近似最近邻搜索的思想

聚类算法(k-means)

对于向量的搜索问题,假如能够为查询向量先划定一个大致范围再搜索。有一种称之为聚类的算法可以实现这一点。以最为流行的k-means聚类算法为例:

  1. 选一个想要分类的数量,比如4类

  2. 随机生成4个点,称之为聚类中心点

  3. 这些向量和哪个中心点最近就被分为哪一类
    在这里插入图片描述

  4. 用当前被分为一类的向量计算出一个平均向量点
    在这里插入图片描述

  5. 把对应的中心点的位置更新为这个平均点
    在这里插入图片描述

  6. 判断每个向量点和哪一个中心点最近,重新分类

  7. 继续用同一类的向量点计算出一个平均点,把中心点更新过去,再次重新分类,如此反复

这个不断迭代的过程,就称之为训练。最后这些中心点将趋于稳定,或者说收敛。最终将这些向量分成了4类。如此在搜索的时候,只需要找出和查询向量最近的那个聚类中心,搜索这个分类中的向量即可,也就实现了缩小搜索范围的目的。

当然,聚类方法并不能保证不会出现遗漏的问题,比如查询向量在这里,但和他最接近的向量其实在这个分类中
在这里插入图片描述
有一些缓解这个问题的办法,比如增加聚类的数量,同时指定搜索多个最近区域从而减少遗漏。但只要是试图提高搜索质量,基本上都会增加搜索时间,实际上速度和质量,往往是一对难以调和的矛盾。
在这里插入图片描述

几乎所有的算法都是在这两个指标上结合实际情况衡量的结果(还有一个存储问题),所以现实就是除了爆搜能一定找到最近邻的一些向量以外,其他任何方法都不能保证这一点。而只能得到一些近似的结果,所以这些算法一般被称之为近似最近邻算法(ANN, Approximate Nearest Neighbors)

位置敏感哈希(LSH)

除了聚类以外,减少搜索范围的方式还有很多,介绍一种比较流行的基于哈希的方法,位置敏感哈希(Locality Sentence Hashing)。
哈希的概念简单来说就是,任何数据经过哈希函数计算后,都会输出一个固定长度的哈希值,比如128位
在这里插入图片描述

而且由于输入是任意数据,而输出是固定长度的数据,以有穷对无穷,根据鸽巢原理必然会出现数据不同但哈希值相同的情况,这也被称之为碰撞。通常情况下,哈希函数的设计一般力求减少这种碰撞的发生。但这里所构建的哈希函数却反其道而行,它力求增大碰撞发生的可能。因为哈希碰撞正是分组的依据,这些分组也被称之为桶(Bucket)
在这里插入图片描述

除了容易发生碰撞以外,这个哈希函数还要具备这样一个特征:位置越近,或者说越相似的向量,发生碰撞的概率越高,被分到一个桶中的可能性越大。如此,在查询的时候只需要计算一下查询向量的哈希值,找到其所在的桶,再在这个桶中搜索就好。因为和查询向量最相似的一些向量,大概率都在这个桶中。把具体这种特性的哈希函数称之为(对向量)位置敏感的哈希函数LSH。

LSH的思想是设计一组哈希函数,满足

  1. 容易发生碰撞
  2. 两个向量之间相似程度越高,则映射出的哈希值相同的概率越高
函数实现

这样的哈希函数怎么实现呢?看一种常用的手法。以A、B、C三个向量为例:

  1. 随机生成一条直线,而且这条直接区分正反两侧
    在这里插入图片描述
    如果一个向量在这条线的正的一侧,那么它就是1,如果在反的一侧那么就是0

  2. 再随机生成一条直线
    在这里插入图片描述
    同样正侧的向量是1,反侧的向量是0

如此这般,随机生成若干个这样的直线,每次都根据向量所在的正反侧得到1或者0。如果一共使用四条随机的直线,如此就为每个向量算出了4个0或1,各自得到一个四位的二进制编码
在这里插入图片描述

现在观察一下这3个二进制编码的相似程度,很明显,AC这两个相近的向量的编码更为相似,只有第3位不同,相似度高达3/4(这种比较方式也称汉明距离)。而这个较远的B和AC的相似度都很低,一个是1/4,一个是0
在这里插入图片描述
所以为什么向量越接近,得到的二进制编码越相似呢?直观的来定性分析一下
在计算这4个二进制编码的某一位的时候,如果要让B和C的结果一样,这条线无论如何,一定要从AC和BC之间穿过去
在这里插入图片描述

同样,如果要让A和C的结果一样的,这条线应该从BC和AB之间穿过
在这里插入图片描述

忽略共同穿越的AB,直观上来看,B和C之间的宽度要远大于A和C之间的宽度。而直线是随机生成的,所以从概率上来说,生成的直线从BC间穿过的可能性要比从C间穿过的要更大。所以在生成二进制编码的过程中,C更有可能和A的一样而不是B。

同样如果要让A和B的编码值一样,直线要穿过AC和BC。而如果要让A和C的结果一样,这条线应该从BC和AB之间穿过。忽略共同穿越的BC,AC间的宽度也远小于AB,所以A也是更有可能和C一样而不是B。

所以这串二进制编码便可以作为向量的哈希值,而这个生成的过程就是一种寻找的哈希函数。因为它满足刚才所说的两个要求:

  1. 容易碰撞
  2. 越近越容易碰撞

越近越相似的向量,越容易碰撞以至于被分到一个桶中

当然,这个三个向量的哈希值并不完全相同,但如果在观察一个距离A更近的D,会发现D最后的二进制编码或者说哈希值和A一样,发生了碰撞
在这里插入图片描述
用4个向量展示了这个方法的基本工作原理,而对于真实情况中许多的向量而言,每个向量通过这个哈希函数后,都会得到一串二进制编码的哈希值。
在这里插入图片描述
而那些非常接近的向量的哈希值大概率是一样的(碰撞),也就会被分到了同一个桶中。对于更高维度的向量,道理也是一样的。比如三维便可以使用三维空间中的一个随机平面来做哈希函数的计算。在这里插入图片描述
这个面也有正反,正面的向量得到1,反面的得到0,若干的随机平面自然也得到了一串二进制编码的哈希值。

如果是更高的维度,在这些更高维度中也存在着高维的超平面,同样也可以完成这样的哈希值生成。所以把这种方法称之为随机超平面或者随机投影。

当然,除了直接爆搜,任何试图减少搜索量的方法都会在一定程度上降低搜索的质量。

比如还是这四个向量,现在用9个随机直线,每个向量生成长度为9的二进制哈希编码,可能是这样的过程,AD两个比较近的点的哈希值一致,被分到了同一个桶中,这是比较理想的结果。
在这里插入图片描述

分段优化

但因为直线是随机的,所以这个过程也有可能是这样的,在生成第6个编码的时候,这个直线就随机到了AD中间穿过,导致A和D的哈希编码的第6位不同
在这里插入图片描述
虽然说概率比较小,但毕竟是有可能发生的,最后A和D无法进入同一个桶。
LSH一般会采用一种分段的措施来改善这种情况。比如:

  1. 把这些二进制哈希值分成3段
    在这里插入图片描述
  2. 独立对这些片段进行分桶
    在这里插入图片描述
    虽然AD的第二个片段被分到了不同的桶中,但第1、3两个片段被分到了同一个桶。可以采用只要匹配一个片段,就将其作为候选项的策略,合理的扩充更多的搜索范围。在这种分段措施下,A和C的第二段也分到一个桶中,两者由此成为了相似向量的候选项,因为它们比较接近,这是一种合理的扩充,而B则没有任何一个段和其他向量对应的段被分到同一个桶中,因为它们距离很远,这很合理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/66602.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ARM CCA机密计算安全模型之安全生命周期管理

安全之安全(security)博客目录导读 目录 一、固件启用的调试 二、CCA系统安全生命周期 三、重新供应 四、可信子系统与CCA HES 启用 CCA(机密计算架构)的安全系统是指 CCA 平台的实现处于可信状态。 由于多种原因,CCA 启用系统可能处于不…

k8s排错集:zk集群的pod报错 Init:CrashLoopBackOff无法启动

zk三节点集群,zk-0无法启动 statefulset 进到该node节点上查看容器的报错日志,发现在初始化container的时候一个命令有问题 查看正常zk集群的pod的资源配置文件 解决办法: 修改资源配置文件 应该修改为 chown -R 1000:1000 /zkenv kubec…

Golang的并发编程框架比较

# Golang的并发编程框架比较 中的并发编程 在现代软件开发中,处理高并发的能力愈发重要。Golang作为一门支持并发编程的编程语言,提供了丰富的并发编程框架和工具,使得开发者能够更轻松地处理并发任务。本文将介绍Golang中几种常用的并发编程…

【Web】软件系统安全赛CachedVisitor——记一次二开工具的经历

明天开始考试周,百无聊赖开了一把CTF,还顺带体验了下二开工具,让无聊的Z3很开心🙂 CachedVisitor这题 大概描述一下:从main.lua加载一段visit.script中被##LUA_START##(.-)##LUA_END##包裹的lua代码 main.lua loca…

单纯形法的学习笔记

文章目录 A. 单纯形法概述1. 优化模型示例 B. 理论基础C. 算法思想D. 实现算法1. 线性规划的标准型2. 顶点解的理解及表示2.1 在标准型中变量取值为零的意义2.2 顶点解的表示 3. 最优性判断4. 解的更新5. 完成迭代过程 E. 单纯形法的基本概念与本文对照F. 文档源码 前言&#x…

【VBA】【EXCEL】将某列内容横向粘贴到指定行

Sub CopyRowToColumn()On Error GoTo ErrorHandler 添加错误处理Application.ScreenUpdating FalseApplication.Calculation xlCalculationManualApplication.EnableEvents False 禁用事件处理Dim lastCol As LongDim lastRow As LongDim i As Long, colCount As LongDim …

JS进阶--JS听到了不灭的回响

作用域 作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问 作用域分为局部和全局 局部作用域 局部作用域分为函数和块 那 什么是块作用域呢? 在 JavaScript 中使用 { } 包裹的代码称为代码块…

计算机网络 (26)互联网的路由选择协议

一、路由选择协议的基本概念 路由选择协议是计算机网络中用于确定数据包在网络中传输路径的一种协议。它帮助路由器构建和维护路由表,以便根据目的地址将数据包转发到正确的下一跳路由器。路由选择协议分为静态路由选择协议和动态路由选择协议两大类。 二、静态路由…

Spring项目创建流程及配置文件bean标签参数简介

1. 项目搭建流程 1. pom.xml中引入依赖Spring-webMVC <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><…

左神算法基础巩固--2

文章目录 稳定性选择排序冒泡排序插入排序归并排序快速排序堆排序 哈希表链表解题 稳定性 稳定性是指算法在排序过程中保持相等元素之间相对顺序的特性。具体来说&#xff0c;如果一个排序算法是稳定的&#xff0c;那么对于任意两个相等的元素&#xff0c;在排序前它们的相对顺…

UART串口数据分析

串口基础知识详细介绍&#xff1a; 该链接详细介绍了串并行、单双工、同异步、连接方式 https://blog.csdn.net/weixin_43386810/article/details/127156063 该文章将介绍串口数据的电平变化、波特率计算、脉宽计算以及数据传输量的计算。 捕获工具&#xff1a;逻辑分析仪&…

机器学习模型评估指标

模型的评估指标是衡量一个模型应用于对应任务的契合程度&#xff0c;常见的指标有&#xff1a; 准确率&#xff08;Accuracy&#xff09;: 正确预测的样本数占总样本数的比例。适用于类别分布均衡的数据集。 精确率&#xff08;Precision&#xff09;: 在所有被预测为正类的样…

面试题解,JVM中的“类加载”剖析

一、JVM类加载机制说一下 其中&#xff0c;从加载到初始化就是我们的类加载阶段&#xff0c;我们逐一来分析 加载 “加载 loading”是整个类加载&#xff08;class loading&#xff09;过程的一个阶段&#xff0c;加载阶段JVM需要完成以下 3 件事情&#xff1a; 1&#xff0…

腾讯云AI代码助手编程挑战赛-古诗词学习

一、作品介绍 在科技与文化深度交融的当下&#xff0c;“腾讯云 AI 代码助手编程挑战赛 - 每日古诗词” 宛如一颗璀璨的新星&#xff0c;闪耀登场。它绝非一场普通的赛事&#xff0c;而是一座连接编程智慧与古典诗词韵味的桥梁。 这项挑战赛以独特的视角&#xff0c;将每日古…

GelSight Mini视触觉传感器凝胶触头升级:增加40%耐用性,拓展机器人与触觉AI 应用边界

马萨诸塞州沃尔瑟姆-2025年1月6日-触觉智能技术领军企业Gelsight宣布&#xff0c;旗下Gelsight Mini视触觉传感器迎来凝胶触头的更新。经内部测试&#xff0c;新Gel凝胶触头耐用性提升40%&#xff0c;外观与触感与原凝胶触头保持一致。此次升级有效满足了客户在机器人应用中对设…

【C++入门】详解(上)

目录 &#x1f495;1.C中main函数内部———变量的访问顺序 &#x1f495;2.命名空间域namespace &#x1f495;3.命名空间域&#xff08;代码示例&#xff09;&#xff08;不要跳&#xff09; &#x1f495;4.多个命名空间域的内部重名 &#x1f495;5.命名空间域的展开 …

Ungoogled Chromium127 编译指南 MacOS篇(八)- 开始编译

1. 引言 完成了所有依赖包的安装后&#xff0c;我们终于来到了最关键的编译阶段。在开始编译之前&#xff0c;有一些重要的配置信息需要了解。本文将指导您完成整个编译过程。 2. 签名相关说明 虽然在我们的测试编译中不需要进行签名操作&#xff0c;但了解官方的签名要求仍…

使用uniapp 微信小程序一些好用的插件分享

总结一下自己在开发中遇见的一问题&#xff0c;通过引入组件可以快速的解决 1.zxz-uni-data-select 下拉框选择器(添加下拉框检索&#xff0c;多选功能&#xff0c;多选搜索功能&#xff0c;自定义 下拉框插件&#xff0c;使用这个的原因是因为 uniui uview 组件库下拉框太…

腾讯云AI代码助手编程挑战赛-有趣的冷知识分享

作品简介 有趣的冷知识这一编程主要用于对于小朋友的探索力的开发&#xff0c;让小朋友在一开始就对学习具有探索精神。在信息化时代下&#xff0c;会主动去学习自己认知以外的知识&#xff0c;同时丰富了眼界&#xff0c;开拓了新的知识。 技术架构 使用python语言的TK库…

使用 SQL 和表格数据进行问答和 RAG(7)—将表格数据(CSV 或 Excel 文件)加载到向量数据库(ChromaDB)中

将表格数据&#xff08;CSV 或 Excel 文件&#xff09;加载到向量数据库&#xff08;ChromaDB&#xff09;中。这里定义的类 PrepareVectorDBFromTabularData&#xff0c;它的主要功能是读取表格数据文件到DataFrame中、生成嵌入向量、并将这些数据存储在向量数据库的集合中&am…