SpringAI(GA):RAG下的ETL快速上手

原文鏈接:SpringAI(GA):RAG下的ETL快速上手

教程說明

說明:本教程將采用2025年5月20日正式的GA版,給出如下內容

  1. 核心功能模塊的快速上手教程
  2. 核心功能模塊的源碼級解讀
  3. Spring ai alibaba增強的快速上手教程 + 源碼級解讀

版本:JDK21 + SpringBoot3.4.5 + SpringAI 1.0.0 + SpringAI Alibaba 1.0.0.2

將陸續完成如下章節教程。本章是第六章(Rag增強問答質量)下的ETL Pipeline快速上手篇

代碼開源如下:https://github.com/GTyingzi/spring-ai-tutorial

往屆解讀可參考:

第一章內容

SpringAI(GA)的chat:快速上手+自動注入源碼解讀

SpringAI(GA):ChatClient調用鏈路解讀

第二章內容

SpringAI的Advisor:快速上手+源碼解讀

SpringAI(GA):Sqlite、Mysql、Redis消息存儲快速上手

第三章內容

SpringAI(GA):Tool工具整合—快速上手

第五章內容

SpringAI(GA):內存、Redis、ES的向量數據庫存儲—快速上手

SpringAI(GA):向量數據庫理論源碼解讀+Redis、Es接入源碼

第六章內容

SpringAI(GA):RAG快速上手+模塊化解讀

獲取更好的觀賞體驗,可付費獲取飛書云文檔Spring AI最新教程權限,目前49.9,隨著內容不斷完善,會逐步漲價。

注:M6版快速上手教程+源碼解讀飛書云文檔已免費提供

RAG 的 ETL Pipeline 快速上手

[!TIP]
提取(Extract)、轉換(Transform)和加載(Load)框架是《第六章:Rag 增強問答質量》中數據處理的鏈路,將原始數據源導入到向量化存儲的流程,確保數據處于最佳格式,以便 AI 模型進行檢索

實戰代碼可見:https://github.com/GTyingzi/spring-ai-tutorial 下的 rag/rag-etl-pipeline

源碼解讀可見:《ETL Pipeline 源碼解析》

pom 文件

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-openai</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-commons</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-rag</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-jsoup-document-reader</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-markdown-document-reader</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-tika-document-reader</artifactId></dependency></dependencies>

application.yml

server:port: 8080spring:application:name: rag-etl-pipelineai:openai:api-key: ${DASHSCOPEAPIKEY}base-url: https://dashscope.aliyuncs.com/compatible-modechat:options:model: qwen-maxembedding:options:model: text-embedding-v1

提取文檔

Constant
package com.spring.ai.tutorial.rag.model;public class Constant {public static final String PREFIX = "classpath:data/";public static final String TEXTFILEPATH = PREFIX + "/text.txt";public static final String JSONFILEPATH = PREFIX + "/text.json";public static final String MARKDOWNFILEPATH = PREFIX + "/text.md";public static final String PDFFILEPATH = PREFIX + "/google-ai-agents-whitepaper.pdf";;public static final String HTMLFILEPATH = PREFIX + "/spring-ai.html";
}

