Elasticsearch:调整近似 kNN 搜索

在我之前的文章 “Elasticsearch:调整搜索速度”,我详细地描述了如何调整正常的 BM25 的搜索速度。在今天的文章里,我们来进一步探讨如何提高近似 kNN 的搜索速度。希望对广大的向量搜索开发者有一些启示。

Elasticsearch 支持近似 k 最近邻搜索,以有效查找与查询向量最接近的 k 个向量。 由于近似 kNN 搜索的工作方式与其他查询不同,因此对其性能有特殊的考虑。其中许多建议有助于提高搜索速度。 使用近似 kNN,索引算法在底层运行搜索以创建向量索引结构。 因此,这些相同的建议也有助于提高索引速度。

减少向量内存占用

默认的 element_type是 float。 但这可以通过 quantization 在索引时间时自动进行标量量化。具体的介绍可以详细阅读文章 “Elasticsearch:dense vector 数据类型及标量量化”。 量化会将所需的内存减少 4 倍,但也会降低向量的精度并增加该字段的磁盘使用量(最多增加 25%)。 磁盘使用量增加是 Elasticsearch 存储量化向量和未量化向量的结果。 例如,当量化 40GB 浮点向量时,将为量化向量存储额外的 10GB 数据。 总磁盘使用量为50GB,但快速搜索的内存使用量将减少到10GB。

对于 dim 大于或等于 384 的浮点向量,强烈建议使用量化索引。

降低向量维数

kNN 搜索的速度与向量维数成线性关系,因为每个相似度计算都会考虑两个向量中的每个元素。 只要有可能,最好使用维度较低的向量。 一些嵌入模型有不同的维度大小,有更低和更高维度的选项。 你还可以尝试使用 PCA 等降维技术。 在尝试不同的方法时,衡量对相关性的影响非常重要,以确保搜索质量仍然可以接受。

从 _source 中排除向量字段

Elasticsearch 将在索引时传递的原始 JSON 文档存储在 _source 字段中。 默认情况下,搜索结果中的每个命中都包含完整文档 _source。 当文档包含 dense_vector 字段时,_source 可能非常大且加载成本昂贵。 这可能会显着降低 kNN 搜索的速度。

你可以通过 excludes 映射参数禁用在 _source 中存储 dense_vector 字段。 这可以防止在搜索期间加载和返回大向量,并且还可以减少索引大小。 _source 中省略的向量仍然可以在 kNN 搜索中使用,因为它依赖于单独的数据结构来执行搜索。 在使用 excludes 参数之前,请确保查看从 _source 中省略字段的缺点。

另一种选择是使用 synthetic_source(如果所有索引字段都支持)。

确保数据节点有足够的内存

Elasticsearch 使用 HNSW 算法进行近似 kNN 搜索。 HNSW 是一种基于图的算法,只有当大多数向量数据保存在内存中时才能有效地工作。 你应该确保数据节点至少有足够的 RAM 来保存向量数据和索引结构。 要检查向量数据的大小,你可以使用分析索引磁盘使用情况 API。 作为一个宽松的经验法则,并假设默认的 HNSW 选项,使用的字节将为 num_vectors * 4 * (num_dimensions + 12)。 当使用字节 element_type 时,所需的空间将更接近 num_vectors * (num_dimensions + 12)。 请注意,所需的 RAM 用于文件系统缓存,它与 Java 堆分开。

数据节点还应该为其他需要 RAM 的方式留下缓冲区。 例如,你的索引可能还包括文本字段和数字,这也受益于使用文件系统缓存。 建议使用你的特定数据集运行基准测试,以确保有足够的内存来提供良好的搜索性能。 你可以在这里和这里找到我们用于夜间基准测试的一些数据集和配置示例。

预热文件系统缓存

如果运行 Elasticsearch 的机器重新启动,文件系统缓存将为空,因此操作系统需要一些时间才能将索引的热区域加载到内存中,以便搜索操作快速。 你可以使用 index.store.preload 设置显式告诉操作系统哪些文件应根据文件扩展名立即加载到内存中。

