Elasticsearch:使用硬件加速的 SIMD 指令实现超快 BBQ

作者:来自 Elastic Chris Hegarty

我们如何使用硬件加速 SIMD(Single Instruction Multiple Data - 单指令多数据)指令优化 BBQ 中的向量比较。

随着我们继续致力于让 Elasticsearch 和 Apache Lucene 成为存储和搜索向量数据的最佳场所,我们在 BBQ(Better Binary Quantization - 更好的二进制量化)中引入了一种新方法。BBQ 是一个巨大的进步,通过压缩存储的向量带来了显著的(32 倍)效率,同时保持了高排名质量,并同时提供了超快的性能。你可以在 BBQ 博客中阅读有关 BBQ 如何将 float32 量化为单个位向量进行存储、在索引速度(量化时间减少 20-30 倍)和查询速度(查询速度提高 2-5 倍)方面优于乘积量化(Product Quantization)等传统方法的信息,并查看 BBQ 对各种数据集实现的出色准确率和召回率。

由于 BBQ 博客中已经介绍了高级性能,因此我们将在此更深入地了解 BBQ 如何实现如此出色的性能。特别是,我们将研究如何通过硬件加速的 SIMD(单指令多数据)指令优化向量比较。这些 SIMD 指令执行数据级并行,因此一条指令一次可对多个向量组件进行操作。我们将看到 Elasticsearch 和 Lucene 如何针对特定的低级 SIMD 指令(如 x64 上的 AVX 的 VPOPCNTQ 和 ARM 上的 NEON 的向量指令)来加速向量比较。

为什么我们如此关心向量比较?

向量比较决定了向量数据库中的执行时间,通常是成本最高的因素。我们在配置文件跟踪中看到了这一点,无论是使用 float32、int8、int4 还是其他量化级别。这并不奇怪,因为向量数据库必须大量比较向量!无论是在索引过程中,例如构建 HNSW 图,还是在搜索过程中,因为图或分区被导航以找到最近的邻居。向量比较中的低级性能改进对整体高级性能确实有影响。

Elasticsearch 和 Lucene 支持许多向量相似性指标,如点积(dot product)、余弦(cosine)和欧几里得(Euclidean),但是我们将只关注点积,因为其他指标可以从他的值里面得出。尽管我们有能力在 Elasticsearch 中编写自定义的本机(原生)向量比较器,但我们倾向于尽可能留在 Java 领域,以便 Lucene 也能更轻松地获得好处。

比较查询和存储向量

为了使我们的距离比较函数运行速度更快,我们需要尽可能简化它的工作,以便将其转换为一组在 CPU 上高效执行的 SIMD 指令。由于我们已经将向量量化为整数值,因此我们可以将更多组件加载到单个寄存器中,同时避免更昂贵的浮点运算 - 这是一个好的开始,但我们需要更多。

BBQ 进行非对称量化;查询向量(query vector)被量化为 int4,而存储向量被高度压缩为单个位值。由于点积是组件值乘积的总和,我们可以立即看到,唯一可以对结果产生积极影响的查询组件值是存储向量为 1 的值。

进一步的观察是,如果我们以将每个组件值的各个位置位(1、2、3、4)组合在一起的方式转换查询向量,那么我们的点积就会简化为一组基本的按位运算;对每个组件进行 AND + 位数运算,然后进行移位以表示查询部分的相应位置,最后进行求和以得到最终结果。有关更详细的解释,请参阅 BBQ 博客,但下图直观地展示了查询翻译的示例。

从逻辑上讲,点积简化为以下内容,其中 d 是存储的向量,q1、q2、q3、q4 是平移后的查询向量的相应位置部分:

(bitCount(d & q1) << 0) + (bitCount(d & q2) << 1)
+ (bitCount(d & q3) << 2) + (bitCount(d & q4) << 3)

为了执行目的,我们通过增加相应的位位置,在内存中连续布局翻译后的查询部分。因此,我们现在有了翻译后的查询向量 q[],其大小是存储向量 d[] 的四倍。

此点积的标量 Java 实现如下所示:

byte[] d = ... // stored vector bits
byte[] q = ... // query bitsfor (int i = 0; i < 4; i++) {long subRet = 0;for (int j = 0; j < d.length; j++) {subRet += Integer.bitCount(q[i*d.length + j] & d[j] & 0xFF);}ret += subRet << i;
}

虽然语义上正确,但此实现效率不高。让我们继续看看更优化的实现是什么样子,然后我们可以比较每个实现的运行时性能。

