Spring AI:ETL Pipeline

提取、转换和加载(ETL)框架是检索增强生成(RAG)用例中数据处理的支柱。

ETL管道协调从原始数据源到结构化向量存储的流程,确保数据以最佳格式供AI模型检索。

RAG用例是文本,通过从数据体中检索相关信息来增强生成模型的能力,从而提高生成输出的质量和相关性。

API Overview

ETL管道创建、转换和存储Document实例。

Document类包含文本、元数据以及可选的其他媒体类型,如图像、音频和视频。

ETL管道有三个主要组件,

实施供应商列表的DocumentReader

实现函数<List<Document>、List<Document>>的DocumentTransformer

实现消费者<List<Document>>的DocumentWriter

Document类内容是在DocumentReader的帮助下从PDF、文本文件和其他文档类型创建的。

要构建一个简单的ETL管道,您可以将每种类型的实例链接在一起。

假设我们有这三种ETL类型的以下实例

PagePdfDocumentReader——DocumentReader的一种实现

TokenTextSplitter——DocumentTransformer的一种实现

DocumentWriter的矢量存储实现

要将数据基本加载到矢量数据库中,以便与检索增强生成模式一起使用,请使用以下Java函数样式语法代码。

vectorStore.accept(tokenTextSplitter.apply(pdfReader.get()));

或者,您可以使用更自然地表达域的方法名

vectorStore.write(tokenTextSplitter.split(pdfReader.read()));

ETL Interfaces

ETL管道由以下接口和实现组成。详细的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 Class Diagram

以下类图说明了ETL接口和实现。

DocumentReaders

JSON

JsonReader处理JSON文档,将其转换为Document对象列表。

Example
@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();}
}
Constructor Options

JsonReader提供了几个构造函数选项:

Parameters

resource:一个指向JSON文件的Spring resource对象。

jsonKeysToUse:JSON中的一组键,应用作生成的Document对象中的文本内容。

jsonMetadataGenerator:一个可选的jsonMetadataGenerator,用于为每个文档创建元数据。

Behavior

JsonReader按如下方式处理JSON内容:

它可以处理JSON数组和单个JSON对象。

对于每个JSON对象(数组或单个对象):

它根据指定的jsonKeysToUse提取内容。

如果没有指定键,它将使用整个JSON对象作为内容。

它使用提供的JsonMetadataGenerator(如果没有提供,则为空)生成元数据。

它使用提取的内容和元数据创建一个Document对象。

Using JSON Pointers

JsonReader现在支持使用JSON指针检索JSON文档的特定部分。此功能允许您轻松地从复杂的JSON结构中提取嵌套数据。

The get(String pointer) method
public List<Document> get(String pointer)

此方法允许您使用JSON指针来检索JSON文档的特定部分。

Parameters

指针:JSON指针字符串(如RFC 6901中定义的),用于在JSON结构中定位所需的元素。

Return Value

返回一个List<Document>,其中包含从指针所在的JSON元素解析的文档。

Behavior

该方法使用提供的JSON指针导航到JSON结构中的特定位置。

如果指针有效并指向现有元素:

对于JSON对象:它返回一个包含单个Document的列表。

对于JSON数组:它返回一个文档列表,数组中的每个元素对应一个文档。

如果指针无效或指向不存在的元素,则会抛出IllegalArgumentException。

Example
JsonReader jsonReader = new JsonReader(resource, "description");
List<Document> documents = this.jsonReader.get("/store/books/0");
Example JSON Structure
[{"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对象,其中内容是数组中每个自行车的“descriptions”字段的值。

Notes

JsonReader使用Jackson进行JSON解析。

通过使用数组流,它可以有效地处理大型JSON文件。

如果在jsonKeysToUse中指定了多个键,则内容将是这些键的值的连接。

阅读器很灵活,可以通过定制jsonKeysToUse和JsonMetadataGenerator来适应各种JSON结构。

Text

TextReader处理纯文本文档,将其转换为Document对象列表。

Example
@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();}
}
Constructor Options

