深入理解RecursiveCharacterTextSplitter:文本分割的递归魔法
深入理解RecursiveCharacterTextSplitter:文本分割的递归魔法
- 1. 什么是RecursiveCharacterTextSplitter?
- 2. 如何使用RecursiveCharacterTextSplitter?
- 2.1 初始化
- 2.2 分割文本
- 2.3 示例
- 3. 内部工作原理
- 3.1 `_split_text`方法
- 3.2 `_merge_splits`方法
- 4. 总结
在处理文本数据时,我们经常需要将大段文本分割成更小的块(chunks),以便于后续的处理或分析。例如,在自然语言处理(NLP)任务中,我们可能需要将一篇文章分割成多个句子或段落,以便逐个处理。今天,我们将介绍一个强大的文本分割工具——RecursiveCharacterTextSplitter
,它能够根据指定的分隔符递归地将文本分割成小块。
1. 什么是RecursiveCharacterTextSplitter?
RecursiveCharacterTextSplitter
是一个Python类,用于将文本递归地分割成指定大小的块。它的核心思想是根据一组分隔符(separators)逐步分割文本,直到每个块的大小都符合预设的chunk_size
。如果某个块仍然过大,它会继续递归地分割,直到满足条件为止。
2. 如何使用RecursiveCharacterTextSplitter?
2.1 初始化
首先,我们需要初始化一个RecursiveCharacterTextSplitter
对象。在初始化时,我们可以指定以下参数:
separators
:一个字符串列表,表示用于分割文本的分隔符。默认值为["\n\n", "\n", " ", ""]
,即首先按段落分割,然后按行分割,最后按空格分割,如果都不行则按字符分割。chunk_size
:每个块的最大大小(以字符数为单位)。默认值为100。chunk_overlap
:块与块之间的重叠部分的大小。默认值为20。
from typing import List, Optional
import reclass RecursiveCharacterTextSplitter:def __init__(self, separators: Optional[List[str]] = None, chunk_size: int = 100, chunk_overlap: int = 20):self.separators = separators or ["\n\n", "\n", " ", ""]self.chunk_size = chunk_sizeself.chunk_overlap = chunk_overlap
2.2 分割文本
一旦初始化完成,我们就可以使用split_text
方法来分割文本。这个方法会返回一个字符串列表,每个字符串代表一个分割后的块。
text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
print(texts[1])
2.3 示例
假设我们有以下文本:
state_of_the_union = """
I Love English
I Love Chinese
I Love Math
"""
我们使用RecursiveCharacterTextSplitter
将其分割成块:
text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
print(texts[1])
输出结果可能是:
I Love English
I Love Chinese
I Love Chinese
I Love Math
可以看到,文本被成功分割成了两个块,并且块之间有一定的重叠。
3. 内部工作原理
3.1 _split_text
方法
_split_text
方法是RecursiveCharacterTextSplitter
的核心。它递归地使用分隔符分割文本,直到每个块的大小都符合chunk_size
。
def _split_text(self, text: str, separators: List[str]) -> List[str]:final_chunks = []separator = separators[-1]new_separators = []for s in separators:if s == "":separator = sbreakif re.search(re.escape(s), text):separator = snew_separators = separators[separators.index(s) + 1:]breaksplits = re.split(re.escape(separator), text)good_splits = []for s in splits:if len(s) < self.chunk_size:good_splits.append(s)else:if good_splits:final_chunks.extend(self._merge_splits(good_splits, separator))good_splits = []if not new_separators:final_chunks.append(s)else:final_chunks.extend(self._split_text(s, new_separators))if good_splits:final_chunks.extend(self._merge_splits(good_splits, separator))return final_chunks
3.2 _merge_splits
方法
_merge_splits
方法用于将分割后的块合并成符合chunk_size
的块,并确保块之间的重叠部分符合chunk_overlap
。
def _merge_splits(self, splits: List[str], separator: str) -> List[str]:docs = []current_doc = []total = 0for d in splits:if total + len(d) + (len(separator) if current_doc else 0) > self.chunk_size:if total > self.chunk_size:print(f"Warning: chunk size {total} exceeds {self.chunk_size}")if current_doc:docs.append(separator.join(current_doc))while total > self.chunk_overlap or (total + len(d) + (len(separator) if current_doc else 0) > self.chunk_size and total > 0):total -= len(current_doc[0]) + (len(separator) if len(current_doc) > 1 else 0)current_doc = current_doc[1:]current_doc.append(d)total += len(d) + (len(separator) if len(current_doc) > 1 else 0)if current_doc:docs.append(separator.join(current_doc))return docs
4. 总结
RecursiveCharacterTextSplitter
是一个非常实用的工具,特别适合处理大段文本的分割任务。通过递归地使用分隔符,它能够灵活地将文本分割成指定大小的块,并且支持块之间的重叠,确保信息的连续性。无论是处理长篇文章、日志文件还是其他类型的文本数据,RecursiveCharacterTextSplitter
都能帮助你轻松应对。