使用 Jina Embeddings v2 在 Elasticsearch 中进行后期分块

作者:来自 Elastic Gustavo Llermaly

在 Elasticsearch 中使用 Jina Embeddings v2 模型并探索长上下文嵌入模型的优缺点。

在本文中,我们将配置和使用 jina-embeddings-v2,这是第一个开源 8K 上下文长度嵌入模型,首先使用 semantic_text 进行 OOTB 实现,然后实现 Late Chunking。

长上下文模型 - long-context models

我们通常看到上下文长度为 512 个 token 的嵌入模型,这意味着如果我们尝试创建更长的嵌入,则只有前 512 个 token 会添加到向量字段中。这些短上下文的问题在于,块不会知道整个上下文,而只会知道块内的文本:

正如你在图片中看到的,在块 1 中我们知道我们在谈论 Sarah Johnson,但在块 2 中我们失去了直接引用。因此,随着文档变长,它可能会错过 Sarah Johnson 首次被提及时的依赖关系,并且不会将 “Sarah Johnson”、“She” 和 “her” 指代同一个人联系起来。当然,如果有不止一个人被称为 her/she,这会变得更加复杂,但现在让我们看看解决这个问题的第一种方法。

旨在生成文本的传统长上下文模型只关心对前面单词的依赖关系,因此输入中的最后一个标记比前面的标记更重要,因为文本生成器的任务是在输入后生成下一个单词。然而,Jina Embeddings 2 模型经过三个关键阶段的训练:首先,它使用 1700 亿个单词的英语 C4 数据集进行掩码单词预训练。接下来,它使用已知相似或不相似的文本对进行成对对比训练,使用 Jina AI 的新语料库来优化嵌入,使相似的文本更接近,而不相似的文本更远。最后,使用文本三元组和负挖掘对其进行微调,结合具有相反语法极性的句子的数据集,以改进对具有相反含义的句子的嵌入可能过于接近的情况的处理。

那么,让我们看看它是如何工作的:更长的上下文长度使我们能够将第一次提到 Sarah Johnson 的引用保留在同一块中:

然而,这也有其缺点。上下文越大,意味着你将在相同维度空间内放置更多信息。这种压缩可能会稀释上下文,从嵌入中删除潜在的重要信息。另一个缺点是生成更长的嵌入需要更多的计算资源。最后,在 RAG 系统中,文本块的大小决定了你向 LLM 发送的信息量,这将影响精度、成本和延迟。好消息是你不必使用整个 8K token,你可以根据你的用例找到一个最佳点。你在文章 “Elasticsearch:检索增强生成背后的重要思想” 可以。

Jina 致力于将两者的优点结合起来,提出了一种称为 “后期分块(Late Chunking)” 的方法。后期分块包括在嵌入之后对文本进行分块,而不是先对文本进行分块,然后为每个独立的块创建嵌入。为此,你需要一个能够创建上下文感知嵌入的模型,然后你可以在保留上下文(即块之间的依赖关系和关系)的同时对生成的嵌入进行分块。

我们将在 Elasticsearch 中设置 jina-embeddings-v2 模型并将其与 semantic_text一起使用,然后为后期分块创建自定义设置。

步骤

  • 创建端点
  • 创建索引
  • 索引数据
  • 提问
  • 后期分块示例

创建端点

借助我们的 HuggingFace 开放推理服务集成(Open Inference Service integration),运行 HuggingFace 模型非常简单。你只需打开模型网页,单击 Inference API 下的 View Code,然后从那里获取 API URL。在同一屏幕中,你可以 Manage your tokens 以创建 API 密钥。

有关创建安全 token 的更多详细信息,你可以访问此处。出于本文的目的,将其设置为 read token 是可以的。

获得 url 和 api_key 后,继续创建推理端点(inference endpoint):