TextReader提供了两个构造函数选项:

Parameters

resourceUrl:表示要读取的资源的URL的字符串。

resource:指向文本文件的Spring resource对象。

Configuration

setCharset(字符集字符集):设置用于读取文本文件的字符集。默认值为UTF-8。

getCustomMetadata():返回一个可变映射,您可以在其中为文档添加自定义元数据。

Behavior

TextReader按如下方式处理文本内容:

它将文本文件的全部内容读取到单个Document对象中。

文件的内容成为文档的内容。

元数据会自动添加到文档中:

charset:用于读取文件的字符集(默认值:“UTF-8”)。

source:源文本文件的文件名。

通过getCustomMetadata()添加的任何自定义元数据都包含在文档中。

Notes

TextReader将整个文件内容读入内存,因此它可能不适合非常大的文件。

如果你需要将文本拆分成更小的块,你可以在阅读文档后使用TokenTextSplitter这样的文本拆分器:

List<Document> documents = textReader.get();
List<Document> splitDocuments = new TokenTextSplitter().apply(this.documents);

阅读器使用Spring的资源抽象,允许它从各种源(类路径、文件系统、URL等)读取。

可以使用getCustomMetadata()方法将自定义元数据添加到阅读器创建的所有文档中。

HTML (JSoup)

JsoupDocumentReader处理HTML文档,使用JSoup库将其转换为Document对象列表。

Example
@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允许您自定义JsoudDocumentReader的行为:

charset:指定HTML文档的字符编码(默认为“UTF-8”)。

selector:一个JSoup CSS选择器,用于指定从哪些元素中提取文本(默认为“body”)。

分隔符:用于连接来自多个选定元素的文本的字符串(默认为“\n”)。

allElements:如果为true,则从<body>元素中提取所有文本,忽略选择器(默认为false)。

groupByElement:如果为true,则为选择器匹配的每个元素创建一个单独的Document(默认为false)。

includeLinkUrls:如果为true,则提取绝对链接URL并将其添加到元数据中(默认为false)。

元数据标签:从中提取内容的<meta>标签名称列表(默认为[“description”,“keywords”])。

additionalMetadata:允许您向所有创建的Document对象添加自定义元数据。

Sample Document: my-page.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>My Web Page</title><meta name="description" content="A sample web page for Spring AI"><meta name="keywords" content="spring, ai, html, example"><meta name="author" content="John Doe"><meta name="date" content="2024-01-15"><link rel="stylesheet" href="style.css">
</head>
<body><header><h1>Welcome to My Page</h1></header><nav><ul><li><a href="/">Home</a></li><li><a href="/about">About</a></li></ul></nav><article><h2>Main Content</h2><p>This is the main content of my web page.</p><p>It contains multiple paragraphs.</p><a href="https://www.example.com">External Link</a></article><footer><p>&copy; 2024 John Doe</p></footer>
</body>
</html>

行为:

JsoupDocumentReader处理HTML内容,并根据配置创建Document对象:

选择器确定哪些元素用于文本提取。

如果allElements为true,则<body>中的所有文本都将提取到一个文档中。

如果groupByElement为true,则与选择器匹配的每个元素都会创建一个单独的文档。

如果allElements和groupByElement都不为true,则使用分隔符连接与选择器匹配的所有元素的文本。

文档标题、来自指定<meta>标签的内容和(可选)链接URL将添加到文档元数据中。

用于解析相对链接的基本URI将从URL资源中提取。

阅读器保留所选元素的文本内容,但删除其中的任何HTML标签。

Markdown

MarkdownDocumentReader处理Markdown文档,将其转换为Document对象列表。

Example
@Component
class MyMarkdownReader {private final Resource resource;MyMarkdownReader(@Value("classpath:code.md") Resource resource) {this.resource = resource;}List<Document> loadMarkdown() {MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder().withHorizontalRuleCreateDocument(true).withIncludeCodeBlock(false).withIncludeBlockquote(false).withAdditionalMetadata("filename", "code.md").build();MarkdownDocumentReader reader = new MarkdownDocumentReader(this.resource, config);return reader.get();}
}

