ETL Pipeline
ETL(Extract、Transform、Load)框架是 Retrieval Augmented Generation (RAG) 用例中数据处理的支柱。
ETL pipeline 编排从原始数据源到结构化向量存储的流程,确保数据以 AI 模型检索的最佳格式存在。
RAG 用例是通过从数据体中检索相关信息来增强生成模型能力的文本,以提高生成输出的质量和相关性。
API 概述
ETL pipeline 创建、转换和存储 Document 实例。

Document 类包含文本、元数据,以及可选的额外媒体类型,如图像、音频和视频。
ETL pipeline 有三个主要组件:
DocumentReader,实现Supplier<List<Document>>DocumentTransformer,实现Function<List<Document>, List<Document>>DocumentWriter,实现Consumer<List<Document>>
Document 类的内容是在 DocumentReader 的帮助下从 PDF、文本文件和其他文档类型创建的。
要构建一个简单的 ETL pipeline,可以将每种类型的实例链接在一起。

假设我们有这三种 ETL 类型的以下实例:
PagePdfDocumentReader,DocumentReader的实现TokenTextSplitter,DocumentTransformer的实现VectorStore,DocumentWriter的实现
要执行将数据加载到 Vector Database 以用于 Retrieval Augmented Generation 模式的基本操作,请在 Java 函数式语法中使用以下代码。
vectorStore.accept(tokenTextSplitter.apply(pdfReader.get()));
或者,您可以使用对领域更自然表达的方法名称:
vectorStore.write(tokenTextSplitter.split(pdfReader.read()));
ETL 接口
ETL pipeline 由以下接口和实现组成。 详细的 ETL 类图在 ETL 类图 部分显示。
DocumentReader
提供来自不同来源的文档源。
public interface DocumentReader extends Supplier<List<Document>> {
default List<Document> read() {
return get();
}
}
DocumentTransformer
转换一批文档作为处理工作流的一部分。
public interface DocumentTransformer extends Function<List<Document>, List<Document>> {
default List<Document> transform(List<Document> transform) {
return apply(transform);
}
}
DocumentWriter
管理 ETL 过程的最后阶段,准备文档以供存储。
public interface DocumentWriter extends Consumer<List<Document>> {
default void write(List<Document> documents) {
accept(documents);
}
}
ETL 类图
以下类图说明了 ETL 接口和实现。