警告:如果文件系统缓存不够大,无法容纳所有数据,则在太多索引或太多文件上急切地将数据加载到文件系统缓存中将使搜索速度变慢。 谨慎使用。

以下文件扩展名用于近似 kNN 搜索:

  • 向量值的 vec 和 veq
  • HNSW 图的 vex
  • 用于元数据的 vem、vemf 和 vemq

减少索引段的数量

Elasticsearch 分片由段(segment)组成,段是索引中的内部存储元素。 对于近似 kNN 搜索,Elasticsearch 将每个段的向量值存储为单独的 HNSW 图,因此 kNN 搜索必须检查每个段。 最近的 kNN 搜索并行化使得跨多个片段的搜索速度大大加快,但如果片段较少,kNN 搜索的速度仍然可以提高数倍。 默认情况下,Elasticsearch 通过后台合并过程定期将较小的段合并为较大的段。 如果这还不够,你可以采取明确的步骤来减少索引段的数量。

Lucene 合并,同时索引所有维基百科(英文)

强制合并到一个段

Force merge 操作强制进行索引合并。 如果强制合并到一个段,kNN 搜索只需要检查一个包含所有内容的 HNSW 图。 强制合并 dense_vector 字段是一项昂贵的操作,可能需要大量时间才能完成。

警告我们建议仅强制合并只读索引(意味着索引不再接收写入)。 当文档被更新或删除时,旧版本不会立即删除,而是软删除并标记为 “墓碑”。 这些软删除文档会在定期段合并期间自动清除。 但强制合并可能会导致生成非常大(> 5GB)的段,这些段不符合常规合并的条件。 因此,软删除文档的数量会迅速增长,从而导致更高的磁盘使用率和更差的搜索性能。 如果你定期强制合并接收写入的索引,这也会使快照更加昂贵,因为新文档无法增量备份。

在批量索引期间创建大段

常见的模式是首先执行初始批量上传,然后使索引可用于搜索。 你可以调整索引设置以鼓励 Elasticsearch 创建更大的初始段,而不是强制合并:

  • 确保批量上传期间没有搜索,并通过将其设置为 -1 来禁用 index.refresh_interval。 这可以防止刷新操作并避免创建额外的段。
  • 为 Elasticsearch 提供一个较大的索引缓冲区,以便它可以在刷新之前接受更多文档。 默认情况下,indices.memory.index_buffer_size 设置为堆大小的 10%。 对于像 32GB 这样的大堆大小,这通常就足够了。 为了允许使用完整的索引缓冲区,你还应该增加限制 index.translog.flush_threshold_size。

避免在搜索过程中建立大量索引

积极地索引文档可能会对近似 kNN 搜索性能产生负面影响,因为索引线程会窃取搜索的计算资源。 当同时索引和搜索时,Elasticsearch 也会频繁刷新,这会创建几个小段。 这也会损害搜索性能,因为当分段较多时,近似 kNN 搜索速度会变慢。

如果可能,最好在近似 kNN 搜索期间避免大量索引。 如果你需要重新索引所有数据,可能是因为向量嵌入模型发生了变化,那么最好将新文档重新索引到单独的索引中,而不是就地更新它们。 这有助于避免上述速度减慢,并防止由于频繁的文档更新而导致昂贵的合并操作。

在 Linux 上使用适度的预读值来避免页面缓存抖动

搜索可能会导致大量随机读取 I/O。 当底层块设备具有较高的预读值时,可能会执行大量不必要的读取 I/O,特别是当使用内存映射访问文件时(请参阅存储类型)。

大多数 Linux 发行版对单个普通设备使用 128KiB 的合理预读值,但是,当使用软件 raid、LVM 或 dm-crypt 时,生成的块设备(支持 Elasticsearch path.data)最终可能会具有非常大的预读值(在 几个 MiB 的范围)。 这通常会导致严重的页面(文件系统)缓存抖动,从而对搜索(或更新)性能产生不利影响。

你可以使用 lsblk -o NAME,RA,MOUNTPOINT,TYPE,SIZE 检查当前值(以 KiB 为单位)。 有关如何更改此值的信息,请参阅发行版的文档(例如,使用 udev 规则在重新启动后保持不变,或通过 blockdev --setra 作为瞬态设置)。 我们建议预读值为 128KiB。