性能从何而来?

到目前为止,我们看到的实现是一种简单的标量实现。为了加快速度,我们使用 Panama Vector API 重写了点积,以便明确针对特定的 SIMD 指令。

以下是仅针对查询部分之一的代码的简化片段 - 请记住,我们需要执行四次,每个翻译的 int4 查询部分执行一次。

var sum = LongVector.zero(LongVector.SPECIES_256);
for (int i=0; i < BYTE_SPECIES_256.loopBound(d.length); i += BYTE_SPECIES_256.length()) {var vq = ByteVector.fromArray(BYTE_SPECIES_256, q, i).reinterpretAsLongs();var vd = ByteVector.fromArray(BYTE_SPECIES_256, d, i).reinterpretAsLongs();sum = sum.add(vq.and(vd).lanewise(VectorOperators.BIT_COUNT));
}
long subRet = sum.reduceLanes(VectorOperators.ADD);
// tail processing, if any
ret += subRet << q_part // query part number

这里我们明确针对 AVX,每个循环迭代操作 256 位。首先在 vq 和 vd 之间执行逻辑与,然后对其结果进行位计数,最后将其添加到总和累加器。虽然我们对位数感兴趣,但我们确实将向量中的字节解释为长整型,因为这简化了加法并确保我们不会冒累加器溢出的风险。然后需要最后一步,将累加器向量的通道水平减少为标量结果,然后再按代表性查询部件号进行移位。

在我的 Intel Skylake 上拆解它,我们可以清楚地看到循环的主体。

0x00007cf9bcd57430:   movsxd r14,ecx
0x00007cf9bcd57433:   vmovdqu ymm4,YMMWORD PTR [rsi+r14*1+0x10]
0x00007cf9bcd5743a:   vmovdqu ymm5,YMMWORD PTR [rdx+r14*1+0x10]
0x00007cf9bcd57441:   vpand  ymm4,ymm4,ymm5
0x00007cf9bcd57445:   vpopcntq ymm4,ymm4
0x00007cf9bcd5744b:   vpaddq ymm3,ymm3,ymm4
0x00007cf9bcd5744f:   add    ecx,0x20
0x00007cf9bcd57452:   cmp    ecx,edi
0x00007cf9bcd57454:   jl     0x00007cf9bcd57430

rsirdx 寄存器保存待比较向量的地址,从中分别将下一个 256 位加载到 ymm4ymm5 寄存器中。加载完值后,我们执行按位逻辑与操作(vpand),将结果存储在 ymm4 中。接下来执行的是 vpopcntq 指令,该指令统计设置为 1 的位数。最后,我们将 0x20(32 字节 = 256 位)加到循环计数器中并继续执行。

为了简化,这里没有展示实际操作,但我们实际上展开了 4 个查询部分,并在每次循环迭代中同时执行它们,从而减少了数据向量的加载量。此外,我们为每个部分使用独立的累加器,最后再进行汇总。

当向量维度不足以每次处理 256 位时,采用 128 位的变体;在 ARM 平台上,这些操作会编译成一系列 Neon 向量指令,包括 ANDCNTUADDLP。当然,对于未对齐的数据部分,我们会以标量方式处理。不过,鉴于大多数流行模型的维度大小,这种情况在实际中并不常见。我们还在继续进行 AVX-512 实验,但到目前为止,由于常见的维度大小限制,按 512 位步进处理此数据布局并未显示出明显优势。

SIMD 能改善多少?

当我们比较标量和向量化点积实现时,我们分别看到从 384 到 1536 的一系列流行维度的吞吐量提高了 8 倍到 30 倍。

通过优化点积,我们大大提高了整体性能,使得向量比较不再是使用 BBQ 搜索和索引时最主要的因素。对于感兴趣的人,这里有一些基准和代码的链接。

总结

BBQ 是一种新技术,它带来了令人难以置信的效率和出色的性能。在这篇博客中,我们研究了如何通过硬件加速的 SIMD 指令在 BBQ 中优化向量距离比较。你可以在 BBQ 博客中阅读有关索引和搜索性能以及准确度和召回率的更多信息。BBQ 现已作为技术预览版在 Elasticsearch 8.16 和 Serverless 中发布!

