高维向量检索的设计与实践(二)|学习笔记

本文涉及的产品
PolarClaw,2核4GB
简介: 快速学习高维向量检索的设计与实践(二)

开发者学堂课程【PostgreSQL 实战进阶高维向量检索的设计与实践(二)】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/112/detail/1908


高维向量检索的设计与实践(二)

 

内容介绍:

一、背景介绍

二、向量检索算法/PG 自定义索引

三、PASE 设计与实现

四、PASE 使用实践

二、向量检索算法/PG 自定义索引:

1.向量检索常用算法

向量检索最简单的一种实现方法,就是逐一比对的方式,也简称为暴力搜索的方式。优点就是它的准确率足够高,逐一比对总能找到最相似的向量,像那种方式的准确率是100%,但是它的缺点是查询耗时很高,这种方式是不能应用于工业界的场景中的,因此业界也研究出来就是很多的这个向量算法,向量检索算法也简称为ANN检索算法,就是近似对近邻的方式。通过这个简称也能发现,一般的实现方式都是运用这个精度来换取来换取性能的大幅提升。因此一个算法好坏的就是来衡量这个转化的效率是否足够高,能用很小的精度损失来换取大幅的竞争,那这个就是一个好的算法。那目前常用的这个算法,经过总结基本可以分为这样四大类,基于树的,基于 Hash 的,基于量化的,还有基于图的。

这四个方式各有优缺点,也各有不同的应用场景,树它的特点是对空间进行逐级的切分,直到树的叶子节点只覆盖空间的一个很小的部分,通过这个方式来大幅的提升这个检索的性能。 

Hash 是一个典型的这个算法,是局部敏感哈希算法,他们的共同特征呢,是通过超平面或者一个曲面将空间进行直接的切分,对切分后的这个空间进行二进制的编码,查询只在部分空间中进行,因此来排除掉大部分就是不相关的一些空间,来达到加速的目的。

第三个量化的方式它的思想其实很简单,就是对象进行聚类等等来进行量化。将这个相邻的向量使用中心点来代替,查询只在这些中心点中进行,排除掉大部分不相关的这些向量类图,从而达到讲述这样一个目的,

最后一个算法就是基于图的算法,它的核心思想都是一个就是近邻近邻也可能是近邻,通过离线构建一张临近关系图,查询到在途中迭代的去查找,不断的去逼近最近的这个近邻。 

 image.png

2.典型算法讲解

那这四种方式,刚才提到了个优缺点,在使用场景,根据各个业务的这个不同的要求来进行选举,下面会针对一些典型的一些算法,来对他们的算法原理,进行一个详细的一个描述。

首先第一个是粗量化的,简称叫 IVFFlat,就是量化的一种方式。他的算法原理,其实很简单,从图中可以看到这些向量的天然就有聚类的属性,比如把这个空间分成两个类,如图所示,它是上下两个类,每个类它存在一个中心点,比如图中的红点,用红点来表示这个类聚的中心点,这是离线的处理过程,在线查询的时候,根据 query 和两个中心点进行比较,查到它距离哪个中心点最近,只保留这个中心点所在的类图,丢弃其他不相关的类图,比如图中保留上面的这个类图,查询会在这个类中在进行。这是他的算法原理,那这种算法的优缺点其实很明显,优点这个算法足够简单,只需要聚类即可,但它的缺点也很明显,就是它的精度,其实可以足够高,查询的中心点我可以保留很多,比如图中可以留两个中心点,相当于暴力简短,但精度换取性能效率并不高。它适用的场景就是适用于一些就是精度要求可能会很高,但是对查询要求,查询耗时的要求不高的一些场景,一般在百毫秒级的这些要求。

 image.png

下一个就是 IMI 这样一个算法,它的这个产生的背景,就是解决刚才提到的粗量化的一些问题,比如这里提到的两个背景知识,首先对于粗量化它的候选集质量效果天花板,比如说图中所示通过粗量化,它只保留了这两类图,这个类图它最终效果好坏,决定于这两个类中的点是否足够的相近,另一个它的数量巨大,如图这两个类图,它的点数是很多的,在查询的过程中,会比较好使,这是 IMI 产生的一个背景,我们来看他怎么来解决这样的一个问题。我以两维的为例,x 轴和 y 轴,它的解决方案思想其实很简单的,就是将向量进行两维度的切分,在每个维度上分别进行聚类,比如 X 轴和 Y 轴两个空间,分别进行聚类,它的查询效率,性能与粗量化类似的,它的好处直接把聚类分得更细,从图中这个事例就可以看到,查询的范围都是集中在这个点的周围的这些点上。它的优点和 IVFFlat 类似,它可以达到很高的精度。同时,它的这个查询性能耗时会比粗量化更低。缺点是它的实现要比 IVFFlat 更复杂,图中可以看到会增加这个分段阶段聚类这样一个过程,同时,它的耗时会比IVFFlat 高,但是高的并不是很明显,那这种场景适合 IVFFlat 之类的。对准确率有一定要求,同时对产品耗时要求并不高的这样一个场景。

 image.png

