深入理解RecursiveCharacterTextSplitter:文本分割的递归魔法
在处理文本数据时,我们经常需要将大段文本分割成更小的块(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 re
class 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_size
self.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 = s
break
if re.search(re.escape(s), text):
separator = s
new_separators = separators[separators.index(s) + 1:]
break
splits = 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 = 0
for 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
都能帮助你轻松应对。