在 Linux 上使用适度的预读值 (readahead) 来避免页面缓存抖动

搜索可能会导致大量随机读取 I/O。 当底层块设备具有较高的预读值时,可能会执行大量不必要的读取 I/O,特别是当使用内存映射访问文件时(请参阅存储类型)。

大多数 Linux 发行版对单个普通设备使用 128KiB 的合理预读值,但是,当使用软件 raid、LVM 或 dm-crypt 时,生成的块设备(支持 Elasticsearch path.data)最终可能会具有非常大的预读值(在 几个 MiB 的范围)。 这通常会导致严重的页面(文件系统)缓存抖动,从而对搜索(或更新)性能产生不利影响。

你可以使用 lsblk -o NAME,RA,MOUNTPOINT,TYPE,SIZE 检查当前值(以 KiB 为单位)。 有关如何更改此值的信息,请参阅发行版的文档(例如,使用 udev 规则在重新启动后保持不变,或通过 blockdev --setra 作为瞬态设置)。 我们建议预读值为 128KiB。

警告:blockdev 期望值以 512 字节扇区为单位,而 lsblk 报告值以 KiB 为单位。 例如,要将 /dev/nvme0n1 的预读临时设置为 128KiB,请指定 blockdev --setra 256 /dev/nvme0n1。

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

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

相关文章

一、yocto 编译raspberrypi 4B并启动

yocto 编译raspberrypi 4B并启动 yocto 编译raspberrypi 4B并启动环境准备代码下载编译及配置烧录 yocto 编译raspberrypi 4B并启动 本篇文章为基于raspberrypi 4B单板的yocto实战系列的开篇之作。 环境准备 最近到手一个树莓派4B,准备拿来玩一玩,下面…

Docker部署Django项目——基础

1.服务器配置 1.1centos7 系统的安装 centos-7-isos-x86_64安装包下载) VMware安装自定义配置 选择对应的系统镜像 一般选择内核4核、内存8g、硬盘80g 相关配置 1.2.网络配置 1.2.1查看win电脑虚拟机VMnet8的ip 使用ipconfig查看虚拟机的ip 1.2.2配置虚拟机VMnet8的ip…

152.乐理基础-广义的、实际的原位与转位、转位的意义

内容参考于:三分钟音乐社 上一个内容:151.和弦固定标记法(二)转位和弦,斜杠(slash)和弦 上一个内容里练习的答案:斜杠左边的有多个写法,如果与下图不一样,那…

小白向-使用git实现不同服务器改动的同步

背景 深度学习项目,已有可运行的backbone,已将此项目在github建库。 需要使用不同分支进行不同改动的测试;有两台服务器可供程序运行; 项目需求 以github云端仓库为媒介,实现不同服务器改动无痛关联。维护项目代码…

WRF模型安装教程(ububtu系统)-- III.WRF和WPS模型的安装

六、WRF模型的安装 # 进入Build_WRF文件夹 cd Build_WRF # 下载WRFV3.9.1 wget https://www2.mmm.ucar.edu/wrf/src/WRFV4.0.TAR.gz # 解压WRF安装包并进入 tar -zxvf WRFV4.0.TAR.gz cd WRF # 安装WRF ./configure 出现如下选项: 选择34, 这里是让你选…

FREERTOS任务调度和切换

我们已经学会了 FreeRTOS 的任务创建和删除,挂起和恢复等基本操作,并且也学习了分析FreeRTOS 源码所必须掌握的知识:列表和列表项。但是任务究竟如何被创建、删除、挂起和恢复的?系统是怎么启动的等等这些我们还不了解&#xff0c…

windows使用docker运行TP6使用swoole内置http服务

1,下载docker-Windows客户端 下载地址:https://www.docker.com/products/docker-desktop docker --version #查看docker版本 docker-compose --version #查看docker-compose版本 2,安装环境 使用一键安装包:https://gitee.com/yes…

汇总全网免费API,持续更新(新闻api、每日一言api、音乐。。。)