MarkdownDocumentReaderConfig允许您自定义MarkdownDocumentReader的行为:

horizontalRuleCreateDocument:当设置为true时,Markdown中的水平规则将创建新的Document对象。

includeCodeBlock:当设置为true时,代码块将与周围的文本包含在同一个文档中。如果为false,代码块将创建单独的Document对象。

includeBlockquote:当设置为true时,blockquotes将与周围的文本包含在同一个文档中。如果为false,blockquotes将创建单独的Document对象。

additionalMetadata:允许您向所有创建的Document对象添加自定义元数据。

Sample Document: code.md
This is a Java sample application:```java
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
```Markdown also provides the possibility to `use inline code formatting throughout` the entire sentence.---Another possibility is to set block code without specific highlighting:```
./mvnw spring-javaformat:apply
```

行为:MarkdownDocumentReader处理Markdown内容,并根据配置创建Document对象:

标头将成为Document对象中的元数据。

段落成为Document对象的内容。

代码块可以分离为自己的Document对象,也可以包含在周围的文本中。

块引号可以分隔成自己的Document对象,也可以包含在周围的文本中。

水平规则可用于将内容拆分为单独的文档对象。

阅读器在Document对象的内容中保留了内联代码、列表和文本样式等格式。

PDF Page

PagePdfDocumentReader使用Apache PdfBox库来解析PDF文档

使用Maven或Gradle将依赖项添加到您的项目中。

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>

或者保存到您的Gradle build.Gradle构建文件。

dependencies {implementation 'org.springframework.ai:spring-ai-pdf-document-reader'
}
Example
@Component
public class MyPagePdfDocumentReader {List<Document> getDocsFromPdf() {PagePdfDocumentReader pdfReader = new PagePdfDocumentReader("classpath:/sample1.pdf",PdfDocumentReaderConfig.builder().withPageTopMargin(0).withPageExtractedTextFormatter(ExtractedTextFormatter.builder().withNumberOfTopTextLinesToDelete(0).build()).withPagesPerDocument(1).build());return pdfReader.read();}}

PDF Paragraph

ParagraphPdfDocumentReader使用PDF目录(如TOC)信息将输入的PDF拆分为文本段落,并为每个段落输出一个文档。注意:并非所有PDF文档都包含PDF目录。

Dependencies

使用Maven或Gradle将依赖项添加到您的项目中。

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>

或者保存到您的Gradle build.Gradle构建文件。

dependencies {implementation 'org.springframework.ai:spring-ai-pdf-document-reader'
}
Example
@Component
public class MyPagePdfDocumentReader {List<Document> getDocsFromPdfWithCatalog() {ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader("classpath:/sample1.pdf",PdfDocumentReaderConfig.builder().withPageTopMargin(0).withPageExtractedTextFormatter(ExtractedTextFormatter.builder().withNumberOfTopTextLinesToDelete(0).build()).withPagesPerDocument(1).build());return pdfReader.read();}
}

Tika (DOCX, PPTX, HTML…)

TikaDocumentReader使用Apache Tika从各种文档格式中提取文本,如PDF、DOC/DOCX、PPT/PPTX和HTML。有关支持格式的完整列表,请参阅Tika文档。

Dependencies
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>

或者保存到您的Gradle build.Gradle构建文件。

dependencies {implementation 'org.springframework.ai:spring-ai-tika-document-reader'
}
Example
@Component
class MyTikaDocumentReader {private final Resource resource;MyTikaDocumentReader(@Value("classpath:/word-sample.docx")Resource resource) {this.resource = resource;}List<Document> loadText() {TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(this.resource);return tikaDocumentReader.read();}
}

Transformers

TextSplitter

TextSplitter是一个抽象基类,有助于划分文档以适应AI模型的上下文窗口。

TokenTextSplitter

TokenTextSplitter是TextSplitter的一种实现,它使用CL100K_BASE编码,根据令牌计数将文本分割成块。

