Elasticsearch测试:BBQ量化让Jina v5内存占用降29倍,召回率达0.994!
突发Elasticsearch向量索引对比测试一项动手测试对Elasticsearch中的BBQ与float32向量索引进行了比较测量了五种语言下的内存占用、磁盘占用以及recall10。用户可通过Search AI的自助式动手学习亲自体验向量搜索能立即开始免费的云试用或者在本地机器上体验Elastic。BBQ量化效果显著BBQ量化将Jina embeddings v5向量在Elasticsearch中的内存占用缩小了29倍。与全精度float32基线相比Recall[10]保持在0.994。测试在包含五种语言的多语言新闻语料库上进行构建了原始float32索引和bbq_hnsw索引测量发现两种索引磁盘占用几乎相同而内存占用从12.71 MB降低到了0.44 MB。Jina v5面向量化的训练使召回率保持稳定。前提条件进行测试需满足以下条件Elasticsearch 9.x并且已提供 jina-embeddings-v5-text-small推理端点Python 3.10Elasticsearch API密钥。什么是量化嵌入是一组数字默认每个数字是float32占用4字节。量化使用更少的位数来存储每个数字以空间换取精度。经过量化的向量如同JPEG是原始向量更小、保真度更低的副本但仍能完成相同任务。什么是BBQBetter Binary QuantizationBBQ是Elasticsearch针对稠密向量提供的1位量化模式。向量的每个维度存储为一个比特加上每个向量的少量校正字节查询时会执行重新评分步骤使最终检索质量接近全精度搜索。有关每一级量化背后的数学原理可参阅相关文章。BBQ如何保持搜索准确性普通的1位量化会使搜索质量下降过多BBQ通过三种机制保持较高检索质量非对称精度存储的向量每个维度仅使用1位校正因子每个向量用少量浮点数记录舍入误差并在评分时校正距离过采样与重新评分先使用比特扫描候选结果再用更高精度对排名靠前的结果重新排序获取前10个结果时通常扫描约30个候选结果。最终得到的向量体积约缩小32倍检索质量接近全精度。Jina embeddings v5的工作原理Jina嵌入v5是支持多语言嵌入的模型采用量化感知训练适合与Elasticsearch中的BBQ搭配使用。其生成的1024维向量高于二进制量化仍能保持准确性的维度下限且模型训练使1位量化几乎不损失检索质量。它的主要特性包括一个模型支持多种任务在单个基础模型上使用小型低秩适配适配器每种任务对应一个适配器Elasticsearch会自动选择合适的适配器Matryoshka维度允许对向量进行截断减少搜索质量下降量化感知训练专门针对BBQ训练1位向量几乎不损失准确性。本文使用的jina-embeddings-v5-text-small模型可通过Elastic Inference Service使用输出1024维向量支持32k令牌上下文窗口和93种语言高于384维阈值低于该阈值时Elasticsearch将不再默认使用bbq_hnsw。设置BBQ与float32对比创建两个索引共享映射配置通过index_options.type参数告诉Elasticsearch如何存储稠密向量字段。使用Jina v5对语料库进行一次嵌入处理将相同向量分别索引到两个索引中比较磁盘占用、内存占用和召回率。可通过支持博客内容笔记本跟随操作。连接到Elasticsearch使用相关代码连接到Elasticsearchfrom elasticsearch import Elasticsearch, helperses_client Elasticsearch(ELASTICSEARCH_URL, api_keyELASTICSEARCH_API_KEY, request_timeout120)es_client.info()创建两个索引定义相关参数和函数创建索引DIMS 1024FLOAT_INDEX vectors-float32BBQ_INDEX vectors-bbqdef create_index(name, index_options):if es_client.indices.exists(indexname):es_client.indices.delete(indexname)es_client.indices.create(indexname,mappings{properties: {text: {type: text},lang: {type: keyword},embedding: {type: dense_vector,dims: DIMS,index: True,similarity: cosine,index_options: index_options,},}},)create_index(FLOAT_INDEX, {type: hnsw}) # raw float32 baselinecreate_index(BBQ_INDEX, {type: bbq_hnsw}) # 1-bit BBQ注意在生产环境中可使用semantic_text让Elasticsearch自动管理映射和推理端点。指向Jina v5推理端点直接调用模型jina-embeddings-v5-text-small将文本转换为向量代码如下INFERENCE_ID .jina-embeddings-v5-text-smalldef embed(texts, batch_size16):out []for i in range(0, len(texts), batch_size):batch texts[i : i batch_size]try:resp es_client.inference.text_embedding(inference_idINFERENCE_ID, inputbatch)except AttributeError: # older client versionsresp es_client.inference.inference(inference_idINFERENCE_ID, inputbatch)out.extend(item[embedding] for item in resp[text_embedding])return np.array(out, dtypenp.float32)embed([hello world]).shape # testing测试结果为(1, 1024)。加载多语言新闻数据集从Hotchpotch/multilingual_cc_news流式读取真实新闻文章获取五种语言约1000篇文章总计约3000个文档保留一小部分标题集合作为搜索查询。代码如下from datasets import load_datasetLANGS [en, de, ja, pt, ru]PER_LANG_DOCS 1000PER_LANG_QUERIES 20docs, queries [], []for lang in LANGS:ds load_dataset(hotchpotch/multilingual_cc_news, lang, splittrain, streamingTrue)rows [rfor r in ds.take(PER_LANG_DOCS PER_LANG_QUERIES)if r.get(maintext) and r.get(title)]for row in rows[:PER_LANG_DOCS]:text (row[title] . row[maintext]).replace(\n, ).strip()docs.append({text: text[:1000], lang: lang})for row in rows[PER_LANG_DOCS:]:queries.append({text: row[title], lang: lang}) # headlines as queriesprint(fCorpus: {len(docs)} docs | Queries: {len(queries)})结果为Corpus: 3102 docs | Queries: 18。生成嵌入并批量索引只对语料库进行一次嵌入处理将相同向量写入两个索引。代码如下doc_vectors embed([d[text] for d in docs])query_vectors embed([q[text] for q in queries])def index_docs(name):actions ({_index: name,_id: i,_source: {text: d[text],lang: d[lang],embedding: doc_vectors[i].tolist(),},}for i, d in enumerate(docs))helpers.bulk(es_client, actions, refreshTrue)for name in (FLOAT_INDEX, BBQ_INDEX):index_docs(name)es_client.indices.forcemerge(indexname, max_num_segments1)es_client.indices.refresh(indexname)执行强制合并到单个段确保存储数据稳定且具有可比性。结果磁盘占用与内存占用使用磁盘使用API报告每个索引在向量上使用的字节数代码如下def vector_disk_bytes(name):du es_client.indices.disk_usage(indexname, run_expensive_tasksTrue)field du[name][fields][embedding]knn field.get(knn_vectors)if isinstance(knn, dict):return knn[size_in_bytes]return field[knn_vectors_in_bytes]float_disk vector_disk_bytes(FLOAT_INDEX)bbq_disk vector_disk_bytes(BBQ_INDEX)N len(docs)float_mem N * DIMS * 4bbq_mem N * (DIMS // 8 14)print(fOn disk - float32: {float_disk/1e6:6.2f} MB | BBQ: {bbq_disk/1e6:6.2f} MB)print(fIn memory - float32: {float_mem/1e6:6.2f} MB | BBQ: {bbq_mem/1e6:6.2f} MB ({float_mem/bbq_mem:.0f}x smaller))结果为On disk - float32: 12.80 MB | BBQ: 13.25 MBIn memory - float32: 12.71 MB | BBQ: 0.44 MB (29x smaller)。磁盘上两个索引大小基本相同BBQ因保留原始float32向量并添加1位向量占用略大。真正的节省体现在内存中HNSW扫描只需RAM中的1位向量原始浮点向量从磁盘读取用于重新评分。使用kNN内存公式估算占用BBQ在磁盘上的额外字节数与计算出的1位负载基本一致。结果召回率使用召回率检查量化索引返回结果与float基线的相似度公式为recall[k] | BBQ top-k ∩ float32 top-k | / k并在所有查询上取平均值。调整过采样因子找到匹配float32的最低值代码如下def search_ids(index, qvec, k10, num_candidates10):resp es_client.search(indexindex,sizek,_sourceFalse,knn{field: embedding,query_vector: qvec.tolist(),k: k,num_candidates: num_candidates,},)return [h[_id] for h in resp[hits][hits]]K 10ground_truth [set(search_ids(FLOAT_INDEX, qv, kK, num_candidates2000)) for qv in query_vectors]oversamples [1, 2, 3, 5, 10]recalls []for f in oversamples:num_candidates max(K * f, K)hits 0for gt, qv in zip(ground_truth, query_vectors):got set(search_ids(BBQ_INDEX, qv, kK, num_candidatesnum_candidates))hits len(got gt)recalls.append(hits / (len(query_vectors) * K))print(foversample {f:2}x - recall{K} {recalls[-1]:.3f})BBQ在1x过采样时的recall[10]从0.994开始3x之前保持该水平更高因子下稳定在0.989意味着所有过采样值下其返回的top-10文档中至少有98.9%与float32相同。BBQ量化结果总结相同向量两种存储格式的实验结果磁盘上大致相同12.80 MB对比13.25 MBBBQ为重新评分和合并保留原始浮点向量内存小29倍12.71 MB对比0.44 MB这决定集群是否能容纳语料库Recall10在1x过采样时为0.994量化感知训练发挥作用。启用BBQ的条件为维度数量高于384维下限向量是主要内存开销且能接受额外候选结果重新评分Jina v5针对此场景训练多数语料库上召回率损失小。关于BBQ和向量量化的进一步阅读可在支持博客内容仓库中运行本文完整的笔记本了解BBQ背后数学原理的信息获取Jina v5架构的更多信息查看采用BBQ的更广泛介绍阅读BBQ原始研究论文。

