Text Splitterの活用(分割戦略)

1. テキスト分割の目的と LlamaIndex パイプラインでの位置づけ

LLM は入力できるトークン数に上限があるため、大規模ドキュメントをそのまま扱うとコンテキストあふれや推論コストの増大を招きます。LlamaIndex では Document → Node → Index というデータフローを採用しており、Text Splitter は Document を「Node」と呼ばれるチャンクへ変換する要となります。チャンク化により (1) 検索用ベクトルの粒度が最適化され、(2) 生成時に関連コンテキストだけを LLM に渡せるため精度と速度が向上します。medium.com

2. Text Splitter と Node Parser の違い

  • Text Splitter … 純粋に文字列を「長さ」と「重複幅」で裁断する軽量クラス。

  • Node Parser … ドキュメント構造やメタデータを考慮しつつ内部で Text Splitter を呼び出す高機能クラス。
    MetadataAwareTextSplitter は両者の中間に位置し、メタデータも保持しながら分割できます。選択基準は「速度と単純さを取るか」「構造保持を取るか」です。github.com

3. 代表的な Text Splitter / Node Parser

分割器 主な用途 主要パラメータ 特徴
TokenTextSplitter 汎用テキスト chunk_size, chunk_overlap トークン数で裁断。高速だが文が切れる可能性あり。docs.llamaindex.ai
SentenceSplitter 自然言語文書 chunk_size, chunk_overlap, separator 文単位でできるだけ文脈を保つ。 文切れを低減。docs.llamaindex.aidocs.llamaindex.ai
MarkdownNodeParser Markdown, 技術記事 章見出し (#, ## …) をキーに階層分割 見出しパスを Node に保持し、構造を活かした検索が可能。docs.llamaindex.ai
SemanticSplitterNodeParser 学術論文・議事録 buffer_size, embed_model まず文を抽出→埋め込み類似度で意味的に近い文を束ねる。docs.llamaindex.ai
Code 系 (CodeTextSplitter など) ソースコード 言語ごとの関数/クラス境界 函数単位で切り、コメント保持。※外部 blog で紹介。blog.lancedb.com

4. パラメータ設計のポイント

chunk_size

  • LLM の コンテキスト長 ÷ 2 〜 3 を上限に設定すると、索引語+プロンプトを足しても安全域を確保できます。

  • 小さ過ぎると検索精度が落ち、大き過ぎると計算量が増える。

chunk_overlap

  • 境界近傍の文脈欠落を防ぐために 10 % 〜 20 % 程度を重複させるのが定石です。

  • GitHub Discussion でも overlap が 20〜50 トークン推奨との議論があります。github.com

5. 典型的な分割戦略

  1. フラット・トークン分割

    • TokenTextSplitter(chunk_size=1024, chunk_overlap=20)

    • シンプルで高速。ニュース記事など軽量ワークロード向け。

  2. 文セマンティック+オーバーラップ

    • SentenceSplitter(chunk_size=800, chunk_overlap=100)

    • レポートや長文ブログで文脈を保ちたい場合に適用。

  3. 階層(ヘッダ)分割 → 二次細分

    python
    md_splitter = MarkdownNodeParser() fine_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=64) nodes_lvl1 = md_splitter.split_documents(docs) nodes_final = sum((fine_splitter.split_nodes([n]) for n in nodes_lvl1), [])
    • 見出し単位で大枠を保持しつつ、サブチャンクを生成。

  4. 意味クラスタリング分割

    • SemanticSplitterNodeParser(embed_model=my_embedding, buffer_size=3)

    • トピック境界が曖昧な議事録・チャット履歴を、意味的まとまりで自動裁断。

6. 実装例:SimpleDirectoryReader への組み込み

python
from llama_index import SimpleDirectoryReader from llama_index.text_splitter import SentenceSplitter splitter = SentenceSplitter(chunk_size=800, chunk_overlap=100) documents = SimpleDirectoryReader( "./docs", encoding="utf-8", recursive=True, text_splitter=splitter # ★ここで指定 ).load_data()

これでフォルダ内ファイルが読み込まれるたびに自動でチャンク化され、documents には Node 群が格納されます。arsturn.com

7. カスタム Text Splitter を作る場合

  1. MetadataAwareTextSplitter を継承。

  2. split_text(self, text) で独自ロジックを実装(例:正規表現で章末を検出)。

  3. self._build_metadata(...) をオーバーライドすれば、分割点の章番号やページ番号を Node メタデータに付与できます。

  4. 実装後は my_splitter.split_documents(docs) で既存フローに簡単に組み込み可能です。

8. ベストプラクティスまとめ

  • 目的別に分割器を選択:自然文=Sentence、技術資料=Markdown、コード=Code。

  • chunk_size と overlap のチューニングは検索 ⇔ 生成のバランスで決定。

  • 階層 → 文脈 → 意味 の順で粒度を細かくする3段階戦略が最も汎用的。

  • 分割後は 平均トークン数分布を確認し、極端に短い/長い Node がないか検証する。

  • パフォーマンス測定には 同一クエリで Splitter を切り替え A/B テストを行い、RAG 精度と応答コストを比較する。

以上が LlamaIndex における Text Splitter 活用と分割戦略の詳細です。適切な分割器とパラメータ設計を行うことで、高精度かつ効率的な RAG パイプラインを構築できます。

ChatGPT4o 生成日:2025/06/14