Usage
@Component
class MyTokenTextSplitter {public List<Document> splitDocuments(List<Document> documents) {TokenTextSplitter splitter = new TokenTextSplitter();return splitter.apply(documents);}public List<Document> splitCustomized(List<Document> documents) {TokenTextSplitter splitter = new TokenTextSplitter(1000, 400, 10, 5000, true);return splitter.apply(documents);}
}
Constructor Options

TokenTextSplitter提供了两个构造函数选项:

Parameters

defaultChunkSize:每个文本块的目标大小(默认值:800)。

minChunkSizeChars:每个文本块的最小字符大小(默认值:350)。

minChunkLengthToEmbed:要包含的块的最小长度(默认值:5)。

maxNumChunks:从文本生成的最大块数(默认值:10000)。

keepSeparator:是否在块中保留分隔符(如换行符)(默认值:true)。

Behavior

TokenTextSplitter按如下方式处理文本内容:

Example
Document doc1 = new Document("This is a long piece of text that needs to be split into smaller chunks for processing.",Map.of("source", "example.txt"));
Document doc2 = new Document("Another document with content that will be split based on token count.",Map.of("source", "example2.txt"));TokenTextSplitter splitter = new TokenTextSplitter();
List<Document> splitDocuments = this.splitter.apply(List.of(this.doc1, this.doc2));for (Document doc : splitDocuments) {System.out.println("Chunk: " + doc.getContent());System.out.println("Metadata: " + doc.getMetadata());
}
Notes

TokenTextSplitter使用jtokkit库中的CL100K_BASE编码,该编码与较新的OpenAI模型兼容。

拆分器试图通过在可能的情况下打破句子边界来创建语义上有意义的块。

原始文档中的元数据被保留并复制到从该文档派生的所有块中。

如果copyContentFormatter设置为true(默认行为),则原始文档中的内容格式化程序(如果设置)也会复制到派生块。

此拆分器对于为具有令牌限制的大型语言模型准备文本特别有用,可确保每个块都在模型的处理能力范围内。

ContentFormatTransformer

确保所有文档的内容格式统一。

KeywordMetadataEnricher

KeywordMetadataEnricher是一个DocumentTransformer,它使用生成式AI模型从文档内容中提取关键字并将其添加为元数据。

Usage
@Component
class MyKeywordEnricher {private final ChatModel chatModel;MyKeywordEnricher(ChatModel chatModel) {this.chatModel = chatModel;}List<Document> enrichDocuments(List<Document> documents) {KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(this.chatModel, 5);return enricher.apply(documents);}
}
Constructor

KeywordMetadataEnricher构造函数接受两个参数:

Behavior

KeywordMetadataEnricher按如下方式处理文档:

Customization

可以通过修改类中的KEYWORDS_TEMPLATE常量来定制关键字提取提示。默认模板为:

\{context_str}. Give %s unique keywords for this document. Format as comma separated. Keywords:

其中{context_str}被替换为文档内容,%s被替换为指定的关键字计数。

Example
ChatModel chatModel = // initialize your chat model
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(chatModel, 5);Document doc = new Document("This is a document about artificial intelligence and its applications in modern technology.");List<Document> enrichedDocs = enricher.apply(List.of(this.doc));Document enrichedDoc = this.enrichedDocs.get(0);
String keywords = (String) this.enrichedDoc.getMetadata().get("excerpt_keywords");
System.out.println("Extracted keywords: " + keywords);
Notes

KeywordMetadataEnricher需要一个正常工作的ChatModel来生成关键字。

关键字计数必须为1或更大。

富集器将“excerpt_keywords”元数据字段添加到每个处理过的文档中。

生成的关键字以逗号分隔的字符串形式返回。

这种丰富器对于提高文档的可搜索性和为文档生成标签或类别特别有用。

SummaryMetadataEnricher

SummaryMetadataEnricher是一个DocumentTransformer,它使用生成式AI模型为文档创建摘要并将其添加为元数据。它可以为当前文档以及相邻文档(上一个和下一个)生成摘要。