DocumentReaders
JSON
JsonReader 处理 JSON 文档,将它们转换为 Document 对象列表。
示例
@Component
class MyJsonReader {
private final Resource resource;
MyJsonReader(@Value("classpath:bikes.json") Resource resource) {
this.resource = resource;
}
List<Document> loadJsonAsDocuments() {
JsonReader jsonReader = new JsonReader(this.resource, "description", "content");
return jsonReader.get();
}
}
构造函数选项
JsonReader 提供多个构造函数选项:
JsonReader(Resource resource)JsonReader(Resource resource, String... jsonKeysToUse)JsonReader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String... jsonKeysToUse)
参数
resource:指向 JSON 文件的 SpringResource对象。jsonKeysToUse:JSON 中应作为结果Document对象中文本内容使用的键数组。jsonMetadataGenerator:可选的JsonMetadataGenerator,用于为每个Document创建元数据。
行为
JsonReader 按以下方式处理 JSON 内容:
- 它可以处理 JSON 数组和单个 JSON 对象。
- 对于每个 JSON 对象(在数组中或单个对象中):
** 它根据指定的
jsonKeysToUse提取内容。 ** 如果未指定键,它使用整个 JSON 对象作为内容。 ** 它使用提供的JsonMetadataGenerator(如果未提供则使用空生成器)生成元数据。 ** 它创建一个包含提取内容和元数据的Document对象。
使用 JSON Pointers
JsonReader 现在支持使用 JSON Pointers 检索 JSON 文档的特定部分。此功能允许您轻松地从复杂的 JSON 结构中提取嵌套数据。
get(String pointer) 方法
public List<Document> get(String pointer)
此方法允许您使用 JSON Pointer 检索 JSON 文档的特定部分。
参数
pointer:JSON Pointer 字符串(如 RFC 6901 中定义),用于定位 JSON 结构中的所需元素。
返回值
- 返回包含从指针定位的 JSON 元素解析的文档的
List<Document>。
行为
- 该方法使用提供的 JSON Pointer 导航到 JSON 结构中的特定位置。
- 如果指针有效且指向现有 元素: ** 对于 JSON 对象:它返回包含单个 Document 的列表。 ** 对于 JSON 数组:它返回 Document 列表,数组中的每个元素一个。
- 如果指针无效或指向不存在的元素,它会抛出
IllegalArgumentException。
示例
JsonReader jsonReader = new JsonReader(resource, "description");
List<Document> documents = this.jsonReader.get("/store/books/0");
示例 JSON 结构
[
{
"id": 1,
"brand": "Trek",
"description": "A high-performance mountain bike for trail riding."
},
{
"id": 2,
"brand": "Cannondale",
"description": "An aerodynamic road bike for racing enthusiasts."
}
]
在此示例中,如果 JsonReader 配置为使用 "description" 作为 jsonKeysToUse,它将创建 Document 对象,其中内容是数组中每辆自行车的 "description" 字段的值。
注意事项
JsonReader使用 Jackson 进行 JSON 解析。- 它可以通过对数组使用流式处理来高效处理大型 JSON 文件。
- 如果在
jsonKeysToUse中指定了多个键,内容将是这些键值的连接。 - 通过自定义
jsonKeysToUse和JsonMetadataGenerator,读取器可以灵活适应各种 JSON 结构。
Text
TextReader 处理纯文本文档,将它们转换为 Document 对象列表。
示例
@Component
class MyTextReader {
private final Resource resource;
MyTextReader(@Value("classpath:text-source.txt") Resource resource) {
this.resource = resource;
}
List<Document> loadText() {
TextReader textReader = new TextReader(this.resource);
textReader.getCustomMetadata().put("filename", "text-source.txt");
return textReader.read();
}
}
构造函数选项
TextReader 提供两个构造函数选项:
TextReader(String resourceUrl)TextReader(Resource resource)
参数
resourceUrl:表示要读取的资源的 URL 的字符串。resource:指向文本文件的 SpringResource对象。
配置
setCharset(Charset charset):设置用于读取文本文件的字符集。默认为 UTF-8。getCustomMetadata():返回一个可变映射,您可以在其中为文档添加自定义元数据。
行为
TextReader 按以下方式处理文本内容:
- 它将整个文本文件的内容读入单个
Document对象。 - 文件的内容成为
Document的内容。 - 元数据自动添加到
Document: **charset:用于读取文件的字符集(默认:"UTF-8")。 **source:源文本文件的文件名。 - 通过
getCustomMetadata()添加的任何自定义元数据都包含在Document中。
注意事项
TextReader将整个文件内容读入内存,因此可能不适合非常大的文件。- 如果需要将文本拆分为更小的块,可以在读取文档后使用文本拆分器(如
TokenTextSplitter):
List<Document> documents = textReader.get();
List<Document> splitDocuments = new TokenTextSplitter().apply(this.documents);
- 读取器使用 Spring 的
Resource抽象,允许它从各种源(classpath、文件系统、URL 等)读取。 - 可以使用
getCustomMetadata()方法向读取器创建的所有文档添加自定义元数据。
HTML (JSoup)
JsoupDocumentReader 使用 JSoup 库处理 HTML 文档,将它们转换为 Document 对象列表。
示例
@Component
class MyHtmlReader {
private final Resource resource;
MyHtmlReader(@Value("classpath:/my-page.html") Resource resource) {
this.resource = resource;
}
List<Document> loadHtml() {
JsoupDocumentReaderConfig config = JsoupDocumentReaderConfig.builder()
.selector("article p") // Extract paragraphs within <article> tags
.charset("ISO-8859-1") // Use ISO-8859-1 encoding
.includeLinkUrls(true) // Include link URLs in metadata
.metadataTags(List.of("author", "date")) // Extract author and date meta tags
.additionalMetadata("source", "my-page.html") // Add custom metadata
.build();
JsoupDocumentReader reader = new JsoupDocumentReader(this.resource, config);
return reader.get();
}
}
JsoupDocumentReaderConfig 允许您自定义 JsoupDocumentReader 的行为:
charset:指定 HTML 文档的字符编码(默认为 "UTF-8")。selector:JSoup CSS 选择器,用于指定要从中提取文本的元素(默认为 "body")。separator:用于连接多个选定元素的文本的字符串(默认为 "\n")。allElements:如果为true,则从<body>元素提取所有文本,忽略selector(默认为false)。groupByElement:如果为true,则为selector匹配的每个元素创建一个单独的Document(默认为false)。includeLinkUrls:如果为true,则提取绝对链接 URL 并将它们添加到元数据(默认为false)。metadataTags:要从中提取内容的<meta>标签名称列表(默认为["description", "keywords"])。additionalMetadata:允许您向所有创建的Document对象添加自定义元数据。