那以上都是基于量化的方式来实现的这样的两种算法,考虑另外的一种实现方案,就是基于近邻图的这种方式。它的方法论就是近邻的近邻也可能是近邻,如何来实现这个查找过程?首先先将这个离线的这些向量进行近邻图的构造,比如图中实例,将它做成一张邻接图,同时会随机的采用一个入口点,绿色的点是查询点,查询是从入口点进入,查询它和它的邻近点之间哪一个距离 query 更近,比如有两个点都离他更近,那我就保留其中一个点。然后,从这个点再找它和它的邻近点之间哪一个距离 query 更近,依次迭代,最终找到最近的这个向量,这种方式能够比较快速的,就是经过比较少量的向量距离来定位到这个最近邻。

但是这种方式连接图的方式,有一些可以优化的点,比如这张图中,如果点数非常多,这个入口点距离最近邻距离比较远的情况下,可能会经过多次的调整才能查到最近邻,如何来优化这个问题。

一种方法是采用跳表的思想,就是采用多层邻近图的方式,那上层图是下层图的缩略图,可以想象一个场景,就是从一个地方到另一个地方,首先要走的是高速公路,然后会走城市之间的道路,然后再走乡镇之间的这种道路,通过这种方式,能快速的定位到它可能出现的区域,从而达到加速查找的这个目的。

这种多层图的思想就是 HNSW 这种图上的核心思想,这种算法的优点就是查询速度非常高,同时准确率就有一定的保障,但是它的缺点就是这些邻接点的这个存储会浪费一定的内存磁盘,会带来空间的这种伤感,可以适用于大部分的这种场景,对于产品耗时有一定要求,同时这个准确率有要求的这个场景,另外对于存储耗时不敏感的场景都可以采用近邻图的算法。

 image.png

有了这些图算法之后,其实已经出现了很多的这个 ANN 算法库,比较有名的是faiss,第一个就是 Facebook 开源向量检索库,它的优势是 A NN 算法还是很齐全的,目前业界中的很多研究方向都是基于faiss开的一些库来进行优化,这是它的优势。但是有些问题就是他的这个代码工程质量其实是很一般的,比较适用于这些学术界的研究,其实工业界的使用并不是特别友好。

另外一个是 SPTAG,这个算法,是微软的开源向量检索库,它的优势其实是有一些算法的创新,它是将树算法和这个图算法进行了结合,实现了一种比较高效的一种算盘。但是它支持的 ANN 算法选择其实是比较少的,只有几种优化的算法,同时他的那个测试的这个性能,其实不如 Faiss。

另外一个是proxima,这个是阿里的达摩院提供的一个向量检索库,目前阿里集团内部的这个 向量检索实现其实都是大部分都是基于 proxima 来实现的,他的这个代码质量是很好的,同时还支持 ANN 算法选择,另外,它的性能是足够高的,经过对比实现是优于 faiss。另外,它的缺点是他并不开源,就是集团外其实用不了,

另外一个是 vearch,这个是京东的开源向量检索库,好处是它是完整的一个检索引擎,是一个分布式的一个服务,是一整套的一个服务实现,但是,他的其他的搜索能力其实是比较弱,他的分布式能力是比较弱的,这个是现有的一些开源的典型的这个 ANN 算法库的这个列表。

 image.png

3.PG 自定义索引方法介绍

有了这些 ANN 算法和一些实现的库之后,要考虑如何来实现一个向量检索引擎,当时我们在做在做这些业务的时候,也做了进行了一般的这个基础选型。根据这个技术选型的经验,可以去评估自己的场景是否适用,是否和我们相匹配一下,我们的这个技术选型,我们的候选集合,选择的是很多的,大概可以分为这样几类:

比如第一类,是搜索引擎类的,开源的引擎和我们内部的资源做引擎,然后有这个数据分析的库,比如 AnalyticDB,另外一个是 explorer,另外一个大类,是数据库类的,比如 OceanBase 和 mysql,我们的业务场景,是需要我们有轻量级的这种要求,精简之后剩下的其实并不多的,只有 Elasticsearch、mysql、PostgreSql 这三款引擎,经过这个扩展能力的考核之后,其实剩下的只有 PostgreSql 这样一个数据库,mysql其实它的索引扩展能力没有这么丰富。另外 Elasticsearch 它的扩展对索引层面是复杂的,

总结一下 PostgreSql 的优势,首先它是轻量级,第二个是它的性能比较优越,然后它的作战能力比较强大,稳定性就足够高,同时,它的生态是很丰富的,有很多的这个开源的这献在里面。然后采用一些业务的使用者,并不需要数据的迁移,很多的业务数据都存在数据库中的,PostgreSql 是一个选择,在 PostgreSql 上直接实现检索的这样一个功能,就不需要实现这个数据的迁移,这是很重要的一点。另外是支持组合查询的,我们可以结合其他的这个条件查询来进行这个组合查询。同时PostgreSql 还支持这个分布式的这种部署,通过一些第三方插件的这个支持来实现这个分布式的部署。经过这些考量,最终选择 PostgreSql 做为我们将检索引擎的这样一个技术引擎。

 image.png

