Elasticsearch:Lucene 中引入标量量化

作者: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.mzph.cn/news/140192.shtml

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

相关文章

cocosCreator 之 Bundle使用

版本: v3.4.0 语言: TypeScript 环境: Mac Bundle简介 全名 Asset Bundle(简称AB包),自cocosCreator v2.4开始支持,用于作为资源模块化工具。 允许开发者根据项目需求将贴图、脚本、场景等资源划分在 Bundle 中&am…

深度学习基于python+TensorFlow+Django的花朵识别系统

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 花朵识别系统,基于Python实现,深度学习卷积神经网络,通过TensorFlow搭建卷积神经…

Essential C++ 面向对象4.1 ~ 5.4

个人认为,结合网上对《Essential c》的评论,它不适合初学者: (1)过于精炼,很多内容不会细讲 (2)中文版翻译较生硬,逻辑不够连贯清晰 (3)课后作业有…

05-Spring中Bean的生命周期

Bean的生命周期 生命周期就是对象从创建开始到最终销毁的整个过程 , Spring其实就是一个管理Bean对象的工厂,它负责对象的创建和销毁等 Bean生命周期的管理可以参考Spring的源码:AbstractAutowireCapableBeanFactory类的doCreateBean()方法 研究生命周期的意义&am…

【案例】超声波测距系统设计

1.1 总体设计 1.1.1 概述 学习了明德扬至简设计法和明德扬设计规范,本人用FPGA设计了一个测距系统。该系统采用超声波进行测量距离再在数码管上显示。在本案例的设计过程中包括了超声波的驱动、三线式数码管显示等技术。经过逐步改进、调试等一系列工作后&#xf…

Vue中的常用指令v-html / v-show / v-if / v-else / v-on / v-bind / v-for / v-model

前言 持续学习总结输出中,Vue中的常用指令v-html / v-show / v-if / v-else / v-on / v-bind / v-for / v-model 概念:指令(Directives)是Vue提供的带有 v- 前缀 的特殊标签属性。可以提高操作 DOM 的效率。 vue 中的指令按照不…

【洛谷 P5019】[NOIP2018 提高组] 铺设道路 题解(分治算法+双指针)

[NOIP2018 提高组] 铺设道路 题目背景 NOIP2018 提高组 D1T1 题目描述 春春是一名道路工程师,负责铺设一条长度为 n n n 的道路。 铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 n n n 块首尾相连的区域,一开始,第 i i i …

Jenkins简介及Docker Compose部署

Jenkins是一个开源的自动化服务器,用于自动化构建、测试和部署软件项目。它提供了丰富的插件生态系统,支持各种编程语言和工具,使得软件开发流程更加高效和可靠。在本文中,我们将介绍Jenkins的基本概念,并展示如何使用…

openssl+sha256开发实例(C++)

文章目录 一、 sha256介绍二、sha256原理三、openssl sha256实现 一、 sha256介绍 SHA-256(Secure Hash Algorithm 256-bit)是一种哈希算法,属于 SHA-2(Secure Hash Algorithm 2)家族的一员。SHA-256 产生的哈希值是一…

Redis使用Pipeline(管道)批量处理

Redis 批量处理 在开发中,有时需要对Redis 进行大批量的处理。 比如Redis批量查询多个Hash。如果是在for循环中逐个查询,那性能会很差。 这时,可以使用 Pipeline (管道)。 Pipeline (管道) Pipeline (管道) 可以一次性发送多条命令并在执…

【操作系统】考研真题攻克与重点知识点剖析 - 第 3 篇:内存管理

前言 本文基础知识部分来自于b站:分享笔记的好人儿的思维导图与王道考研课程,感谢大佬的开源精神,习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析,本人技术…

Git 服务器上的 LFS 下载

以llama为例: https://huggingface.co/meta-llama/Llama-2-7b-hf Github # 1. 安装完成后,首先先初始化;如果有反馈,一般表示初始化成功 git lfs install ​ # 2. 如果刚刚下载的那个项目没啥更改,重新下一遍&#x…

TP触摸屏调试

此处以MT6739 1g版本敦泰TP为例(kernel 4.19),主要修改点如下: 1. 两个配置文件defconfig: kernel-4.19\arch\arm\configs\k39tv1_bsp_1g_k419_debug_defconfig: kernel-4.19\arch\arm\configs\k39tv1_bsp_1g_k419_defconfig: CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCRE…

一文了解游戏行业(数据分析)

一.概况 1.基本术语 游戏行业基础术语——持续更新ing... 2.产业链 包括游戏开发,发行和销售等环节 ①游戏开发 上游环节是游戏产业链的核心环节,包括游戏策划,美术设计,程序开发等,是决定游戏质量与内容的关键因…

Leetcode刷题详解—— 有效的数独

1. 题目链接:36. 有效的数独 2. 题目描述: 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的…

sass 封装媒体查询工具

背景 以往写媒体查询可能是这样的&#xff1a; .header {display: flex;width: 100%; }media (width > 320px) and (width < 480px) {.header {height: 50px;} }media (width > 480px) and (width < 768px) {.header {height: 60px;} }media (width > 768px) …

解决ios向mac复制文字不成功的一种方法

### 环境&#xff1a; ios: 16.7.2 macos: 13.6.1 ### 问题现象&#xff1a; 从ios复制了文字&#xff0c;在mac上粘贴总是不成功&#xff0c;总是粘贴出mac上复制的内容。 ### 问题分析&#xff1a; 可能是mac复制的内容优先级比ios复制的内容优先级高&#xff0c;所以不清…

Python实战 | 使用 Python 和 TensorFlow 构建卷积神经网络(CNN)进行人脸识别

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…

链表的逆置

方法1&#xff1a; 依次将指针反向&#xff0c;最后令头指针指向尾元素。 逆置过程如下&#xff1a; 当q指针为空时&#xff0c;循环结束。 //试写一算法&#xff0c;对单链表实现就地逆置&#xff0c; void Reverse1(List plist)//太复杂,不用掌握 {assert(plist ! NULL);i…

Spark Job优化

1 Map端优化 1.1 Map端聚合 map-side预聚合&#xff0c;就是在每个节点本地对相同的key进行一次聚合操作&#xff0c;类似于MapReduce中的本地combiner。map-side预聚合之后&#xff0c;每个节点本地就只会有一条相同的key&#xff0c;因为多条相同的key都被聚合起来了。其他节…