Usage
@Configuration
class EnricherConfig {@Beanpublic SummaryMetadataEnricher summaryMetadata(OpenAiChatModel aiClient) {return new SummaryMetadataEnricher(aiClient,List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));}
}@Component
class MySummaryEnricher {private final SummaryMetadataEnricher enricher;MySummaryEnricher(SummaryMetadataEnricher enricher) {this.enricher = enricher;}List<Document> enrichDocuments(List<Document> documents) {return this.enricher.apply(documents);}
}
Constructor

SummaryMetadataEnricher提供了两个构造函数:

Parameters

chatModel:用于生成摘要的AI模型。

summaryTypes:SummaryType枚举值列表,指示要生成哪些摘要(上一个、当前、下一个)。

summaryTemplate:用于生成摘要的自定义模板(可选)。

元数据模式:指定在生成摘要时如何处理文档元数据(可选)。

Behavior

SummaryMetadataEnricher按如下方式处理文档:

section_summary:当前文档的摘要。

prev_section_summary:上一份文档的摘要(如果可用和要求)。

next_section_summary:下一个文档的摘要(如果可用和需要)。

Customization

摘要生成提示可以通过提供自定义摘要模板进行自定义。默认模板为:

"""
Here is the content of the section:
{context_str}Summarize the key topics and entities of the section.Summary:
"""
Example
ChatModel chatModel = // initialize your chat model
SummaryMetadataEnricher enricher = new SummaryMetadataEnricher(chatModel,List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));Document doc1 = new Document("Content of document 1");
Document doc2 = new Document("Content of document 2");List<Document> enrichedDocs = enricher.apply(List.of(this.doc1, this.doc2));// Check the metadata of the enriched documents
for (Document doc : enrichedDocs) {System.out.println("Current summary: " + doc.getMetadata().get("section_summary"));System.out.println("Previous summary: " + doc.getMetadata().get("prev_section_summary"));System.out.println("Next summary: " + doc.getMetadata().get("next_section_summary"));
}

提供的示例演示了预期的行为:

对于两个文档的列表,这两个文档都会收到section_summary。

第一个文档接收next_section_summary,但没有prevent_section_ssummary。

第二个文档收到上一个操作摘要,但没有下一个操作总结。

第一个文档的section_summary与第二个文档的previous_section_summary匹配。

第一个文档的next_section_summary与第二个文档的section_summary匹配。

Notes

SummaryMetadataEnricher需要一个正常工作的ChatModel来生成摘要。

富集器可以处理任何大小的文档列表,正确处理第一个和最后一个文档的边缘情况。

这种丰富器对于创建上下文感知摘要特别有用,可以更好地理解序列中的文档关系。

MetadataMode参数允许控制如何将现有元数据合并到摘要生成过程中。

Writers

File

FileDocumentWriter是一个DocumentWriter实现,它将文档对象列表的内容写入文件。

Usage
@Component
class MyDocumentWriter {public void writeDocuments(List<Document> documents) {FileDocumentWriter writer = new FileDocumentWriter("output.txt", true, MetadataMode.ALL, false);writer.accept(documents);}
}
Constructors

FileDocumentWriter提供了三个构造函数:

Parameters

fileName:要将文档写入的文件的名称。

withDocumentMarkers:是否在输出中包含文档标记(默认值:false)。

metadataMode:指定要写入文件的文档内容(默认值:metadataMode.NONE)。

append:如果为true,数据将写入文件末尾而不是开头(默认值:false)。

Behavior

FileDocumentWriter按如下方式处理文档:

Document Markers

当withDocumentMarkers设置为true时,编写器将按以下格式为每个文档添加标记:

### Doc: [index], pages:[start_page_number,end_page_number]
Metadata Handling

作者使用两个特定的元数据键:

page_number:表示文档的起始页码。

end_page_number:表示文档的结束页码。

这些用于编写文档标记。

Example
List<Document> documents = // initialize your documents
FileDocumentWriter writer = new FileDocumentWriter("output.txt", true, MetadataMode.ALL, true);
writer.accept(documents);