相关新闻

IP6862至为芯支持PD快充的一芯多充15W无线充电方案芯片

IP6862至为芯支持PD快充的一芯多充15W无线充电方案芯片

英集芯IP6862是一款适用于多设备同时充电的无线充电发射端控制SOC芯片,广泛应用于手机、智能手表、车载充电器等无线充电方案,单芯片支持双线圈、三线圈多设备同时无线充电,成熟实现 15W15W3W三合一方案。支持单路最大30W应用。兼容WPC Qi BP…

2026/11/14 20:53:52 阅读更多 →
Cloudflare品牌认知困境与技术品牌C端化策略

Cloudflare品牌认知困境与技术品牌C端化策略

1. Cloudflare的定位困境:从基础设施到品牌认知Cloudflare作为全球领先的网络基础设施服务商,在技术圈内享有盛誉。但一个尴尬的现实是:普通网民可能每天都在使用Cloudflare保护的服务,却对这个名字毫无印象。这就像电力公司——我…

2026/11/3 1:00:17 阅读更多 →
情感化内容创作技巧与安全边界指南

情感化内容创作技巧与安全边界指南

1. 项目背景解析"这里充满了愤怒与不甘"这个标题本身就蕴含着强烈的情感张力。作为一个内容创作者,我理解这种情绪表达背后往往反映了某些普遍存在的社会现象或个人困境。这类内容通常具有以下特征:情感浓度高,容易引发读者共鸣往往…

2026/11/12 5:17:51 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/14 5:13:29 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/14 5:13:29 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/14 5:13:29 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/14 5:13:29 阅读更多 →

日新闻

周新闻

月新闻