Elasticsearch:Lucene 中引入标量量化

news2024/12/26 14:50:35

作者:BENJAMIN TRENT

我们如何将标量量化引入 Lucene。

Lucene 中的自动字节量化

虽然 HNSW 是一种强大而灵活的存储和搜索向量的方法,但它确实需要大量内存才能快速运行。 例如,查询 768 维的 1MM float32 向量大约需要 1,000,000*4*(768+12)=3120000000bytes≈3GB 的 RAM。 一旦你开始搜索大量向量,这就会变得昂贵。 减少大约 75% 内存使用的一种方法是通过字节量化。 Lucene 和 Elasticsearch 支持索引字节向量已有一段时间了,但构建这些向量一直是用户的责任。 这种情况即将改变,因为我们在 Lucene 中引入了 int8 标量量化。

标量量化 101

所有量化技术都被视为原始数据的有损变换。 这意味着由于空间原因,一些信息丢失了。 有关标量量化的深入解释,请参阅:标量量化 101。从高层次来看,标量量化是一种有损压缩技术。 一些简单的数学计算可以节省大量空间,而对召回率的影响很小。

节点、分片、段,天哪!

习惯使用 Elasticsearch 的人可能已经熟悉这些概念,但这里是搜索文档分布的快速概述。

每个 Elasticsearch 索引都由多个分片组成。 虽然每个分片只能分配给单个节点,但每个索引多个分片可以让你跨节点进行并行计算。

每个分片都由一个 Lucene 索引组成。 Lucene 索引由多个只读段组成。 在索引期间,文档被缓冲并定期刷新到只读段中。 当满足某些条件时,这些片段可以在后台合并成更大的片段。 所有这些都是可配置的,并且有其自身的复杂性。 但是,当我们谈论段和合并时,我们谈论的是只读 Lucene 段以及这些段的自动定期合并。 这里更深入地探讨了段合并和设计决策。

每段量化

Lucene 中的每个段都存储以下内容:各个向量、HNSW 图索引、量化向量和计算的分位数。 为了简洁起见,我们将重点关注 Lucene 如何存储量化向量和原始向量。 对于每个片段,我们跟踪 vec 文件中的原始向量、量化向量和 veq 中的单个校正乘数浮点数,以及 vemq 文件中有关量化的元数据。

