ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Haystack PreProcessors API 全解:文档清洗与切分组件的参数、源码实现与工程选型

Haystack PreProcessors API 全解:文档清洗与切分组件的参数、源码实现与工程选型 Haystack PreProcessors API 全解文档清洗与切分组件的参数、源码实现与工程选型【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack本文系统讲解 Haystack 框架haystack.components.preprocessors模块PreProcessors API的全部组件DocumentSplitter、DocumentCleaner、DocumentPreprocessor、RecursiveDocumentSplitter、HierarchicalDocumentSplitter、CSVDocumentSplitter、CSVDocumentCleaner与TextCleaner。文章以版本 2.20 的 PreProcessors API 参考文档preprocessors_api.md为主体结合当前仓库源码haystack/components/preprocessors/逐参数展开每个组件的完整初始化参数、run()的输入输出契约、内部处理顺序与底层算法以及各组件在 RAG 索引流水线中的选型建议。1. 模块总览清洗、切分与结构化三类组件PreProcessors 是 Haystack 索引流水线中的核心预处理层官方定位是 “Preprocess your Documents and texts. Clean, split, and more.”清洗文档与文本清理、切分等。从 haystack/components/preprocessors/init.py 的导入结构看当前仓库共暴露 11 个组件组件职责输入 → 输出DocumentSplitter按单位词/行/句/页/自定义函数等切分长文档list[Document]→list[Document]DocumentCleaner清洗文档文本空白、空行、子串、正则、页眉页脚等list[Document]→list[Document]DocumentPreprocessor先切分再清洗的 SuperComponent 组合list[Document]→list[Document]RecursiveDocumentSplitter按分隔符列表递归降粒度切分list[Document]→list[Document]HierarchicalDocumentSplitter生成多级块大小的层级树结构list[Document]→list[Document]CSVDocumentCleaner删除 CSV 中的空行/空列list[Document]→list[Document]CSVDocumentSplitter按空行/空列阈值把 CSV 拆成子表list[Document]→list[Document]TextCleaner清洗纯字符串正则、小写、标点、数字list[str]→list[str]除上述 8 个组件外当前源码还新增了EmbeddingBasedDocumentSplitter、MarkdownHeaderSplitter、PythonCodeSplitter见 embedding_based_document_splitter.py、markdown_header_splitter.py、python_code_splitter.py它们不在 2.20 API 文档范围内此处不展开。所有 Document 级组件都遵循统一的组件契约run(documents: list[Document]) - dict[str, list[Document]]通过component.output_types(documentslist[Document])声明输出 socket可直接用Pipeline.connect()串联。2. DocumentCleaner文本清洗的处理顺序与参数详解2.1 功能与可运行示例DocumentCleaner清洗 Document 的文本内容按固定顺序移除多余空白、空行、指定子串、正则匹配内容、页眉页脚。文档给出的最小示例可直接运行from haystack import Document from haystack.components.preprocessors import DocumentCleaner doc Document(contentThis is a document to clean\n\n\nsubstring to remove) cleaner DocumentCleaner(remove_substrings[substring to remove]) result cleaner.run(documents[doc]) assert result[documents][0].content This is a document to clean 2.2 完整参数表DocumentCleaner.__init__document_cleaner.py#L42-L55的 2.20 参数如下参数类型默认值说明remove_empty_linesboolTrue移除空行以及纯空白行remove_extra_whitespacesboolTrue压缩连续空白为单个空格remove_repeated_substringsboolFalse移除每页重复出现的子串页眉/页脚keep_idboolFalse是否保留原始 Document IDremove_substringslist[str] \| NoneNone要原样删除的子串列表remove_regexstr \| NoneNone匹配后将匹配内容替换为空串的正则unicode_normalizationNFC\|NFKC\|NFD\|NFKD \| NoneNone应用的 Unicode 规范化形式最先执行ascii_onlyboolFalse转为纯 ASCII带音符字符转为 ASCII 近似其余非 ASCII 字符直接删除源码补充当前版本新增参数当前仓库的DocumentCleaner还接受strip_whitespaces: bool False只去掉首尾空白、保留内部空白适合保留 Markdown 排版、replace_regexes: dict[str, str] | None None正则→替换串映射可做自定义替换而非仅删除如{r\n\n: \n}与min_content_length: int 0清洗后内容短于该长度的文档会被整体丢弃。2.3 源码中的真实执行顺序文档强调“unicode_normalization 先于其他步骤执行”“ascii_only 先于任何模式匹配”这一顺序在run()中得到印证document_cleaner.py#L136-L165unicode_normalization→ 调用unicodedata.normalize(form, text)ascii_only→ 实现是normalize(NFKD, text).encode(ascii, ignore)即先 NFKD 分解把音符从基础字符分离再丢弃无法编码的字符见_ascii_onlydocument_cleaner.py#L191-L204remove_extra_whitespaces→ 正则\s\s替换为单空格remove_empty_lines→ 逐行strip()过滤空行remove_substrings→ 逐个子串str.replace(sub, )remove_regex→re.sub(regex, , text)remove_repeated_substrings→ 页眉/页脚启发式删除当前版本strip_whitespaces→ 首尾strip()。几个值得注意的实现细节页面感知的清洗_remove_empty_lines、_remove_extra_whitespaces、_remove_regex都先text.split(\f)按分页符处理再重新用\f拼接。因此页眉页脚功能依赖“页面以分页符\f分隔”这一约定——文档明确说明TextFileToDocument和AzureOCRDocumentConverter这类转换器会输出\f分隔的页面若上游转换器不产生\fremove_repeated_substrings无从区分“页”。页眉页脚启发式_find_and_remove_header_footerdocument_cleaner.py#L280-L317在每页开头 300 字符内找页眉、结尾 300 字符内找页脚算法是在所有页面忽略首尾页的候选片段集合上求“最长公共 n-gram”n 取 3~30 个单词。源码注释坦承该启发式是精确匹配对 “Copyright 2019 by XXX” 这类固定页脚有效但无法识别 “Page 3 of 4” 这种逐页变化的页脚。输入校验run()会检查输入是list[Document]否则抛TypeErrorcontent is None的文档只记录警告并原样透传不会中断批次。输出元数据清洗后文档默认生成新 IDkeep_idFalse时blob、meta深拷贝、score、embedding、sparse_embedding字段都会保留。3. DocumentSplitter单位、窗口、阈值与元数据3.1 功能定位DocumentSplitter是索引阶段最常用的切分器目标是让 Embedder 生成有意义的语义向量、并防止超出语言模型上下文窗口。API 文档还列出了它对各 Document Store 的兼容情况Astra、Chroma有限支持不存储重叠信息、Elasticsearch、OpenSearch、Pgvector、Pinecone有限支持不存储重叠信息、Qdrant、Weaviate。可运行示例from haystack import Document from haystack.components.preprocessors import DocumentSplitter doc Document(contentMoonlight shimmered softly, wolves howled nearby, night enveloped everything.) splitter DocumentSplitter(split_byword, split_length3, split_overlap0) result splitter.run(documents[doc])3.2 完整参数表DocumentSplitter.__init__的 2.20 参数document_splitter.py#L59-L73参数类型默认值说明split_byLiteral[function,page,passage,period,word,line,sentence]word切分单位split_lengthint200每个切片的最大单位数split_overlapint0相邻切片之间的重叠单位数split_thresholdint0切片最小单位数不足的切片并入上一个splitting_functionCallable[[str], list[str]] \| NoneNonesplit_byfunction时必填的自定义切分函数respect_sentence_boundaryboolFalse按词切分时尽量不切在句子中间依赖 NLTKlanguageLanguageenNLTK 分句器使用的语言use_split_rulesboolTrue分句时是否启用附加切分规则extend_abbreviationsboolTrue用 curated 缩写表扩展 NLTK PunktTokenizer当前支持 en/deskip_empty_documentsboolTrue是否跳过空内容文档当下游如LLMDocumentContentExtractor还能从非文本文档抽取文本时应设为False源码补充当前版本新增当前仓库新增了split_bytoken模式与tokenizer_encoding: str o200k_base参数——按 tiktoken token 数切分warm_up()时加载tiktoken.get_encoding(...)需要pip install tiktoken。split_by各单位的底层映射document_splitter.py#L23page→\f分页符、passage→\n\n双换行、period→.、word→空格、line→\nsentence走 NLTK 分句器function走自定义函数。3.3 核心算法滑动窗口 阈值合并字符类切分page/passage/period/word/line统一走_concatenate_unitsdocument_splitter.py#L379-L425用more_itertools.windowed(elements, nsplit_length, stepsplit_length - split_overlap)做滑动窗口窗口宽度split_length、步长split_length - split_overlap重叠由此精确实现若某窗口内单位数少于split_threshold且已有前序切片则只把超出重叠部分的文本追加到上一个切片避免产生碎片切片同时保证合并后的 chunk 仍能在原文中连续找到不会重复拼接重叠文本逐窗口累计\f计数维护页码。respect_sentence_boundaryTrue时走另一条路径_concatenate_sentences_based_on_word_amountdocument_splitter.py#L517-L584先 NLTK 分句再以“词数”为预算把整句拼入当前 chunk——下一句会使 chunk 超过split_length才落刀重叠用_number_of_sentences_to_keep反向累计整句数实现保证重叠以整句为单位。参数校验_init_checksdocument_splitter.py#L133-L173要求split_length 0、0 split_overlap split_lengthsplit_byfunction但没传splitting_function直接ValueErrorrespect_sentence_boundary仅在split_byword下生效其他取值会告警并自动置回False。3.4 输出元数据与重叠信息run()要求输入是list[Document]否则TypeError内容None抛ValueError。每个切片的meta由_create_docs_from_splitsdocument_splitter.py#L427-L456写入source_id原始文档 IDpage_number切片起始页码从 1 计split_id切片序号split_idx_start切片在原文中的字符偏移原meta其余字段全部深拷贝继承_split_overlap仅当split_overlap 0时写入双向记录相邻切片重叠的doc_id与range供下游 Joiner 恢复上下文用。切分器支持to_dict()/from_dict()序列化document_splitter.py#L483-L515其中splitting_function通过serialize_callable/deserialize_callable做可调用对象序列化因此整条 Pipeline 可存入 YAML。4. DocumentPreprocessor先切分、后清洗的 SuperComponentDocumentPreprocessor是一个super_component内部由DocumentSplitterDocumentCleaner组成一条子 Pipelinesplitter.documents → cleaner.documents对外只暴露一个documents输入 socket 和一个documents输出 socket。示例from haystack import Document from haystack.components.preprocessors import DocumentPreprocessor doc Document(contentI love pizza!) preprocessor DocumentPreprocessor() result preprocessor.run(documents[doc]) print(result[documents])完整参数2.20 文档口径分两组Splitter 参数split_by默认word、split_length默认 250注意与DocumentSplitter单独的默认值 200 不同、split_overlap0、split_threshold0、splitting_functionNone、respect_sentence_boundaryFalse、languageen、use_split_rulesTrue、extend_abbreviationsTrueCleaner 参数remove_empty_linesTrue、remove_extra_whitespacesTrue、remove_repeated_substringsFalse、keep_idFalse、remove_substringsNone、remove_regexNone、unicode_normalizationNone、ascii_onlyFalse。源码实现document_preprocessor.py#L109-L150值得注意两点它不是简单转发参数而是真正实例化两个子组件并Pipeline.connect(splitter.documents, cleaner.documents)再通过input_mapping {documents: [splitter.documents]}与output_mapping {cleaner.documents: documents}定义对外 socket 映射to_dict()/from_dict()把整组参数扁平化序列化splitting_function同样经 callable 序列化反序列化时重建内部 Pipeline。这意味着在 Pipeline 中它既是一个节点可整体连线又是一个含子图的可序列化单元。若只想用默认行为DocumentPreprocessor()等价于“按 250 词切分 去空行/压缩空白”的索引前置件。5. RecursiveDocumentSplitter按分隔符递归降粒度5.1 算法原理RecursiveDocumentSplitter按分隔符列表的顺序递归切分先按最粗的分隔符切凡仍超过split_length的 chunk再交给列表中的下一个分隔符直到所有 chunk 达标。默认分隔符为[\n\n, sentence, \n, ]——段落 → 句子 → 行 → 空格。特殊值sentence不是正则而是触发基于 NLTK 的自定义分句器SentenceSplitter见 sentence_tokenizer.py。文档的完整示例from haystack import Document from haystack.components.preprocessors import RecursiveDocumentSplitter chunker RecursiveDocumentSplitter(split_length260, split_overlap0, separators[\n\n, \n, ., ]) text (Artificial intelligence (AI) - Introduction AI, in its broadest sense, is intelligence exhibited by machines, particularly computer systems. AI technology is widely used throughout industry, government, and science. Some high-profile applications include advanced web search engines; recommendation systems; interacting via human speech; autonomous vehicles; generative and creative tools; and superhuman play and analysis in strategy games.) chunker.warm_up() doc Document(contenttext) doc_chunks chunker.run([doc]) print(doc_chunks[documents])5.2 参数与约束参数类型默认值说明split_lengthint200每个 chunk 的最大长度split_overlapint0相邻 chunk 的重叠单位数split_unitLiteral[word,char,token]wordsplit_length的计量单位token使用 tiktokeno200k_base编码separatorslist[str] \| NoneNone→[\n\n,sentence,\n, ]分隔符列表字符串按正则处理sentence例外sentence_splitter_paramsdict[str, Any] \| NoneNone→{keep_white_spaces: True}传给SentenceSplitter的参数约束_check_paramsrecursive_splitter.py#L113-L121split_length 1、split_overlap 0且 split_length、所有分隔符必须是字符串否则ValueError。5.3 warm_up 契约与重叠实现必须预热当separators含sentence或split_unittoken时未调用warm_up()就run()会抛RuntimeError。warm_up()recursive_splitter.py#L100-L111负责按需构建 NLTK 分句器与 tiktoken 编码器重叠是后处理切分先按分隔符产出无重叠 chunks再由_apply_overlaprecursive_splitter.py#L154-L200把前一个 chunk 的末尾单位拼接到下一个 chunk 开头若拼接后超出split_length超出的部分会被修剪并转移到下一个 chunk递归直到合法输出元数据每个 chunk 携带original_id原始文档 ID、split_id、split_idx_start、_split_overlap字段。与DocumentSplitter的区别在于DocumentSplitter 用单一单位 滑动窗口重叠严格等于split_overlap个单位RecursiveDocumentSplitter 用多级分隔符切点更贴近文本结构段落/句子优先重叠单位数由文本内容决定天然产生结构化程度更高的 chunk。6. HierarchicalDocumentSplitter多级块大小的树结构HierarchicalDocumentSplitter把文档切成多个块大小的 Document 集合形成一棵树根节点是原文档叶节点是最小块中间各层的小块是上一层大块的子块。文档示例from haystack import Document from haystack.components.preprocessors import HierarchicalDocumentSplitter doc Document(contentThis is a simple test document) splitter HierarchicalDocumentSplitter(block_sizes{3, 2}, split_overlap0, split_byword) splitter.run([doc]) # 输出 7 个 Document # level 0: 原文档parent_idNone, children_ids[...], block_size0 # level 1: 两个 3 词块This is a 、simple test document # level 2: 四个 2 词叶块This is 、a 、simple test 、document参数与约束hierarchical_document_splitter.py#L39-L72参数类型默认值说明block_sizesset[int]必填块大小集合按降序逐层切分不可为空split_overlapint0每层的重叠单位数必须小于min(block_sizes)split_byLiteral[word,sentence,page,passage]word各层共用的切分单位从源码看hierarchical_document_splitter.py#L87-L134_build_block_sizes()为每个块大小创建一个独立的DocumentSplitter实例层级机制完全复用了 DocumentSplitterbuild_hierarchy_from_doc()自顶向下逐层展开某节点被切出多于 1 个子块时子块写入层级 meta 并挂入下一层只切出 1 个块则停止展开该节点当前版本的层级元数据字段带双下划线前缀__block_size、__parent_id、__children_ids、__level2.20 文档中未带前缀叶块还继承source_id/page_number/split_id/split_idx_start。这类树结构适合“粗块检索、细块生成”或按层级扩展上下文的场景配合支持父子关联存储的 Document Store 使用。7. CSV 系列组件表格文档的清洗与拆表7.1 CSVDocumentCleanerCSVDocumentCleaner处理存于 Document 中的 CSV 内容删除整行为空/整列为空的行与列。__init__全参数参数类型默认值说明ignore_rowsint0处理前从表格顶部忽略的行数ignore_columnsint0处理前从表格左侧忽略的列数remove_empty_rowsboolTrue是否删除整行为空的行remove_empty_columnsboolTrue是否删除整列为空的列keep_idboolFalse输出 Document 是否保留原 ID关键语义文档原文强调容易踩坑被ignore_rows/ignore_columns忽略的行和列会原样保留在输出中即它们不参与“空行/空列”判定也不被删除。处理步骤为读取 CSV 表 → 固定忽略区 → 删除空行/空列 → 把忽略区拼回原位置 → 输出新 Document。7.2 CSVDocumentSplitterCSVDocumentSplitter把一个可能包含多张表以空行/空列分隔的 CSV Document 拆成若干子表 Documentdef __init__(row_split_threshold: Optional[int] 2, column_split_threshold: Optional[int] 2, read_csv_kwargs: Optional[dict[str, Any]] None, split_mode: SplitMode threshold) - Nonerow_split_threshold/column_split_threshold默认均为 2触发切分所需的连续空行/空列数read_csv_kwargs透传给pandas.read_csv。文档明确默认使用headerNone、skip_blank_linesFalse保留空行否则无法感知分隔、dtypeobject防止 pandas 类型推断把数字列转成 floatsplit_modethreshold默认按上述阈值切分row-wise则逐行拆成独立子表。切分流程若两个阈值均给出则先按行递归切、再按列递归切确保含空区的子表进一步碎片化最后按子表在原表中的位置排序。每个输出 Document 的 meta 包含source_id源文档 ID、row_idx_start、col_idx_start子表起点行列索引、split_id切分顺序号其余 meta 原样复制。无法解析的文档原样返回meta字段整体保留。8. TextCleaner面向评估的纯文本清洗TextCleaner处理list[str]而非 Document定位是“评估前清洗”去掉匹配正则的子串、转小写、去标点、去数字。示例from haystack.components.preprocessors import TextCleaner text_to_clean 1Moonlight shimmered softly, 300 Wolves howled nearby, Night enveloped everything. cleaner TextCleaner(convert_to_lowercaseTrue, remove_punctuationFalse, remove_numbersTrue) result cleaner.run(texts[text_to_clean])参数类型默认值说明remove_regexpslist[str] \| NoneNone要移除的正则列表convert_to_lowercaseboolFalse全部转小写remove_punctuationboolFalse移除标点remove_numbersboolFalse移除数字从源码看text_cleaner.py#L53-L83实现上有两处工程细节正则列表在__init__里re.compile(|.join(...), flagsre.IGNORECASE)预编译为单个正则运行时只做一次sub标点/数字删除通过str.maketrans(, , to_remove)构造查表翻译器string.punctuation/string.digits比逐字符正则扫描快得多。run()的固定执行顺序是正则移除 → 小写 → 翻译器删字符输出 key 为texts。9. 选型与版本对照小结按需求选组件通用 RAG 索引DocumentSplitter按词/句/页/自定义函数DocumentCleaner或直接用DocumentPreprocessor一步到位需要按 token 数精确控制 chunk 大小对齐模型上下文当前版本DocumentSplitter(split_bytoken, tokenizer_encodingo200k_base)或RecursiveDocumentSplitter(split_unittoken)长文结构化切分段落/句子优先RecursiveDocumentSplitter父子块/多级上下文HierarchicalDocumentSplitter表格CSV语料CSVDocumentCleanerCSVDocumentSplitter先行结构化再交给下游评估前的文本归一化TextCleaner。2.20 文档 vs 当前仓库源码的差异以当前仓库为准的增量能力DocumentSplitter新增split_bytoken与tokenizer_encoding参数document_splitter.py#L61-L73DocumentCleaner新增strip_whitespaces、replace_regexes、min_content_length参数DocumentPreprocessor同步透传tokenizer_encoding模块新增EmbeddingBasedDocumentSplitter、MarkdownHeaderSplitter、PythonCodeSplitter三个组件HierarchicalDocumentSplitter的层级 meta 字段更名为__block_size、__parent_id、__children_ids、__level。引用 2.20 API 文档中的参数与行为时请以上文各参数表为基准引用当前仓库能力时请以 haystack/components/preprocessors/ 下的实现为准相关测试位于 test/components/ 目录可按组件文件名检索对应行为用例。统一契约再强调所有 Document 级 Preprocessor 的run()都返回{documents: [...]}TextCleaner 返回{texts: [...]}。输出 Document 的meta会携带source_id/page_number/split_id/split_idx_startCSV 系组件为source_id/row_idx_start/col_idx_start/split_id这是下游按来源回溯、按页定位与重叠恢复的基础接线时无需额外标注。【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表