确定了选用的 PostgreSql 作为引擎之后,对这个向量检索算法,对已有的向量检索插件进行一番调研,经过总结之后,主要的插件是三个,第一个是开源的,因为是imdsmlr 这样一个插件去实现,它是基于 PostgreSql 的内置的 Gist 来实现的,它的特点是提供了图像特征的处理方法,但是他的限制也是很明显的,它只能用于这个16维向量检索场景,它并不能适用于大规模的工业应用。

第二个 cube 索 引,是 PostgreSql 自带的一个索引类型,也是基于 Gist 索引来出现的。它的特点就是支持向量的聚类、向量的距离计算等等,他的维度有一定提升和支持100维度一下,但是经过我们实测,性能并不能达到要求,同时,其实100维度对于未来深度学习越来越广泛之后,这个维度是捉襟见肘的。

最后一个是 freedy,它是一个爱好者开源的一个向量检索的插件库,实现是基于 SQL function 这个方式来实现,它的优点是支持比较多的这个 ANN 算法,但是它的问题,是基于 SQL function这种思考方式实现的这种性能,其实并不能达到这个工业界使用的这个要求。那基于以上这些调研的情况,得出一个结论,就是如果PostgreSql 想做引擎,需要我们自研插件这样一个现状。

 image.png

有了这样一个背景和目标之后,对 PostgreSql 的这个自定义插件的能力,做了一番的考量,PostgreSql 其实本身就是非常丰富的自定义索引的这个能力,总结了这样两个基础。第一个基础,是 PostgreSql 的基本的这个存储单元配置结构,它是完全可以自定义的,这张图就是配置基表的这个页面的结构,看一下它的组成部分,

首先大概分为三个组成部分,第一部分是 PageHeaderDats 部分,最后结尾是special space 部分,中间这个部分,Tuple 是记录的存储部分,多个 Tuple 就存储在一个页面内,同时在页面这个配置的起始部分,会有像这些记录的指针,通过指针来进行这个寻址。这个配置的默认结构是存储8K,当记录数小于8K的时候,就可以推出多个记录在一张 Page 中。

那对于索引所采用的这个配置结构和这个结构是完全一样的,区别在于中间的一部分是不限制的,这个是可以完全自由使用的空间,总结为右边这张图,可以从图中可以看到,DataTupleN 是最小的数据存储单元的,存储结构完全可以自定义,这个时候 PostgreSql 的提供自定义索引的这样一个基础,

 image.png

第二个基础主要就是 PostgreSql 这个支持了非常丰富的索引定义的这个接口 API。整个这个 PostgreSql 的结构可以分为这样几个层次,最下面一层是数据的存储,在往上一层是索引的存储,在往上一层,是索引的接口层,再往上通过一个结构体来控制这个索引的 API 调用。

 image.png

如下图是 PG 索引 API 的定义,这个定义中可以看到它支持非常丰富的索引操作的接口,比如索引的 build 和单个 insert,以及标记删除,还有查询初始化,返回以及它的查询相关的这个接口。你可以看到它的索引接口还是非常丰富。

image.png

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
向量 (高维思考)
向量 (高维思考)
245 0
|
搜索推荐
|
存储 编译器 C++
C++学习笔记(十四)——vector的模拟实现(二)
C++学习笔记(十四)——vector的模拟实现
C++学习笔记(十四)——vector的模拟实现(二)
|
存储 编译器 C++
C++学习笔记(十四)——vector的模拟实现(一)
C++学习笔记(十四)——vector的模拟实现
C++学习笔记(十四)——vector的模拟实现(一)
|
算法 C++
C++学习笔记(十五)——vector练习题
C++学习笔记(十五)——vector练习题
C++学习笔记(十五)——vector练习题
|
存储 算法 C++
C++学习笔记(十三)——vector
C++学习笔记(十三)——vector
C++学习笔记(十三)——vector
|
自然语言处理 程序员 容器
向量学习之高维思考
向量学习之高维思考
|
C++ 容器
C++学习笔记_15 线性容器-vector容器 2021-05-12
C++学习笔记_15 线性容器-vector容器 2021-05-12
138 0
向量带来的高维思维
学习向量对于我们来说是突然的,感觉我一直在经历“降维打击”,经过十几节课的系统学习,向量似乎在我的眼里和高中时候的不太一样了。为什么这么说呢?在以前的认知里,向量就是简单的“有大小、有方向的量”,
|
编译器 C++ 索引
C++菜鸟学习笔记系列(8)——标准库类型vector
C++菜鸟学习笔记系列(8)——标准库类型vector
356 0
C++菜鸟学习笔记系列(8)——标准库类型vector

热门文章

最新文章