1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LangChainのText Splittersでドキュメントを分割しよう(RecursiveCharacterTextSplitter)

Last updated at Posted at 2024-10-20

はじめに

RAG(Retrieval-Augmented Generation)は、情報を効率的に取得し、それを基に応答を生成する手法です。このプロセスにおいて、大きなドキュメントを適切に分割し、関連する情報を迅速に取り出すことが非常に重要です。特に、テキストの分割方法は、検索効率や回答精度の向上に寄与するため、適切なツールの選択がカギとなります。
ここでは、LangChainライブラリに用意されているテキストを簡単に分割するための「Text Splitters」の中から、RecursiveCharacterTextSplitterの基本的な使い方とその実際の動作について詳しく見ていきます。

こちらも参考にして下さい

筆者のレベル

  • RAGについて基本的な理解を持っている
  • RAGを実装することで、さらに深く学びたいと考えている
  • プログラミング経験はあまりないが、RAGを実装してみたい
  • 実際にコードを作成して動かすことで、理解を深めていきたい

記載していること

  • RecursiveCharacterTextSplitterの基本的な説明
  • いくつかの設定パターンで動かしてみた結果

RecursiveCharacterTextSplitterの特徴

RecursiveCharacterTextSplitterは、再帰的に文字単位でテキストを分割する機能を持つText Splitterです。このツールを使用することで、文字列処理において、より効果的に情報を扱うことができます。以下に、RecursiveCharacterTextSplitterの主要なパラメータを説明します。

パラメータの説明

  • chunk_size: チャンクの最大サイズを指定します。このサイズに基づいてテキストが分割されます。

  • chunk_overlap: チャンク間のオーバーラップを指定します。これにより、前のチャンクと次のチャンクの一部が重複するようになります。

  • separators: 複数のセパレータを指定して、順に分割していきます。句点や改行などを含むリストで設定されます。

  • keep_separator:テキストを分割した際にセパレータをどのように扱うかを決定します。以下のオプションがあります。

    True または "end"

    • 説明: 各チャンクの最後にセパレータを保持します。

    "start"

    • 説明: 各チャンクの最初にセパレータを保持します。

    False

    • 説明: セパレータを削除します。

実装例

以下は、RecursiveCharacterTextSplitterの基本的な使い方の例です。

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

source_text = "あいうえお、かきくけこさしすせそ。"

chunk_size = 10
chunk_overlap = 2

recursive_char_text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=chunk_size,
    chunk_overlap=chunk_overlap,
    separators=['']
)

documents = recursive_char_text_splitter.split_text(source_text)

動かしてみる

ドキュメントの準備

このようなテキストファイルを用意します。

sample.txt
あいうえお。
かきくけこ。さしすせそ。
たちつてと。なにぬねの。はひふへほ。
まみむめも。やゆよ。らりるれろわをん。

①chunk_sizeとseparatorsを設定してみる

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

# テキストをロード
source_document = TextLoader('sample.txt').load()
source_text = source_document[0].page_content

# RecursiveCharacterTextSplitterを設定
recursive_char_text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=5,
    chunk_overlap=0,
    separators=['']
)

# 分割を実行
char_documents = recursive_char_text_splitter.split_text(source_text)

# 分割結果を表示
print('\nRecursiveCharacterTextSplitterによる分割結果: \n')
for i, chunk in enumerate(char_documents):
    print(f"Chunk {i+1} (Length: {len(chunk)}):\n{chunk}\n")

RecursiveCharacterTextSplitterによる分割結果:
セパレータは、チャンクの最初に保持されています。

Chunk 1 (Length: 5):
あいうえお

Chunk 2 (Length: 7):
。
かきくけこ

Chunk 3 (Length: 6):
。さしすせそ

Chunk 4 (Length: 7):
。
たちつてと

Chunk 5 (Length: 6):
。なにぬねの

Chunk 6 (Length: 6):
。はひふへほ

Chunk 7 (Length: 7):
。
まみむめも

Chunk 8 (Length: 4):
。やゆよ

Chunk 9 (Length: 9):
。らりるれろわをん

Chunk 10 (Length: 1):
。

②keep_separatorを設定してみる

# RecursiveCharacterTextSplitterを設定
recursive_char_text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=5,
    chunk_overlap=0,
    separators=[''],
    keep_separator="end"
)

RecursiveCharacterTextSplitterによる分割結果:
セパレータはチャンクの最後に保持されています。