ReaderController
package com.spring.ai.tutorial.rag.controller;import com.spring.ai.tutorial.rag.model.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.JsonReader;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.reader.jsoup.JsoupDocumentReader;
import org.springframework.ai.reader.markdown.MarkdownDocumentReader;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.ParagraphPdfDocumentReader;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/reader")
public class ReaderController {private static final Logger logger = LoggerFactory.getLogger(ReaderController.class);@GetMapping("/text")public List<Document> readText() {logger.info("start read text file");Resource resource = new DefaultResourceLoader().getResource(Constant.TEXTFILEPATH);TextReader textReader = new TextReader(resource); // 適用于文本數據return textReader.read();}@GetMapping("/json")public List<Document> readJson() {logger.info("start read json file");Resource resource = new DefaultResourceLoader().getResource(Constant.JSONFILEPATH);JsonReader jsonReader = new JsonReader(resource); // 只可以傳json格式文件return jsonReader.read();}@GetMapping("/pdf-page")public List<Document> readPdfPage() {logger.info("start read pdf file by page");Resource resource = new DefaultResourceLoader().getResource(Constant.PDFFILEPATH);PagePdfDocumentReader pagePdfDocumentReader = new PagePdfDocumentReader(resource); // 只可以傳pdf格式文件return pagePdfDocumentReader.read();}@GetMapping("/pdf-paragraph")public List<Document> readPdfParagraph() {logger.info("start read pdf file by paragraph");Resource resource = new DefaultResourceLoader().getResource(Constant.PDFFILEPATH);ParagraphPdfDocumentReader paragraphPdfDocumentReader = new ParagraphPdfDocumentReader(resource); // 有目錄的pdf文件return paragraphPdfDocumentReader.read();}@GetMapping("/markdown")public List<Document> readMarkdown() {logger.info("start read markdown file");MarkdownDocumentReader markdownDocumentReader = new MarkdownDocumentReader(Constant.MARKDOWNFILEPATH); // 只可以傳markdown格式文件return markdownDocumentReader.read();}@GetMapping("/html")public List<Document> readHtml() {logger.info("start read html file");Resource resource = new DefaultResourceLoader().getResource(Constant.HTMLFILEPATH);JsoupDocumentReader jsoupDocumentReader = new JsoupDocumentReader(resource); // 只可以傳html格式文件return jsoupDocumentReader.read();}@GetMapping("/tika")public List<Document> readTika() {logger.info("start read file with Tika");Resource resource = new DefaultResourceLoader().getResource(Constant.HTMLFILEPATH);TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(resource); // 可以傳多種文檔格式return tikaDocumentReader.read();}
}
效果

讀取文本文件

讀取 json 文件

讀取 pdf 文件

讀取帶目錄的 pdf 文件

讀取 markdown 文件

讀取 html 文件

利用 tika 讀取任意文檔格式

轉換文檔

TransformerController
package com.spring.ai.tutorial.rag.controller;import com.spring.ai.tutorial.rag.model.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.document.DefaultContentFormatter;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.transformer.KeywordMetadataEnricher;
import org.springframework.ai.model.transformer.SummaryMetadataEnricher;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.transformer.ContentFormatTransformer;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/transformer")
public class TransformerController {private static final Logger logger = LoggerFactory.getLogger(TransformerController.class);private final List<Document> documents;private final ChatModel chatModel;public TransformerController(ChatModel chatModel) {logger.info("start read pdf file by page");Resource resource = new DefaultResourceLoader().getResource(Constant.PDFFILEPATH);PagePdfDocumentReader pagePdfDocumentReader = new PagePdfDocumentReader(resource); // 只可以傳pdf格式文件this.documents = pagePdfDocumentReader.read();this.chatModel = chatModel;}@GetMapping("/token-text-splitter")public List<Document> tokenTextSplitter() {logger.info("start token text splitter");TokenTextSplitter tokenTextSplitter = TokenTextSplitter.builder()// 每個文本塊的目標token數量.withChunkSize(800)// 每個文本塊的最小字符數.withMinChunkSizeChars(350)// 丟棄小于此長度的文本塊.withMinChunkLengthToEmbed(5)// 文本中生成的最大塊數.withMaxNumChunks(10000)// 是否保留分隔符.withKeepSeparator(true).build();return tokenTextSplitter.split(this.documents);}@GetMapping("/content-format-transformer")public List<Document> contentFormatTransformer() {logger.info("start content format transformer");DefaultContentFormatter defaultContentFormatter = DefaultContentFormatter.defaultConfig();ContentFormatTransformer contentFormatTransformer = new ContentFormatTransformer(defaultContentFormatter);return contentFormatTransformer.apply(this.documents);}@GetMapping("/keyword-metadata-enricher")public List<Document> keywordMetadataEnricher() {logger.info("start keyword metadata enricher");KeywordMetadataEnricher keywordMetadataEnricher = new KeywordMetadataEnricher(this.chatModel, 3);return keywordMetadataEnricher.apply(this.documents);}@GetMapping("/summary-metadata-enricher")public List<Document> summaryMetadataEnricher() {logger.info("start summary metadata enricher");List<SummaryMetadataEnricher.SummaryType> summaryTypes = List.of(SummaryMetadataEnricher.SummaryType.NEXT,SummaryMetadataEnricher.SummaryType.CURRENT,SummaryMetadataEnricher.SummaryType.PREVIOUS);SummaryMetadataEnricher summaryMetadataEnricher = new SummaryMetadataEnricher(this.chatModel, summaryTypes);return summaryMetadataEnricher.apply(this.documents);}
}
效果

TokenTextSplitter 切分

DefaultContentFormatter 格式化

KeywordMetadataEnricher 提取關鍵字

SummaryMetadataEnricher 提取摘要

寫出文檔

WriterController
package com.spring.ai.tutorial.rag.controller;import com.spring.ai.tutorial.rag.model.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.writer.FileDocumentWriter;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/writer")
public class WriterController {private static final Logger logger = LoggerFactory.getLogger(WriterController.class);private final List<Document> documents;private final SimpleVectorStore simpleVectorStore;public WriterController(EmbeddingModel embeddingModel) {logger.info("start read pdf file by page");Resource resource = new DefaultResourceLoader().getResource(Constant.PDFFILEPATH);PagePdfDocumentReader pagePdfDocumentReader = new PagePdfDocumentReader(resource); // 只可以傳pdf格式文件this.documents = pagePdfDocumentReader.read();this.simpleVectorStore = SimpleVectorStore.builder(embeddingModel).build();}@GetMapping("/file")public void writeFile() {logger.info("Writing file...");String fileName = "output.txt";FileDocumentWriter fileDocumentWriter = new FileDocumentWriter(fileName, true);fileDocumentWriter.accept(this.documents);}@GetMapping("/vector")public void writeVector() {logger.info("Writing vector...");simpleVectorStore.add(documents);}@GetMapping("/search")public List<Document> search() {logger.info("start search data");return simpleVectorStore.similaritySearch(SearchRequest.builder().query("Spring").topK(2).build());}
}
效果

Document 寫出文本文件

寫入 vector

從 vector 中查找

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85423.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85423.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用dayjs解析時間戳,我被提了bug

引言 前幾天開發中突然接到測試提的一個 Bug&#xff0c;說我的時間組件顯示異常。 我很詫異&#xff0c;這里初始化數據是后端返回的&#xff0c;我什么也沒改&#xff0c;這bug提給我干啥。我去問后端&#xff1a;“這數據是不是有問題&#xff1f;”。后端答&#xff1a;“…

DataAgent產品經理(數據智能方向)

DataAgent產品經理&#xff08;數據智能方向&#xff09; 一、核心崗位職責 AI智能體解決方案設計 面向工業/政務場景構建「數據-模型-交互」閉環&#xff0c;需整合多源異構數據&#xff08;如傳感器數據、業務系統日志&#xff09;與AI能力&#xff08;如大模型微調、知識圖…

Ubuntu取消開機用戶自動登錄

注&#xff1a;配置前請先設置登錄密碼&#xff0c;不同顯示管理器配置方法不同&#xff0c;可用命令查看&#xff1a;cat /etc/X11/default-display-manager 一、LightDM 顯示管理器&#xff0c;關閉 Ubuntu 系統用戶自動登錄 查找自動登錄配置文件&#xff0c;可以看到類似 a…

使用lighttpd和開發板進行交互

文章目錄 &#x1f9e0; 一、Lighttpd 與開發板的交互原理1. 什么是 Lighttpd&#xff1f;2. 與開發板交互的方式&#xff1f; &#x1f9fe; 二、lighttpd.conf 配置文件講解?? 注意事項&#xff1a; &#x1f4c1; 三、目錄結構說明&#x1f4a1; 四、使用 C 編寫 CGI 腳本…

Apache IoTDB V2.0.3 發布|新增元數據導入導出腳本適配表模型功能

Release Announcement Version 2.0.3 Apache IoTDB V2.0.3 已經發布&#xff01; V2.0.3 作為樹表雙模型正式版本&#xff0c;主要新增元數據導入導出腳本適配表模型、Spark 生態集成&#xff08;表模型&#xff09;、AINode 返回結果新增時間戳&#xff0c;表模型新增部分聚…

車輛檢測算法在爆炸事故應急響應中的優化路徑

視覺分析賦能車輛管控&#xff1a;以山東應急場景為例 背景&#xff1a;應急場景下的車輛管控痛點 近期山東多起爆炸事故暴露了應急響應中的車輛管理短板&#xff1a;消防車、救護車因違停車輛堵塞通道&#xff0c;違規車輛闖入事故核心區&#xff0c;傳統監控系統依賴人工識別…

∑ 1/n 調和級數 是 發散的

為什么 ∑ 1 u \sum \frac{1}{u} ∑u1?&#xff08;即 ∑ 1 n \sum \frac{1}{n} ∑n1?&#xff0c;通常稱為調和級數&#xff09;是發散的&#xff1f; ? 一、首先明確你問的是這個級數&#xff1a; ∑ n 1 ∞ 1 n \sum_{n1}^{\infty} \frac{1}{n} n1∑∞?n1? 這個級數…

Android第十二次面試-多線程和字符串算法總結

多線程的創建與常見使用方法 ?一、多線程創建方式? ?1. 繼承Thread類? class MyThread extends Thread {Overridepublic void run() {// 線程執行邏輯System.out.println(Thread.currentThread().getName() " is running");} }// 使用 MyThread thread new …

大模型調用數據庫表實踐:基于自然語言的SQL生成與數據查詢系統

# 大模型調用數據庫表實踐&#xff1a;基于自然語言的SQL生成與數據查詢系統 ## 一、背景與目標 在企業數據管理場景中&#xff0c;非技術人員&#xff08;如業務人員、管理人員&#xff09;常常需要通過數據庫查詢獲取關鍵信息&#xff0c;但直接編寫SQL語句存在技術門檻。傳…

28 C 語言作用域詳解:作用域特性(全局、局部、塊級)、應用場景、注意事項

1 作用域簡介 作用域定義了代碼中標識符&#xff08;如變量、常量、數組、函數等&#xff09;的可見性與可訪問范圍&#xff0c;即標識符在程序的哪些位置能夠被引用或訪問。在 C 語言中&#xff0c;作用域主要分為三類&#xff1a; 全局作用域局部作用域塊級作用域 需注意&am…

Tomcat運行比較卡頓進行參數調優

在Tomcat conf/catalina.bat或catalina.sh中 的最上面增加參數 1. 初步調整參數&#xff08;緩解問題&#xff09; set JAVA_OPTS -Xms6g -Xmx6g -Xmn3g # 增大新生代&#xff0c;減少對象過早晉升到老年代 -XX:MetaspaceSize256m -XX:MaxMetaspaceS…

WSL2 安裝與Docker安裝

注意&#xff1a;如沒有科學上網請勿嘗試&#xff0c;無法判斷是否會因網絡錯誤導致的安裝失敗&#xff01;&#xff01;&#xff01; WSL2&#xff08;Windows Subsystem for Linux 2&#xff09; 功能簡介&#xff1a; WSL2 是微軟提供的在 Windows 上運行完整 Linux 內核的…

Redis的安裝與使用

網址&#xff1a;Spring Data Redis 安裝包&#xff1a;Releases tporadowski/redis GitHub 解壓后 在安裝目錄中打開cmd 打開服務&#xff08;注意&#xff1a;每次客戶端連接都有先打開服務&#xff01;&#xff01;&#xff01;&#xff09; 按ctrlC退出服務 客戶端連接…

springboot-響應接收與ioc容器控制反轉、Di依賴注入

1.想將服務器中的數據返回給客戶端&#xff0c;需要在controller類上加注解&#xff1a;ResponseBody; 這個注解其實在前面已經使用過&#xff0c;RestController其實就包含兩個注解&#xff1a; Controller ResponseBody 返回值如果是實體對象/集合&#xff0c;將會轉換為j…

將材質球中的紋理屬性對應的貼圖保存至本地

通過Texture2D的EncodeToPNG方法將紋理轉為圖片形式 material.GetTexture方法通過屬性名獲取紋理貼圖 material.SetTexture方法通過屬性名設置紋理貼圖 屬性名可在shader代碼中查看 using UnityEngine; using System.IO;public class TextureSaver : MonoBehaviour {public…

MySQL半同步復制配置和參數詳解

目錄 1 成功配置主從復制 2 加載插件 3 半同步復制監控 4 半同步復制參數 1 成功配置主從復制 操作步驟參考&#xff1a;https://blog.csdn.net/zyb378747350/article/details/148309545 2 加載插件 #主庫上 MySQL 8.0.26 之前版本: mysql>INSTALL PLUGIN rpl_semi_syn…

【筆記】Windows 成功部署 Suna 開源的通用人工智能代理項目部署日志

#工作記錄 本地部署運行截圖 kortix-ai/suna&#xff1a; Suna - 開源通用 AI 代理 項目概述 Suna 是一個完全開源的 AI 助手&#xff0c;通過自然對話幫助用戶輕松完成研究、數據分析等日常任務。它結合了強大的功能和直觀的界面&#xff0c;能夠理解用戶需求并提供結果。其強…

PCB制作入門

文章目錄 1 嘉立創使用旋轉 2元器件選擇MP2315SLM7815與LM7915 1 嘉立創使用 旋轉 空格旋轉 2元器件選擇 MP2315S MP2315S 是一款內置功率 MOSFET 的高效率同步整流降壓開關變換器。 其輸入電壓范圍為 4.5V 至 24V &#xff0c;能實現 3A 連續輸出電流&#xff0c;負載與…

2025——》NumPy中的np.logspace使用/在什么場景下適合使用np.logspace?NumPy中的np.logspace用法詳解

1.NumPy中的np.logspace使用: 在 NumPy 中,np.logspace函數用于生成對數尺度上等間距分布的數值序列,適用于科學計算、數據可視化等需要對數間隔數據的場景。以下是其核心用法和關鍵細節: 一、基礎語法與參數解析: numpy.logspace(start, stop, num=50, endpoint=True, ba…

Java實現中文姓名轉拼音生成用戶信息并寫入文件

中文姓名轉拼音 Java實現中文姓名轉拼音生成用戶信息并寫入文件&#xff08;shili域名版&#xff09;一、項目背景與功能簡介二、技術棧與核心組件2.1 主要技術2.2 功能模塊 三、核心代碼解析3.1 主函數邏輯&#xff08;流程控制&#xff09;3.2 拼音轉換模塊&#xff08;核心功…