这将使用所有可用元数据将所有文档写入“output.txt”,包括文档标记,并在文件已存在的情况下附加到文件中。

Notes

编写器使用FileWriter,因此它使用操作系统的默认字符编码编写文本文件。

如果在写入过程中发生错误,将抛出RuntimeException,并将原始异常作为原因。

元数据模式参数允许控制如何将现有元数据合并到编写的内容中。

此编写器对于调试或创建文档集合的人类可读输出特别有用。

VectorStore

提供与各种矢量存储的集成。有关完整列表,请参阅Vector DB文档。

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

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

相关文章

26.安卓逆向2-frida hook技术-解密响应

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取码&#xff1…

人工智能与人工智障———仙盟创梦IDE

<!-- 桌面导航 -->&#x3C;nav class&#x22;hidden md:flex items-center space-x-8&#x22;&#x3E;&#x3C;a href&#x22;#home&#x22; class&#x22;nav-link text-gray-700 hover:text-primary font-medium&#x22;&#x3E;&#x9996;&…

车载通信架构 --- 以太网相关网络安全

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

行业实践案例:金融行业数据治理体系全景解析

“金融行业是数据治理的试金石。” ——高密度数据、高合规要求、高业务依赖,决定了金融治理的复杂度和先进性。 📘 本文目录 为什么金融行业对数据治理要求高? 金融行业数据治理的独特挑战 金融行业治理框架搭建实践 典型治理能力案例详解 工具与平台选型经验 总结与启示 …

C#读取modbus值,C#读写modbus,支持读写uint32值,Modbus TCP工具类

C#读取modbus值&#xff0c;C#读写modbus&#xff0c;支持读写uint32值&#xff1b;Modbus TCP工具类 需要首先安装nuget包Modbus using Modbus.Device; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; us…

Oracle注释详解

在Oracle SQL中&#xff0c;注释是用于解释代码逻辑、提高可读性的文本&#xff0c;不会被数据库执行。Oracle支持两种类型的注释语法&#xff1a; 1. 单行注释&#xff08;--&#xff09; 使用双连字符--在一行中添加注释&#xff0c;从--开始到行末的所有内容都会被视为注释。…

关于 scrapy框架 详解

scrapy 是一个纯 Python 编写的异步爬虫框架&#xff0c;具备以下特点&#xff1a;优势说明异步高效基于 Twisted&#xff0c;非阻塞 IO模块化各部分可灵活配置/替换中间件机制支持代理、UA、cookie 控制等强大的解析内置 XPath、CSS 提取器自动去重Scheduler 内部维护请求 fin…

DHCP中继实验及其核心原理

DHCP 中继&#xff08;DHCP Relay&#xff09;是一种允许跨网段分配 IP 地址的技术&#xff0c;无需在每个子网部署 DHCP 服务器。以下是其原理和配置方法的详细说明&#xff1a;一、核心原理1. 为什么需要 DHCP 中继&#xff1f;问题&#xff1a;DHCP 客户端通过广播&#xff…

ABP VNext + RediSearch:微服务级全文检索

ABP VNext RediSearch&#xff1a;微服务级全文检索 &#x1f680; &#x1f4da; 目录ABP VNext RediSearch&#xff1a;微服务级全文检索 &#x1f680;&#x1f4da; 一、背景与动机 &#x1f680;&#x1f6e0;️ 二、环境与依赖 &#x1f433;2.1 Docker Compose 启动 R…

TensorFlow深度学习实战——基于自编码器构建句子向量

TensorFlow深度学习实战——基于自编码器构建句子向量 0. 前言1. 句子向量2. 基于自编码器构建句子向量2.1 数据处理2.2 模型构建与训练 3. 模型测试相关链接 0. 前言 在本节中&#xff0c;我们将构建和训练一个基于长短期记忆 (Long Short Term Memory, LSTM) 的自编码器&…

C语言使用Protobuf进行网络通信

