導入
文字数で機械的に切ると、どうしても単語や文の途中でぶつ切りになりがちでした。文書には本来、段落や文という「意味のまとまり」があります。その切れ目で分ければ、チャンク1つ1つが読んでまとまりのある内容になります。
説明
import re
text = """RAG has two phases. First is indexing.
Second is retrieval and generation.
Chunking matters a lot. Small chunks are precise.
Large chunks keep more context."""
# 段落(空行)で分ける
paragraphs = [p.strip() for p in text.split("\n\n") if p.strip()]
print("Paragraphs:", len(paragraphs))
for p in paragraphs:
print(" -", repr(p))
# 文(. ! ?)で分ける
sentences = [s.strip() for s in re.split(r"(?<=[.!?])\s+", text) if s.strip()]
print("\nSentences:", len(sentences))
for i, s in enumerate(sentences):
print(f"[{i}] {s}")
段落分割は単純で、text.split("\n\n") で「空行」を区切りにしています。文分割はもう一段技巧的です。re.split(r"(?<=[.!?])\s+", text) は、「.・!・? の直後にある空白(改行も含む)」で区切る正規表現です。(?<=...) は「肯定後読み」と呼ばれる書き方で、区切り文字そのものは残したまま、その直後の空白だけを区切り目にできます。だから文末の . や ? はちゃんと各文に残ります。
実務では、文単位で切っただけだと短すぎる文がたくさんできてしまうことがあるので、目標のチャンクサイズに近づくまで隣の文をまとめる「再結合」もよく行います。ここでは仕組みの基本だけ押さえれば十分です。
これでチャンクへの分割は一通り学びました。次章では、こうして切ったチャンクをベクトル(数値の並び)に変換し、質問文と似ているチャンクを実際に検索する方法に進みます。
やってみよう
text の内容を書き換えて、段落数と文数がそれぞれどう変わるか確かめてみましょう。空行を増やしたり、! や ? で終わる文を足したりしてみてください。
演習
上のコードの sentences を使い、文の数(len(sentences))を print で表示してください。
ヒント1を見る
import re としてから、本文中の正規表現で sentences を作ります。
ヒント2を見る
最後に print(len(sentences)) を書きます。