除了 BBQ 等新技术外,我们还在不断改进向量数据库的低级性能。你可以在其他博客中阅读有关我们已经完成的工作的更多信息:FMA、FFM 和 SIMD。此外,随着我​​们不断提高 Elasticsearch 的性能,使其成为存储和搜索向量数据的最佳场所,未来还会看到更多像这样的以低级性能为重点的博客。

Elasticsearch 包含许多新功能,可帮助你为你的用例构建最佳搜索解决方案。深入了解我们的示例笔记本以了解更多信息,开始免费云试用,或立即在你的本地机器上试用 Elastic。

原文:Smokin' fast BBQ with hardware accelerated SIMD instructions - Search Labs

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

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

相关文章

青龙面板添加任务执行自己的脚本文件(非订阅) 保姆级图文

目录 效果预览脚本存放的位置创建任务cron规则字段含义&#xff1a;常见的特殊字符&#xff1a; 可能你的脚本需要安装依赖总结 欢迎关注 『青龙面板』 专栏&#xff0c;持续更新中 欢迎关注 『青龙面板』 专栏&#xff0c;持续更新中 效果预览 你的python脚本 print(123)运行…

flink的安装配置(详细版本)

Standalone集群模式安装部署 conda deactivate 退出 base环境 Flink支持多种安装模式。 local&#xff08;本地&#xff09;——本地模式 standalone——独立模式&#xff0c;Flink自带集群&#xff0c;开发测试环境使用 standaloneHA—独立集群高可用模式&#xff0c;Fli…

Scala编程基础:模式匹配、解构赋值与正则表达式

在Scala编程语言中&#xff0c;模式匹配、解构赋值和正则表达式是三个非常强大的特性&#xff0c;它们可以让我们以更简洁、更直观的方式处理数据。本文将通过三个示例&#xff0c;详细解释这些特性的使用方法和背后的原理。 1. 模式匹配与case class 模式匹配是Scala中处理数…

Linux Cgroup学习笔记

文章目录 Cgroup(Control Group)引言简介Cgroup v1通用接口文件blkio子系统cpu子系统cpuacct子系统cpuset子系统devices子系统freezer子系统hugetlb子系统memory子系统net_cls子系统net_prio子系统perf_event子系统pids子系统misc子系统 Cgroup V2基础操作组织进程和线程popula…

JVM, JRE 和 JDK

JRE: Java Runtime Environment, Java 运行环境. JDK: Java Development Kit, Java 开发工具包. JRE JVM 核心类库 运行工具 JDK JVM 核心类库 开发工具 JVM: Java Virtual Machine, Java 虚拟机. 核心类库: Java 已经写好的东西, 直接拿来用即可. 开发工具: 包括 …

一次完整的HTTP请求所经历几个步骤?

1. 用户输入 URL 或触发请求 当你在浏览器中输入一个 URL 或在应用程序中触发某个请求时&#xff0c;首先需要解析这个 URL&#xff0c;识别出协议、域名、路径等信息。 2. DNS 解析 计算机需要通过 域名系统&#xff08;DNS&#xff09; 将 URL 中的域名转换为 IP 地址。比…

用于LiDAR测量的1.58um单芯片MOPA(一)

--翻译自M. Faugeron、M. Krakowski1等人2014年的文章 1.简介 如今&#xff0c;人们对高功率半导体器件的兴趣日益浓厚&#xff0c;这些器件主要用于遥测、激光雷达系统或自由空间通信等应用。与固态激光器相比&#xff0c;半导体器件更紧凑且功耗更低&#xff0c;这在低功率供…

前端框架的选择与反思:在简约与复杂之间寻找平衡

在当今互联网时代&#xff0c;前端开发已经成为web应用构建中不可或缺的一环。从最初的静态HTML页面&#xff0c;到如今复杂的单页应用&#xff08;SPA&#xff09;&#xff0c;前端技术的发展让我们见证了Web应用的蓬勃发展。然而&#xff0c;伴随着技术的进步&#xff0c;一个…

推荐 编译器c++

网页型 https://www.acgo.cn/playground C 在线工具 | 菜鸟工具 AcWing - 在线题库 ZJYYC在线测评系统 少儿编程竞赛在线学习 登录 - JOYSKID 余博士教编程_酷哥OJ_酷哥爱编程_酷哥创客AI编程 登录 - Luogu Spilopelia 软件型 DEV-c Dev C软件下载

吴恩达:《State of AI report》展现2024的主要趋势和突破(二)