Public&FreeAPI 网址:apis.whyta.cn (推荐) UomgAPI 网址:https://api.uomg.com 教书先生 网址:https://api.oioweb.cn/ 山海API https://api.shserve.cn/ 云析API铺 https://api.a20safe.com/ 韩小韩…

深度学习pytorch——基本数据类型创建Tensor(持续更新)

声明:本深度学习笔记基于课时18 索引与切片-1_哔哩哔哩_bilibili学习而来 All is about Tensor 定义:Tensors are simply mathematical objects that can be used to describe physical properties, just like scalars and vectors. In fact tensors a…

day6 3/18

2.试编程: 封装一个动物的基类,类中有私有成员:姓名,颜色,指针成员年纪 再封装一个狗这样类,共有继承于动物类,自己拓展的私有成员有:指针成员:腿的个数(整…

JAVA实战开源项目:天然气工程业务管理系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、使用角色3.1 施工人员3.2 管理员 四、数据库设计4.1 用户表4.2 分公司表4.3 角色表4.4 数据字典表4.5 工程项目表4.6 使用材料表4.7 使用材料领用表4.8 整体E-R图 五、系统展示六、核心代码6.1 查询工程项目6.2 工程物资…

HackTheBox WifineticTwo

靶机信息系统LinuxIP/难度Medium状态Active/Reason 4地址https://app.hackthebox.com/machines/WifineticTwo 端口扫描 ┌──(st4rry🚀Kali)-[/mnt/e/htb/WifineticTwo] └─\ ✨ nmap -p22,8080 -sC -sV 10.129.41.69 -oN cv Starting Nmap 7.94 ( https://nma…

【Django开发】0到1美多商城项目md教程第2篇:展示用户注册页面,1. 创建用户模块子应用【附代码文档】

美多商城完整教程(附代码资料)主要内容讲述:欢迎来到美多商城!,项目准备。展示用户注册页面,创建用户模块子应用。用户注册业务实现,用户注册前端逻辑。图形验证码,图形验证码接口设…

【C语言进阶篇】C语言内存函数

目录 1.memcpy函数及其模拟实现 1.1 memcpy函数的使用 1.2 memcpy函数的模拟实现 2.memmove函数及其模拟实现 2.1 memmove函数的使用 2.2 memmove函数的模拟实现 3.memset函数 4.memcmp函数 1.memcpy函数及其模拟实现 1.1 memcpy函数的使用 memcpy函数是用来拷贝内存的函数&…

mysql 索引(为什么选择B+ Tree?)

索引实现原理 索引:排好序的数据结构 优点:降低I/O成本,CPU的资源消耗(数据持久化在磁盘中,每次查询都得与磁盘交互) 缺点:更新表效率变慢,(更新表数据,还要…

数据的响应式:实现动态数据驱动的技巧

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

洛谷P1100 高低位交换

#先看题目 题目描述 给出一个小于 的非负整数。这个数可以用一个 32 位的二进制数表示(不足 32 位用 0 补足)。我们称这个二进制数的前 16 位为“高位”,后 16 位为“低位”。将它的高低位交换,我们可以得到一个新的数。试问这…

​关于robotframework,app,appium的xpath定位问题及常用方法​

关于类似的帖子好像很多,但是没有找到具体能帮我解决问题的办法。还是自己深究了好久才基本知道app上面的xpath定位和web上的不同点: 先放一个图: A,先说说不用xpath的场景,一般是用于存在id或者name。可能没有看到na…

UI 学习 三 可访问性 UX

设计、交流和实现不同领域内容的易访问性决策,涉及到一系列考虑因素,以达到更容易访问的产品体验。 Material使用的框架借鉴了WCAG标准和行业最佳实践,以帮助任何人预测、计划、记录和实现可访问体验。 下面描述的三个阶段有助于将可视化UI…

Verilog——信号类型

Verilog HDL 的信号类型有很多种,主要包括两种数据类型:线网类型 (net type) 和寄存器类型 ( reg type )。在进行工程设计的过程中也只会使用到这两个类型的信号。 4.1 信号位宽 定义信号类型的同时,必须定义好信号…