PUT _inference/text_embedding/jina-embeddings-v2-base-en
{"service": "hugging_face","service_settings": {"api_key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "url": "https://api-inference.huggingface.co/models/jinaai/jina-embeddings-v2-base-en" }
}

如果你收到此错误 “Model jinaai/jina-embeddings-v2-base-en is currently loading”,则表示模型正在预热。请等待几秒钟,然后重试。

创建索引

我们将使用 semantic_text 字段类型。它将负责推断嵌入映射和配置,并为你进行段落分块!如果你想了解更多信息,可以阅读这篇精彩的文章。

PUT jina-embeddings
{"mappings": {"properties": {"super_body": {"type": "semantic_text","inference_id": "jina-embeddings-v2-base-en"}}}
}

这种方法将为我们处理向量配置和文档分块,从而为我们提供一个良好的起点。它将创建 250 个单词的块,其中有 100 个单词重叠。对于诸如增加块大小以利用 8K 上下文大小之类的自定义,我们必须经历一个更长的过程,我们将在后期分块部分进行探讨。

索引数据

使用 semantic_text 时,我们会用到。我们只需像往常一样索引数据即可。

PUT jina-embeddings/_bulk
{ "index" : { "_index" : "jina-embeddings", "_id" : "1" } }
{"super_body": "Sarah Johnson is a talented marine biologist working at the Oceanographic Institute. Her groundbreaking research on coral reef ecosystems has garnered international attention and numerous accolades."}
{ "index" : { "_index" : "jina-embeddings", "_id" : "2" } }
{"super_body": "She spends months at a time diving in remote locations, meticulously documenting the intricate relationships between various marine species. "}
{ "index" : { "_index" : "jina-embeddings", "_id" : "3" } }
{"super_body": "Her dedication to preserving these delicate underwater environments has inspired a new generation of conservationists."}

提出问题

现在我们可以使用语义搜索查询来向我们的数据提出问题:

GET jina-embeddings/_search 
{"query": {"semantic": {"field": "super_body","query": "who inspired taking care of the sea?"}}
}

第一个结果将如下所示:

{"_index": "jina-embeddings","_id": "1","_score": 0.64889884,"_source": {"super_body": {"text": "Sarah Johnson is a talented marine biologist working at the Oceanographic Institute. Her groundbreaking research on coral reef ecosystems has garnered international attention and numerous accolades.","inference": {"inference_id": "jina-embeddings-v2-base-en","model_settings": {"task_type": "text_embedding","dimensions": 768,"similarity": "cosine","element_type": "float"},"chunks": [{"text": "Sarah Johnson is a talented marine biologist working at the Oceanographic Institute. Her groundbreaking research on coral reef ecosystems has garnered international attention and numerous accolades.","embeddings": [-0.0064849486,-0.014192865,0.028806737,0.0026694024,... // 768 dims]}]}}}
}

后期分块示例

现在我们已经配置了嵌入模型,我们可以在 Elasticsearch 中创建自己的后期分块实现。该过程需要以下步骤:

1. 创建映射

PUT jina-late-chunking
{"mappings": {"properties": {"content_embedding": { "type": "dense_vector", "dims": 768, "element_type": "float","similarity": "cosine"},"content": { "type": "text" }}}
}

2. 加载数据

你可以在支持 Notebook 中找到完整的实现。

我们在这里不使用摄取管道方法,因为我们想要创建特殊的嵌入,而是使用一个 Python 脚本,其关键作用是获取块标记位置的注释,为整个文档生成嵌入,然后根据我们提供的长度对嵌入进行分块:

使用此代码,你可以通过按句子拆分并获取块位置来定义文本块大小。

def chunk_by_sentences(input_text: str, tokenizer: callable):"""Split the input text into sentences using the tokenizer:param input_text: The text snippet to split into sentences:param tokenizer: The tokenizer to use:return: A tuple containing the list of text chunks and their corresponding token spans"""inputs = tokenizer(input_text, return_tensors='pt', return_offsets_mapping=True)punctuation_mark_id = tokenizer.convert_tokens_to_ids('.')sep_id = tokenizer.convert_tokens_to_ids('[SEP]')token_offsets = inputs['offset_mapping'][0]token_ids = inputs['input_ids'][0]chunk_positions = [(i, int(start + 1))for i, (token_id, (start, end)) in enumerate(zip(token_ids, token_offsets))if token_id == punctuation_mark_idand (token_offsets[i + 1][0] - token_offsets[i][1] > 0or token_ids[i + 1] == sep_id)]chunks = [input_text[x[1] : y[1]]for x, y in zip([(1, 0)] + chunk_positions[:-1], chunk_positions)]span_annotations = [(x[0], y[0]) for (x, y) in zip([(1, 0)] + chunk_positions[:-1], chunk_positions)]return chunks, span_annotations

第二个函数将接收整个输入的注释(annotations)和嵌入以生成嵌入块。

def late_chunking(model_output: 'BatchEncoding', span_annotation: list, max_length=None
):token_embeddings = model_output[0]outputs = []for embeddings, annotations in zip(token_embeddings, span_annotation):if (max_length is not None):  # remove annotations which go bejond the max-length of the modelannotations = [(start, min(end, max_length - 1))for (start, end) in annotationsif start < (max_length - 1)]pooled_embeddings = [embeddings[start:end].sum(dim=0) / (end - start)for start, end in annotationsif (end - start) >= 1]pooled_embeddings = [embedding.detach().cpu().numpy() for embedding in pooled_embeddings]outputs.append(pooled_embeddings)return outputs

这是将所有内容组合在一起的部分;对整个文本输入进行标记,然后将其传递给 late_chunking 函数以对池化嵌入进行分块。

inputs = tokenizer(input_text, return_tensors='pt')
model_output = model(**inputs)
embeddings = late_chunking(model_output, [span_annotations])[0] 

经过这个过程,我们可以索引我们的文档:

# Prepare the documents to be indexed
documents = []
for chunk, new_embedding in zip(chunks, embeddings):documents.append({"_index": "jina-late-chunking","_source": {"content_embedding": new_embedding,"content": chunk,},})
# Use helpers.bulk to index
helpers.bulk(client, documents)

你可以在此处找到包含完整示例的笔记本。

请随意尝试 input_text 变量中的不同值。

3. 运行查询

你现在可以针对新数据索引运行语义搜索:

GET jina-late-chunking/_search
{"knn": {"field": "content_embedding","query_vector_builder": {"text_embedding": {"model_id": "jina-embeddings-v2-base-en","model_text": "berlin"}},"k": 10,"num_candidates": 100}
}

结果将如下所示:

{"_index": "jina-late-chunking","_id": "gGDN1JEBF7lnCNFTVZBg","_score": 0.4930191,"_source": {"content_embedding": [-0.9107036590576172,-0.57366544008255,1.0492067337036133,0.25255489349365234,-0.1283145546913147... ],"content": "Berlin is the capital and largest city of Germany, both by area and by population."}
}

结论

虽然仍处于试验阶段,但后期分块可能有很多好处,尤其是在 RAG 中,因为它允许你在对文本进行分块时保留关键上下文信息。此外,Jina 嵌入模型有助于存储较短的向量,从而占用更少的内存和存储空间,并加快搜索检索速度。因此,这两个功能与 Elasticsearch 结合使用,在使用向量搜索时提高了管理和检索信息的效率和有效性。

Elasticsearch 与业界领先的 Gen AI 工具和提供商进行了原生集成。查看我们的网络研讨会,了解如何超越 RAG 基础知识,或构建可用于生产的应用程序 Elastic Vector Database。

要为你的用例构建最佳搜索解决方案,请立即开始免费云试用或在你的本地机器上试用 Elastic。

原文:Late chunking in Elasticsearch with Jina Embeddings v2 - Search Labs

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

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

相关文章

电视网络机顶盒恢复出厂超级密码大全汇总

部分电视机顶盒在按遥控器设置键打开设置时&#xff0c;会弹出设置密码弹窗&#xff0c;需输入密码才能操作其中内容。 如下图所示&#xff1a; 部分电视机顶盒在选择恢复出厂设置时&#xff0c;会出现设置密码弹窗&#xff0c;只有输入操作密码后才能进行恢复出厂设置的操作。…

cmake原理

CMake原理与快速入门 CMake是一个跨平台的构建&#xff08;build&#xff09;工具&#xff0c;完成代码编译、链接、打包过程。在开发AI应用平台时&#xff0c;由于开发的平台是在边缘设备运行的&#xff0c;而边缘设备的算力不高&#xff0c;所以对平台的效率要求比较高&…

SFTP全解析:深入了解组件功能与适用场景

文章目录 一、组件功能二、适用场景三、SFTP优势四、SFTP原理五&#xff0e;SFTP与同类产品对比六、部署方案1.裸金属部署2.k8s容器化部署 七、高可用方案八、监控方案九、常见问题及解决方法 一、组件功能 安全文件传输协议SFTP(SSH File Transfer Protocol)是文件传输协议(F…

Android 中文文件名排序实现案例教程

Android 中文文件名排序实现案例教程 一、问题分析二、解决方法2.1 使用系统提供的 Collator 类2.2 使用第三方库 Pinyin4J2.3 自定义排序规则 三、总结 在 Android 应用中&#xff0c;经常需要对包含中文的文件名进行排序。由于中文的特殊性&#xff0c;直接使用字符串比较的方…

java——Spring MVC的工作流程

Spring MVC的工作流程是基于模型-视图-控制器&#xff08;MVC&#xff09;设计模式的一个典型实现&#xff0c;以下是其主要工作流程步骤&#xff1a; 客户端请求提交&#xff1a; 用户通过浏览器向服务器发送请求&#xff0c;该请求首先到达Spring MVC的前端控制器DispatcherS…

Mutex::Autolock 和 std::lock_guard 的区别

Mutex::Autolock 和 std::lock_guard 都是 C 中用于管理互斥锁&#xff08;mutex&#xff09;的一种方式&#xff0c;它们的目标是自动获取和释放锁&#xff0c;避免手动管理锁的复杂性&#xff0c;从而防止死锁和遗漏解锁等问题。尽管它们有相似的功能&#xff0c;但二者也存在…

<项目代码>YOLOv8 红绿灯识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

mac下安装Ollama + Open WebUI + Llama3.1

本文介绍mac下安装Ollama Open WebUI Llama3.1 8b具体步骤。 目录 推荐配置Ollama Open WebUI Llama3.1简介安装Ollama安装Open WebUI 推荐配置 m1以上芯片&#xff0c;16g内存&#xff0c;20g以上硬盘空间 Ollama Open WebUI Llama3.1简介 Ollama: 下载&#xff0c;管理…

Linux 无图形界面磁盘空间排查与优化实践20241127

Linux 无图形界面磁盘空间排查与优化实践 引言&#xff1a;磁盘空间问题的痛点与挑战 &#x1f50d; 常见问题 当系统磁盘空间超过 90% 时&#xff0c;不仅可能导致性能下降&#xff0c;还可能让关键操作无法正常完成。这种情况下&#xff0c;如何高效且精准地排查磁盘占用来…

【Fargo】27:ffmpeg ffprobe 和python分析h264文件并绘制

从帧和包两个层面进行分析。帧级别分析 ffprobe 可以读取264文件信息 -Y9KP MINGW64 /d/XTRANS/thunderbolt/ayame/zhb-bifrost/player-only (main) $ ffprobe test.h264 ffprobe version N-116778-g7e4784e40c-20240827 Copyright (c) 2007-2024 the FFmpeg developersbuilt …

uniapp生命周期:应用生命周期和页面生命周期

文章目录 1.应用的生命周期2.页面的生命周期 1.应用的生命周期 生命周期的概念&#xff1a;一个对象从创建、运行、销毁的整个过程被称为生命周期 生命周期函数&#xff1a;在生命周期中每个阶段会伴随着每一个函数的出发&#xff0c;这些函数被称为生命周期函数 所有页面都…

【AI】JetsonNano启动时报错:soctherm OC ALARM

1、问题描述 将JetsonNano烧写SD卡镜像为Ubuntu20.04后&#xff0c;启动时报错&#xff1a;soctherm OC ALARM&#xff0c;启动失败&#xff1b;然后系统一直重启 2、原因分析 “soctherm OC ALARM”是检测到系统温度超过安全阈值时发出的过热警告。 “soctherm”代表系统…

SycoTec 4060 ER-S德国高精密主轴电机如何支持模具的自动化加工?

SycoTec 4060 ER-S高速电主轴在模具自动化加工中的支持体现在以下几个关键方面&#xff1a; 1.高精度与稳定性&#xff1a;SycoTec 4060 ER-S锥面跳动小于1微米&#xff0c;确保了加工过程中的极高精度&#xff0c;这对于模具的复杂几何形状和严格公差要求至关重要。高精度加工…

构建一个去中心化的零售生态参与者的商业模型

在数字化和去中心化技术快速发展的背景下&#xff0c;传统零售行业正迎来革命性的转型。去中心化零售生态不仅让消费者、商家和内容创作者在同一平台上共同参与价值的创造和分配&#xff0c;还推动了零售体验、数据控制和社会互动的彻底变革。本文将探讨如何构建一个去中心化的…

clickhouse 使用global in 优化 in查询

文章目录 in例子使用global in in例子 SELECT uniq(UserID) FROM distributed_table WHERE CounterID 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID 34)对于in 查询来说&#xff0c;本来查询的就是分布式表&#xff0c;假设这个表有100 个…

Docker 启动和停止的精准掌舵:操控指南

Docker 启动和停止的精准掌舵&#xff1a;操控指南 Docker是一个开源的应用容器引擎&#xff0c;基于Go语言开发&#xff0c;能够让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。Do…

Oracle Universal Unique Identifier (UUID)

本文介绍Oracle生成全局唯一ID的函数SYS_GUID&#xff0c;后续会对SYS_GUID和Sequence两种方法进行比较。 SYS_GUID 函数生成并返回一个由 16 个字节组成的全局唯一标识符&#xff08;RAW 值&#xff09;。在大多数平台上&#xff0c;生成的标识符由主机标识符、调用该函数的进…

微信小程序页面配置详解:从入门到精通

微信小程序页面配置详解:从入门到精通 引言 随着移动互联网的飞速发展,微信小程序作为一种新兴的应用形式,因其便捷性和丰富的功能而受到广泛欢迎。在小程序的开发过程中,页面配置是至关重要的一环。本文将深入探讨微信小程序的页面配置,帮助开发者从基础到高级逐步掌握…

d3-contour 生成等高线图

D3.js 是一个强大的 JavaScript 库&#xff0c;用于创建动态、交互式数据可视化。d3-contour 是 D3.js 的一个扩展模块&#xff0c;用于生成等高线图&#xff08;contour plots&#xff09;。 属性和方法 属性 x: 一个函数&#xff0c;用于从数据点中提取 x 坐标。y: 一个函…

Vue 中 data 属性为函数的深度剖析:原理、区别与实践

在 Vue.js 中,data 属性通常是一个 函数 而不是一个对象,这背后有一系列设计上的原因和原理,尤其是与 Vue 的组件系统、实例化机制、以及响应式数据的管理有关。下面我将详细解答这个问题,并结合实际项目示例和代码分析,进行全面讲解。 1. Vue 中 data 为什么是一个函数而…