图 1:原始向量存储文件的简化布局。 由于浮点值是 4 个字节,因此占用磁盘空间 (dimension*4*numVectors。 因为我们正在量化,所以在 HNSW 搜索期间不会加载这些。 仅在有特殊要求时才使用它们(例如通过 重新评分进行强力辅助),或用于段合并期间的重新量化。

图 2:.veq 文件的简化布局。 占用 (dimension+4)*numVectors 空间,在搜索时会被加载到内存中。 +4 字节用于考虑修正乘数浮点数,用于调整评分以获得更好的准确性和召回率。

图 3:元数据文件的简化布局。 我们在这里跟踪量化和向量配置以及该段的计算分位数。

因此,对于每个段,我们不仅存储量化向量,还存储用于生成这些量化向量和原始原始向量的分位数。 但是,为什么我们要保留原始向量呢?

与你一起成长的量化

由于 Lucene 会定期刷新只读段,因此每个段仅具有所有数据的部分视图。 这意味着计算的分位数仅直接适用于整个数据的该样本集。 现在,如果你的样本足以代表你的整个语料库,那么这并不是什么大问题。 但是 Lucene 允许你以各种方式对索引进行排序。 因此,你可以对按分位数计算增加偏差的方式排序的数据建立索引。 此外,你可以随时刷新数据! 你的样本集可能很小,甚至只有一个向量。 另一个难题是你可以控制何时发生合并。 虽然 Elasticsearch 已配置默认值和定期合并,但你可以随时通过 _force_merge API 请求合并。 那么,我们如何仍然允许所有这些灵活性,同时提供良好的量化以提供良好的召回率?

Lucene 的向量量化会随着时间的推移自动调整。 由于 Lucene 采用只读段架构设计,因此我们可以保证每个段中的数据没有更改,并在代码中明确划分何时可以更新。 这意味着在分段合并期间,我们可以根据需要调整分位数,并可能重新量化向量。

图 4:具有不同分位数的三个示例片段。

但重新量化不是很昂贵吗? 它确实有一些开销,但 Lucene 会智能地处理分位数,并且仅在必要时才完全重新量化。 我们以图 4 中的段为例。 让我们为段 A 和 B 各提供 1,000 个文档,而段 C 仅提供 100 个文档。 Lucene 将对分位数进行加权平均,如果生成的合并分位数足够接近片段的原始分位数,我们就不必重新量化该片段,并将利用新合并的分位数。

图 5:合并分位数示例,其中段 A 和 B 有 1000 个文档,而 C 只有 100 个文档。

在图 5 中可视化的情况中,我们可以看到生成的合并分位数与 A 和 B 中的原始分位数非常相似。因此,它们没有必要进行重新量化向量。 C段,好像偏差太大了。 因此,C 中的向量将使用新合并的分位数值重新量化。

确实存在合并分位数与任何原始分位数显着不同的极端情况。 在这种情况下,我们将从每个分段中抽取样本并完全重新计算分位数。

性能与数字

那么,它的速度快吗,并且还能提供良好的召回率吗? 以下数据是在 c3-standard-8 GCP 实例上运行实验时收集到的。 为了确保与 float32 进行公平比较,我们使用了一个足够大的实例来在内存中保存原始向量。 我们使用最大内积(maximum-inner-product)索引了 400,000个 Cohere Wiki 向量。

图 6:量化向量与原始向量的 Recall@10。 量化向量的搜索性能明显快于原始向量,并且只需多收集 5 个向量即可快速恢复召回率; 由 quantized@15 可见

图 6 显示了这个故事。 尽管存在召回率差异,但正如预期的那样,差异并不显着。 而且,仅再收集 5 个向量,召回率差异就消失了。 所有这一切都通过 2 倍更快的段合并和 float32 向量的 1/4 内存实现。

结论

Lucene 为难题提供了独特的解决方案。 量化不需要 “训练” 或 “优化” 步骤。 在 Lucene 中,它会正常工作。 如果数据发生变化,无需担心必须 “重新训练” 向量索引。 Lucene 将检测重大变化,并在数据的生命周期内自动处理这些变化。 期待我们将此功能引入 Elasticsearch!

原文:Introducing Scalar Quantization in Lucene — Elastic Search Labs

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

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

相关文章

Spring Boot 集成 ElasticSearch

1 加入依赖 首先创建一个项目&#xff0c;在项目中加入 ES 相关依赖&#xff0c;具体依赖如下所示&#xff1a; <dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.1.0</version&g…

「算法小记」-2:矩阵链相乘的方案数【迭代/递归/动态规划/区域化DP/记忆化搜索】(C++ )

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…

PHP 使用递归方式 将其二维数组整合为层级树 其中层级id 为一个uuid的格式 造成的诡异问题 已解决

不啰嗦 直接上源代码 <?php function findChildren($list, $p_id){$r array();foreach ($list as $k > $item) {if ($item[fid] $p_id) {unset($list[$k]);$length count($r);$r[$length] $item;if ($t findChildren($list, $item[id])) {$r[$length][children] …

Godot Shader -变量的声明

变量的声明 uniform 可以将值传递给着色器。这些值对整个着色器来说是全局的&#xff0c;被称为 uniform。当一个着色器后来被分配给一个材质时&#xff0c;uniform 将作为可编辑的参数出现在其中。uniform 不能从着色器内部写入。 可以在材质编辑器的修改这些uniform的值&a…

万宾科技内涝积水监测仪使用效果一览

当一个城市突降暴雨&#xff0c;对城市管理部门来讲首当其中的是防止积水成患。随着城市人口快速增长&#xff0c;基础设施建设也日益受到更多的关注&#xff0c;城市内涝问题频繁增加&#xff0c;会给城市带来严重的经济损失和人员的安全问题。城市生命线工程建设过程中&#…

黑客(网络安全)技术——高效自学1.0

前言 前几天发布了一篇 网络安全&#xff08;黑客&#xff09;自学 没想到收到了许多人的私信想要学习网安黑客技术&#xff01;却不知道从哪里开始学起&#xff01;怎么学 今天给大家分享一下&#xff0c;很多人上来就说想学习黑客&#xff0c;但是连方向都没搞清楚就开始学习…

屏幕提词软件Presentation Prompter mac中文版使用方法

Presentation Prompter for mac是一款屏幕提词器软件&#xff0c;它可以将您的Mac电脑快速变成提词器&#xff0c;支持编写或导入&#xff0c;可以在一个或多个屏幕上平滑地滚动&#xff0c;Presentation Prompter 下载是为适用于现场表演者&#xff0c;新闻广播员&#xff0c;…

Ps:选区的基本操作

在 Photoshop 中&#xff0c;选区是为处理局部图像而自行定义的一个区域。 定义选区后&#xff0c;操作被限制在选区之内。选区周围显示的虚线边框&#xff0c;俗称“蚂蚁线”。 全选 Select All Ps菜单&#xff1a;选择/全部 Select/All 快捷键&#xff1a;Ctrl A 提示&#…

JVM字符串常量池StringTable

目录 一、StringTable为什么要调整 二、String的基本特性 三、String的内存分配 四、字符串拼接操作 五、intern()方法 六、Stringtable的垃圾回收 七、G1中String去重操作 一、StringTable为什么要调整 jdk7之前&#xff0c;hotspot对于方法区的实现是永久代&#xff…

C语言之文件操作(详解版)

不知不觉我们已经学到C语言的文件操作部分了&#xff0c;这部分内容其实很有意思&#xff0c;因为它可以直接把我们代码中的数据写入硬盘&#xff0c;而不是我们关掉这个程序&#xff0c;代码就没有了&#xff0c;让我们开始学习吧&#xff01; 目录 1.为什么使用文件 2.什么…

伪造referer [极客大挑战 2019]Http1

打开题目 没有发现什么&#xff0c;我们查看源代码 在这里我们发现了提示 访问一下页面得到 提示说不能来自于https://Sycsecret.buuoj.cn&#xff0c;我们尝试访问一下这个url 发现访问不了 我们bp抓包一下 伪造个referer头 referer:https://Sycsecret.buuoj.cn 发包过去…

ChatGPT、GPT-4 Turbo接口调用

接口地址 https://chat.xutongbao.top/api/light/chat/createChatCompletion 请求方式 post 请求参数 model可选值&#xff1a; “gpt-3.5-turbo-1106”、 “gpt-3.5-turbo-16k” 、 “gpt-4”、“gpt-4-1106-preview”。 默认值为&#xff1a; “gpt-3.5-turbo-1106” to…

Delphi TCP服务端监听端口获取客户端RFID网络读卡器上传的刷卡数据

本示例使用设备介绍&#xff1a;液显WIFI无线网络HTTP协议RFID云读卡器可编程实时可控开关TTS语-淘宝网 (taobao.com) unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, ComCtrls, ScktComp, StdCtrls, ScktCom…

JVM源码剖析之软、弱、虚引用的处理细节

目录 写在前面&#xff1a; 源码剖析&#xff1a; Java层面&#xff1a; JVM层面&#xff1a; 使用危险点&#xff1a; 总结&#xff1a; 版本信息&#xff1a; jdk版本&#xff1a;jdk8u40 垃圾回收器&#xff1a;Serial new/old 写在前面&#xff1a; 不同的垃圾回收…

PROFINET和UDP、MODBUS-RTU通信速度对比实验

这篇博客我们介绍PROFINET 和MODBUS-RTU通信实验时的数据刷新速度,以及这种速度不同对控制系统带来的挑战都有哪些,在介绍这篇对比实验之前大家可以参考下面的文章链接: S7-1200PLC和SMART PLC的PN智能从站通信 S7-200 SMART 和 S7-1200PLC进行PROFINET IO通信-CSDN博客文…

远程电脑未连接显示器时分辨率太小的问题处理

背景&#xff1a;单位电脑显示器坏了&#xff0c;使用笔记本通过向日葵远程连接&#xff0c;发现分辨率只有800*600并且不能修改&#xff0c;网上找了好久找到了处理方法这里记录一下&#xff0c;主要用到的是一个虚拟显示器软件usbmmidd_v2 1)下载usbmmidd_v2 2&#xff09;…

Flink SQL自定义表值函数(Table Function)

使用场景&#xff1a; 表值函数即 UDTF&#xff0c;⽤于进⼀条数据&#xff0c;出多条数据的场景。 开发流程&#xff1a; 实现 org.apache.flink.table.functions.TableFunction 接⼝实现⼀个或者多个⾃定义的 eval 函数&#xff0c;名称必须叫做 eval&#xff0c;eval ⽅法…

什么是进程等待?

什么是进程等待 在了解进程等待之前&#xff0c;我们要回顾一下什么是僵尸进程&#xff1a;是指一个已经终止执行的进程&#xff0c;但其父进程还没有通过 wait() 系统调用来获取该进程的退出状态信息。当一个进程正常退出或者被终止时&#xff0c;其所占用的系统资源会被操作…

基于SSM的智能物业管理网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

rabbitMq虚拟主机概念

虚拟主机是RabbitMQ中的一种逻辑隔离机制&#xff0c;用于将消息队列、交换机以及其他相关资源进行隔离。 在RabbitMQ中&#xff0c;交换机&#xff08;Exchange&#xff09;用于接收生产者发送的消息&#xff0c;并根据特定的路由规则将消息分发到相应的队列中。而虚拟主机则…