Chunk 1 (Length: 6):
あいうえお。

Chunk 2 (Length: 7):

かきくけこ。

Chunk 3 (Length: 6):
さしすせそ。

Chunk 4 (Length: 7):

たちつてと。

Chunk 5 (Length: 6):
なにぬねの。

Chunk 6 (Length: 6):
はひふへほ。

Chunk 7 (Length: 7):

まみむめも。

Chunk 8 (Length: 4):
やゆよ。

Chunk 9 (Length: 9):
らりるれろわをん。

③chunk_overlapを設定してみる

chunk_sizeは10、chunk_overlapは2を設定してみます。

# RecursiveCharacterTextSplitterを設定
recursive_char_text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=10,
    chunk_overlap=2,
    separators=[''],
    keep_separator="end"
)

RecursiveCharacterTextSplitterによる分割結果:
オーバラップされていない・・・

Chunk 1 (Length: 6):
あいうえお。

Chunk 2 (Length: 6):
かきくけこ。

Chunk 3 (Length: 6):
さしすせそ。

Chunk 4 (Length: 6):
たちつてと。

Chunk 5 (Length: 6):
なにぬねの。

Chunk 6 (Length: 6):
はひふへほ。

Chunk 7 (Length: 6):
まみむめも。

Chunk 8 (Length: 4):
やゆよ。

Chunk 9 (Length: 9):
らりるれろわをん。

④chunk_sizeを変更してみる

セパレータをカウントしない長さ(chunk_size=5)に、チャンクサイズを設定します。

# RecursiveCharacterTextSplitterを設定
recursive_char_text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=5,
    chunk_overlap=2,
    separators=[''],
    keep_separator="end"
)

RecursiveCharacterTextSplitterによる分割結果:
chunk_size=5よりも大きなサイズで分割されてしまいます。

Chunk 1 (Length: 6):
あいうえお。

Chunk 2 (Length: 7):

かきくけこ。

Chunk 3 (Length: 6):
さしすせそ。

Chunk 4 (Length: 7):

たちつてと。

Chunk 5 (Length: 6):
なにぬねの。

Chunk 6 (Length: 6):
はひふへほ。

Chunk 7 (Length: 7):

まみむめも。

Chunk 8 (Length: 4):
やゆよ。

Chunk 9 (Length: 9):
らりるれろわをん。

⑤separatorsに空白文字('')を設定してみる

CharacterTextSplitterにおいて、セパレータに空白文字('')を設定しないと、適切にカウントされていないことを確認していたので、それを参考に空白文字('')を設定してみました。

# RecursiveCharacterTextSplitterを設定
recursive_char_text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=5,
    chunk_overlap=2,
    separators=['',''],
    keep_separator="end"
)

RecursiveCharacterTextSplitterによる分割結果:
一見、chunk_size、chunk_overlapともに、思った通りに分割されているように見えますが、オーバーラップしていないチャンクもあります。

Chunk 1 (Length: 5):
あいうえお

Chunk 2 (Length: 3):
えお。

Chunk 3 (Length: 4):
かきくけ

Chunk 4 (Length: 4):
くけこ。

Chunk 5 (Length: 5):
さしすせそ

Chunk 6 (Length: 3):
せそ。

Chunk 7 (Length: 4):
たちつて

Chunk 8 (Length: 4):
つてと。

Chunk 9 (Length: 5):
なにぬねの

Chunk 10 (Length: 3):
ねの。

Chunk 11 (Length: 5):
はひふへほ

Chunk 12 (Length: 3):
へほ。

Chunk 13 (Length: 4):
まみむめ

Chunk 14 (Length: 4):
むめも。

Chunk 15 (Length: 4):
やゆよ。

Chunk 16 (Length: 5):
らりるれろ

Chunk 17 (Length: 5):
れろわをん

Chunk 18 (Length: 3):
をん。

考察

チャンクサイズに分割する際に、指定した分割サイズまでにセパレータが存在しなければ、オーバーラップが機能するように見えます。
(必ずオーバーラップして欲しいのだが・・・)

まとめ

RAG(Retrieval-Augmented Generation)においては、文脈や意味の単位でテキストを分割することが、精度向上につながります。RecursiveCharacterTextSplitterを用いることで、指定したセパレータやチャンクサイズに基づいて、再帰的にテキストを効率よく分割できます。
ですが、思った通りに分割するには、もう少し工夫がいるのかもしれません。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?