深入理解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都能帮助你轻松应对。

猜你喜欢

转载自blog.csdn.net/engchina/article/details/143318366