笔者前面博文Go语言网络游戏服务器模块化编程介绍了Go语言在开发网络游戏时如何进行模块化编程&#xff0c;在其中使用了Protobuf进行网络通信。在Protobuf官方实现中并没有生成C语言的实现&#xff0c;不过有一个开源的protobuf-c可以使用。 先来看看protobuf-c生成的代码&am…

vue3 随手笔记12--组件通信方式9/5--useAttrs

一 什么是useAttrsuseAttrs 是 Vue 3 Composition API 中提供的一个函数&#xff0c;它属于 Vue 的组合式 API 工具集的一部分。通过 useAttrs&#xff0c;你可以访问传递给组件但未被声明为 props 的所有属性。这对于处理非 prop 特性&#xff08;attributes&#xff09;特别有…

HumanRisk-自动化安全意识与合规教育平台方案

权威数据显示&#xff0c;74%以上的数据泄露与网络安全事件归根结底与人为因素有关&#xff0c;60%以上的网络安全事件是由内部人员失误造成的。这一现状揭示了一个核心命题&#xff1a;网络安全威胁正从技术漏洞转向“人为因素风险”。Gartner的调查发现&#xff0c;即便接受了…

2025年食品科学与健康大数据国际会议(SHBD 2025)

2025年食品科学与健康大数据国际会议 2025 International Conference on Food Science and Health Big Data&#xff08;一&#xff09;大会信息 会议简称&#xff1a;ICFSHBD 2025 大会地点&#xff1a;中国上…

CompareFace人脸识别算法环境部署

一、docker 安装 步骤1&#xff1a;启用系统功能 右键开始菜单 → 应用和功能 → 点击 程序和功能 → 勾选 Hyper-V 和 Windows子系统Linux 步骤2&#xff1a;获取安装包 访问Docker官网安装包下载页 &#xff0c;下载「Docker Desktop Installer.rar」压缩包 步骤3&#…

STM32固件升级设计——内部FLASH模拟U盘升级固件

目录 一、功能描述 1、BootLoader部分&#xff1a; 2、APP部分&#xff1a; 二、BootLoader程序制作 1、分区定义 2、 主函数 3、配置USB 4、配置fatfs文件系统 5、程序跳转 三、APP程序制作 四、工程配置&#xff08;默认KEIL5&#xff09; 五、运行测试 结束语…

操作系统引导过程

操作系统引导是指计算机利用 CPU 运行特定程序&#xff0c;通过程序识别硬盘&#xff0c;识别硬盘分区&#xff0c;识别硬盘分区上的操作系统&#xff0c;最后通过程序启动操作系统。 引导流程&#xff08;8步核心环节&#xff09; 1. 激活CPU 加电后CPU自动读取 ROM中的Boot…

Safetensors与大模型文件格式全面解析

Safetensors是一种专为存储大型张量数据设计的文件格式&#xff0c;由Hugging Face团队开发&#xff0c;旨在提供安全高效的模型参数存储解决方案。下面将详细介绍Safetensors格式及其特点&#xff0c;并全面梳理当前主流的大模型文件格式。 一、Safetensors格式详解 1. 基本概…

分布式理论:CAP、Base理论

目录 1、CAP理论 1.1、介绍 1.2、CAP的三种选择 1.3、CAP的注意事项 2、BASE理论 2.1、定义介绍 2.2、最终一致性的介绍 2.3、BASE的实现方式 2.4、与ACID的对比 3、CAP与BASE的联系 4、如何选择CAP 前言 在分布式系统中&#xff0c;CAP理论和BASE理论是指导系统设计…

【最新】飞算 JavaAl安装、注册,使用全流程,让ai自己给你写代码,解放双手

目录 飞算 JavaAl 产品介绍 安装飞算 JavaAl 第一步&#xff1a;点击 File->Setting 第二步&#xff1a;点击 Plugins 第三步&#xff1a;搜索 CalEx-JavaAI 第四步&#xff1a;点击 Install 进行安装 第五步&#xff1a;点击 Install &#xff0c;查看安装好的飞算…