万字长文&#xff0c;2024AI行业的科研角力 ©作者|Zhongmei 来源|神州问学 前言 吴恩达的网站在十月中旬发表了一篇名为《A Year of Contending Forces》的文章&#xff0c;该文章是围绕着一个名为《State of AI Report - 2024》的年度报告的总结和点评。该报告由Nathan…

三维地图,智慧城市,商业智能BI,数据可视化大屏(Cesiumjs/UE)

绘图工具 三维地图&#xff1a;Cesiumjs 建模方式&#xff1a;激光点云建模、航拍倾斜摄影建模、GIS建模、BIM建模、手工建模 建模工具&#xff1a;C4D Blender GeoBuilding ArcGIS Cesiumjs <!DOCTYPE html> <html lang"en"> <head><meta …

【k8s 深入学习之 event 聚合】event count累记聚合(采用 Patch),Message 聚合形成聚合 event(采用Create)

参考 15.深入k8s:Event事件处理及其源码分析 - luozhiyun - 博客园event 模块总览 EventRecorder:是事件生成者,k8s组件通过调用它的方法来生成事件;EventBroadcaster:事件广播器,负责消费EventRecorder产生的事件,然后分发给broadcasterWatcher;broadcasterWatcher:用…

40分钟学 Go 语言高并发:分布式锁实现

分布式锁实现 一、概述 分布式锁是分布式系统中的一个重要组件&#xff0c;用于协调分布式环境下的资源访问和并发控制。我们将从锁设计、死锁预防、性能优化和容错处理四个维度深入学习。 学习目标 维度重点内容掌握程度锁设计基于Redis/etcd的锁实现原理必须掌握死锁预防…

今日分享开源酷炫大数据可视化大屏html模板

前言 虽然目前已有很多开源在线制作可视化大屏项目 但有时候为了项目赶工期上线&#xff0c;直接利用现成的可视化大屏html模板&#xff0c;配合开源低代码平台Microi吾码的接口引擎&#xff0c;半小时以内就能做一个成品 先上图 代码也非常简单&#xff0c;利用Microi吾码接口…

白鲸开源即将在Doris Summit Asia 2024展示新议题!

一年一度的 Apache Doris 峰会再次启航&#xff0c;Doris Summit Asia 2024 现已开启报名&#xff0c;将于 2024 年 12 月 14 日在深圳正式举办。此次峰会&#xff0c;将对实时极速、存算分离、湖仓一体、半结构化数据分析、向量索引、异步物化视图等诸多特性进行全方位解读&am…

vscode插件 live-server配置https

背景&#xff1a;前端有时候需要在本地搭建https环境测试某些内容&#xff08;如https下访问http资源&#xff0c;下载&#xff09; 步骤&#xff1a; 1.vscode集成开发软件(应该所有前端开发同学都安装了&#xff0c;我用webstorm&#xff0c;vscode备用) 2.vscode安装live…

Mac环境下brew安装LNMP

安装不同版本PHP 在Mac环境下同时运行多个版本的PHP&#xff0c;同Linux环境一样&#xff0c;都是将后台运行的php-fpm设置为不同的端口号&#xff0c;下面将已php7.2 和 php7.4为例 添加 tap 目的&#xff1a;homebrew仅保留最近的php版本&#xff0c;可能没有你需要的版本…

代发考试战报:12月近几日通过,题库已经更新至12月5号

代发考试战报&#xff1a;12月近几日通过&#xff0c;题库已经更新至12月5号&#xff0c;考试大约会遇到几个新题&#xff0c;就算遇到的新题全错&#xff0c;也不影响考试通过&#xff0c;HCIA-PM 12月2号上海通过&#xff0c;售前L3 H19-435 HCSP-Storage 存储 上海通过&…

autogen 源码 (UserProxyAgent 类)

目录 1. 原始代码2. 代码测试3. 代码的运行逻辑4. UserProxyAgent 类的核心功能5. UserProxyAgent 类的使用6. 运行时流程7. 总结 1. 原始代码 import asyncio from inspect import iscoroutinefunction from typing import Awaitable, Callable, List, Optional, Sequence, U…

沪合共融 “汽”势如虹 | 昂辉科技参加合肥上海新能源汽车产业融合对接会

为积极响应制造业重点产业链高质量发展行动号召&#xff0c;促进合肥、上海两地新能源汽车产业链上下游企业融合对接、协同发展&#xff0c;共同打造长三角世界级新能源汽车产业集群&#xff0c;11月28日&#xff0c;合肥市工信局组织部分县区工信部门及全市30余户新能源汽车产…