この記事では、LlamaIndexでチャンク分割をするNode Parserの使い方について解説しています。
構文ベース、長さベース、意味ベース、リレーションベースのそれぞれに対応するパーサーを紹介し、テキストやドキュメントの効果的な分割方法を解説します。
LlamaIndexのNode Parser
LlamaIndexでは、テキストやデータを効果的にチャンク化するために、さまざまなノードパーサーが用意されています。
構文ベース、長さベース、意味ベース、リレーションベースといったなパーサーを活用することで、データの形式に応じた柔軟なチャンク分割が可能です。
この記事では各種パーサーについて詳しく解説しています。
- 構文ベースのNode Parser
- 長さベースNode Parser
- 意味ベースのNode Parser
- リレーションベースのNode Parser
構文ベースのNode Parser
構文ベースのノードパーサーは、テキストの構造に基づいてデータを分割する手法です。
HTMLやJSON、Markdownなど特定のフォーマットに従ってドキュメントを解析し、見出しや段落、タグに基づいてノード(チャンク)に分割します。
これにより文書構造を保持しながら、データを効率的に処理することができます。
構文ベースのノードパーサーは以下のようなものがあります。
- SimpleFileNodeParser
- HTMLNodeParser、
- JSONNodeParser
- MarkdownNodeParser
事前準備
パッケージをインストールします。
pip install llama_index llama-index-core
SimpleFile NodeParser
SimpleFileNodeParser は、さまざまな形式のファイルをシンプルにパースするためのクラスです。
ファイルから読み込まれたテキストデータを適切なサイズのチャンクに分割し、それをノードに変換する役割を担っています。
特定のフォーマットに依存せずにテキストを扱えるため、汎用性が高く柔軟に対応できます。
#SimpleFileNodeParser
from llama_index.core.node_parser import SimpleFileNodeParser
from llama_index.readers.file import FlatReader
from pathlib import Path
docs = FlatReader().load_data(Path("第1章_働き方改革の推進などを通じた労働環境の整備など.txt"))
parser = SimpleFileNodeParser()
nodes = parser.get_nodes_from_documents(docs)
nodes[0].text
'第1章 働き方改革の推進などを通じた労働環境の整備など\n\t 第1節\t 非正規雇用労働者の待遇改善、長時間労働の是正等\n\t1\t非正規雇用の現状と対策\n(1)非正規雇用の現状と課題\n近年、パートタイム労働者、有期雇用労働者、派遣労働者といった非正規雇用労働者は\n全体として増加傾向にあり、雇用者の約4割を占める状況にある。これは、高齢者が増え\nる中、高齢層での継続雇用により非正規雇用が増加していることや、女性を中心にパート\nなどで働き始める労働者が増加していることなどの要因が大きい。なお、新型コロナウイ\nルス感染症の感染拡大の影響もあり、2020(令和2)年、2021(令和3)年の非正規雇\n用労働者は対前年比で減少したが、2022(令和4)年以降は増加し、2023(令和5)年\nは、2,124万人となっている。\n非正規雇用労働者は、雇用が不安定、賃金が低い、能力開発機会が乏しいなどの課題が\nあり、正規雇用を希望しながらそれがかなわず、非正規雇用で働く者(不本意非正規雇用\n労働者)が9.6%(2023年)存在し、年齢階級別では25~34歳の若年層で13.1%(2023\n年)と高くなっている。一方、非正規雇用労働者の中には「自分の都合のよい時間に働き\nたいから」等の理由により自ら非正規雇用を選ぶ方もおり、多様な働き方が進む中で、ど\nのような雇用形態を選択しても納得が得られる処遇を受けられることが重要である。\n(2)非正規雇用労働者への総合的な対策の推進\n1 正社員転換・待遇改善の推進\n正社員を希望する方の正社員転換や非正規雇用を選択する方の待遇改善を推進するた\nめ、キャリアアップ助成金において、非正規雇用労働者の正社員転換、処遇改善の取組み\nを図る事業主に対して助成を行っている。\nまた、どのような働き方を選択しても公正な待遇を受けられるようにし、人々が自分の\n希望に合わせて多様な働き方を自由に選択できるようにすることが重要である。\n2020(令和2)年4月1日に施行された「短時間労働者及び有期雇用労働者の雇用管理\nの改善等に関する法律」(平成5年法律第76号。以下「パートタイム・有期雇用労働法」\nという。同法の中小企業への適用は2021(令和3)年4月1日。)及び「労働者派遣事業\nの適正な運営の確保及び派遣労働者の保護等に関する法律」(昭和60年法律第88号)で\nは、雇用形態にかかわらない公正な待遇の確保に向け、①不合理な待遇差を解消するため\nの規定の整備、②労働者に対する待遇に関する説明義務の強化、③行政による法の履行確\n保措置及び裁判外紛争解決手続(行政ADR)が整備された。\nフリーター等*1の正社員就職支援のため、「わかものハローワーク」(2024(令和6)年\n4月1日現在21か所)等を拠点に、担当者制による個別支援、正社員就職に向けたセミ\n*1 おおむね35歳未満で正社員での就職を希望する求職者
<以下省略>
FlatReader().load_data()
指定したテキストファイルを読み込み、テキストデータを返します。
parser = SimpleFileNodeParser()
SimpleFileNodeParser
のインスタンスを使用して、ファイルの内容を複数のノードに分割します。
nodes = parser.get_nodes_from_documents(docs)
読み込んだテキストデータdocs
をノードに分割します。結果は nodes
というリストに保存されます。
HTML NodeParser
HTMLNodeParser は、HTML文書を解析し、HTMLタグに基づいてテキストをチャンク(ノード)に分割するためのクラスです。
このパーサーは、HTML構造を理解し、指定されたタグ(例えば<p>
や <h1>
)を基準にテキストを分割します。
HTMLのメタデータもノードに含めることができ、構造化されたデータの扱いに便利です。
#HTMLNodeParser
import requests
from llama_index.core import Document
from llama_index.core.node_parser import HTMLNodeParser
url = "https://ja.wikipedia.org/wiki/%E5%8E%9A%E7%94%9F%E5%8A%B4%E5%83%8D%E7%9C%81"
response = requests.get(url)
print(response)
if response.status_code == 200:
html_doc = response.text
document = Document(id_=url, text=html_doc)
parser = HTMLNodeParser(tags=["p", "h1"])
nodes = parser.get_nodes_from_documents([document])
print(nodes)
else:
print("Failed to fetch HTML content:", response.status_code)
Response [200]>
[TextNode(id_='7ea74821-03a3-435a-93d1-415152a092ea', embedding=None, metadata={'tag': 'h1'}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='https://ja.wikipedia.org/wiki/%E5%8E%9A%E7%94%9F%E5%8A%B4%E5%83%8D%E7%9C%81', node_type=<ObjectType.DOCUMENT: '4'>, metadata={}, hash='33ad0f2335430d2596f98c31eb90646051448d37ee2a267f386d735ea0c5b971'), <NodeRelationship.NEXT: '3'>: RelatedNodeInfo(node_id='55e8868f-5021-4b6e-9aa8-021fc58c078a', node_type=<ObjectType.TEXT: '1'>, metadata={'tag': 'p'}, hash='1c798cb79adb44866e6431e2a5b24dd97f30b587c101ec697755fe738807a411')}, text='厚生労働省', mimetype='text/plain', start_char_idx=614, end_char_idx=619, text_template='{metadata_str}\n\n{content}', metadata_template='{key}: {value}', metadata_seperator='\n'), TextNode(id_='55e8868f-5021-4b6e-9aa8-021fc58c078a', embedding=None, metadata={'tag': 'p'}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='https://ja.wikipedia.org/wiki/%E5%8E%9A%E7%94%9F%E5%8A%B4%E5%83%8D%E7%9C%81', node_type=<ObjectType.DOCUMENT: '4'>, metadata={}, hash='33ad0f2335430d2596f98c31eb90646051448d37ee2a267f386d735ea0c5b971'), <NodeRelationship.PREVIOUS: '2'>: RelatedNodeInfo(node_id='7ea74821-03a3-435a-93d1-415152a092ea', node_type=<ObjectType.TEXT: '1'>, metadata={'tag': 'h1'}, hash='826fdfac59e2ad455a222e85cdabff72e36e9084c8ae8cbfd69288d79d43be83')}, text='厚生労働省\n(こうせいろうどうしょう、\n英\n:\nMinistry of Health, Labour and Welfare\n、略称:\nMHLW\n)は、\n日本\nの\n行政機関\nのひとつ\n[4]\n。\n健康\n、\n医療\n、\n福祉\n、\n介護\n、\n雇用\n、\n労働\n、および\n年金\nに関する\n行政\n[5]\nならびに\n復員\n、\n戦没者\n遺族\n等の援護、旧\n陸\n海軍\nの残務整理を所管する\n[注釈 1]\n。\n日本語\n略称・通称は、\n厚労省\n(こうろうしょう)。\n2001年\n(\n平成\n13年)1月の\n中央省庁再編\nにより、\n厚生省\nと\n労働省\nを統合して誕生した。予算規模は中央省庁の中で最大である。\n厚生労働省設置法第4条は計118項目の所掌する事務を列記している。具体的には以下の事項に関する事務がある。\n内部組織は一般的に、法律の厚生労働省設置法、政令の厚生労働省組織令及び省令の厚生労働省組織規則が階層的に規定している。\n\n当省の\n施設等機関\nは以下の7区分がある。国立児童自立支援施設(現在はこども家庭庁に移管)および国立障害者リハビリテーションセンター\n[注釈 6]\nは慣例上、「国立更生援護機関」と総称される。\n厚生労働省検疫所\nは以下の13検疫所の下に14支所と80出張所が置かれている。\n地方支分部局\nは地方厚生局と都道府県労働局の2区分がある。都道府県労働局は47各都道府県に1つ設置されている。\n太字\nは人事ブロック基幹局\n(北海道・宮城・埼玉・東京・新潟・愛知・大阪・広島・香川・福岡)\n主管する\n独立行政法人\nは2024年4月1日現在、以下に示す通り、\n中期目標管理法人\n10、\n国立研究開発法人\n7の計17法人である\n[9]\n)。\n行政執行法人\nは所管しない。\n国立病院機構は、以前は役職員が\n国家公務員\nである「特定独立行政法人(現・行政執行法人)」であったが、\n独立行政法人通則法\nの改正法(平成26年6月13日法律第66号)施行に伴い、2015年(平成27年)4月1日から中期目標管理法人となり、役職員は国家公務員ではなくなった。\n主管する特殊法人は2024年(令和6年)4月1日現在、\n日本年金機構\n(年金局)のみである\n[10]\n。旧\n社会保険庁\nの後身にあたる。なお、2025年4月に国立感染症研究所と国立国際医療研究センターを統合して特殊法人として国立健康危機管理研究機構が設立される\n[11]\n。\n特別の法律により設立される民間法人\n(特別民間法人)には2024年(令和6年)4月1日現在、以下の11法人である\n[12]\n。以前は労働基準局所管の\n鉱業労働災害防止協会\n(略称:鉱災防)があったが、2014年(平成26年)3月31日に解散した。全国健康保険協会は、現在の資料では特別の法律により設立される法人ではなく、特別の法律により設立される民間法人とされている。\n特別の法律により設立される法人\nには\n健康保険
<以下省略>
response = requests.get(url)
指定されたURLのHTMLデータを取得します。response
にはHTMLの応答が格納されます。
if response.status_code == 200…
if response.status_code == 200:
:HTTPリクエストが成功したかどうかを確認します。
html_doc = response.text
: 取得したHTMLデータをテキスト形式でhtml_doc
に保存します。Document(id_=url, text=html_doc)
: HTMLデータをDocument
クラスでラップし、後にHTMLNodeParser
で処理できる形式に変換されます。id_
にはURLが、text
にはHTMLテキストが格納されます。HTMLNodeParser(tags=["p", "h1"])
:<p>
タグと<h1>
タグに基づいてHTMLを分割するパーサを作成します。parser.get_nodes_from_documents([document])
:Document
内のHTMLテキストをタグに基づいて分割します。nodes
には各ノードがリストとして保存されます。
JSON NodeParser
JSONNodeParser は、JSON形式のデータを解析し、チャンク(ノード)に分割するためのクラスです。
このパーサーは、JSONデータの構造を理解し、必要に応じて深いネストされた構造も解析して分割します。
各ノードには、JSONデータ内のキーや値に関するメタデータを付加することが可能です。
#JSONNodeParser
from llama_index.core.node_parser import JSONNodeParser
import os
import requests
os.environ["TAVILY_API_KEY"] = "tvly-*********************"
api_key = os.getenv("TAVILY_API_KEY")
url = "https://api.tavily.com/search"
headers = {
"Content-Type": "application/json"
}
data = {
"api_key": api_key,
"query": "who is fukuoka takamaro?",
"search_depth": "basic",
"include_answer": True,
"max_results": 5,
"include_domains": [],
"exclude_domains": []
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
document = Document(id_=url, text=response.text)
parser = JSONNodeParser()
nodes = parser.get_nodes_from_documents([document])
print(nodes[0])
else:
print("Failed to fetch JSON content:", response.status_code)
Node ID: ed5baeef-e60e-4035-96a7-1e2425ea7c39
Text: query who is fukuoka takamaro? follow_up_questions None answer
Takamaro Fukuoka is a Japanese politician who is a member of the
Liberal Democratic Party and has been serving as the Minister of
Health, Labour, and Welfare since 2024. He has been a member of the
House of Representatives since 2005. results title Takamaro Fukuoka -
Simple English W...
os.environ[“TAVILY_API_KEY”]
環境変数TAVILY_API_KEY
にAPIキーを設定します。このAPIキーはTavilyの公式ページから発行できます。
url = “https://api.tavily.com/search”
APIエンドポイントのURLです。ここでは Tavily
という検索APIのURLを指定しています。
data = {…
APIリクエストのペイロード(データ)です。
query
: 検索クエリです。この例では「Fukuoka Takamaroとは誰か?」という検索を行っています。search_depth
: 検索の深さを指定します。include_answer
: 検索結果に回答を含めるかどうかを指定します。max_results
: 最大検索結果数を指定します。ここでは5件の結果をリクエストしています。include_domains
,exclude_domains
: 特定のドメインを含めたり除外したりする設定ですが、ここでは空のリストが指定されており、ドメインの制限はありません。
if response.status_code == 200…
response.status_code
: APIからのレスポンスのステータスコードを確認します。Document(id_=url, text=response.text)
:response.text
にはAPIからのJSONレスポンスが含まれています。このJSONデータをDocument
オブジェクトに変換します。id_
にはAPIのURL、text
には取得したJSONデータが含まれます。JSONNodeParser()
:JSONNodeParser
のインスタンスを作成します。このパーサを使用して、取得したJSONデータをノードに分割します。get_nodes_from_documents([document])
: JSONデータが格納されたDocument
オブジェクトを渡し、その内容をノードに分割します。分割された結果はnodes
に保存されます。
Markdown NodeParser
MarkdownNodeParser は、Markdown形式のデータを解析し、ノード(チャンク)に分割するためのクラスです。
このパーサーは、Markdownの構造を理解し、見出しや段落などの要素に基づいてデータを分割します。
# MarkdownNodeParser
from llama_index.core.node_parser import MarkdownNodeParser
md_docs = FlatReader().load_data(Path("README.md"))
parser = MarkdownNodeParser()
nodes = parser.get_nodes_from_documents(md_docs)
nodes[0].text
'🗂️ LlamaIndex 🦙\n\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/llama-index)](https://pypi.org/project/llama-index/)\n[![GitHub contributors](https://img.shields.io/github/contributors/jerryjliu/llama_index)](https://github.com/jerryjliu/llama_index/graphs/contributors)\n[![Discord](https://img.shields.io/discord/1059199217496772688)](https://discord.gg/dGcwcsnxhU)\n[![Ask AI](https://img.shields.io/badge/Phorm-Ask_AI-%23F2777A.svg?&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNSIgaGVpZ2h0PSI0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGQ9Ik00LjQzIDEuODgyYTEuNDQgMS40NCAwIDAgMS0uMDk4LjQyNmMtLjA1LjEyMy0uMTE1LjIzLS4xOTIuMzIyLS4wNzUuMDktLjE2LjE2NS0uMjU1LjIyNmExLjM1MyAxLjM1MyAwIDAgMS0uNTk1LjIxMmMtLjA5OS4wMTItLjE5Mi4wMTQtLjI3OS4wMDZsLTEuNTkzLS4xNHYtLjQwNmgxLjY1OGMuMDkuMDAxLjE3LS4xNjkuMjQ2LS4xOTFhLjYwMy42MDMgMCAwIDAgLjItLjEwNi41MjkuNTI5IDAgMCAwIC4xMzgtLjE3LjY1NC42NTQgMCAwIDAgLjA2NS0uMjRsLjAyOC0uMzJhLjkzLjkzIDAgMCAwLS4wMzYtLjI0OS41NjcuNTY3IDAgMCAwLS4xMDMtLjIuNTAyLjUwMiAwIDAgMC0uMTY4LS4xMzguNjA4LjYwOCAwIDAgMC0uMjQtLjA2N0wyLjQzNy43MjkgMS42MjUuNjcxYS4zMjIuMzIyIDAgMCAwLS4yMzIuMDU4LjM3NS4zNzUgMCAwIDAtLjExNi4yMzJsLS4xMTYgMS40NS0uMDU4LjY5Ny0uMDU4Ljc1NEwuNzA1IDRsLS4zNTctLjA3OUwuNjAyLjkwNkMuNjE3LjcyNi42NjMuNTc0LjczOS40NTRhLjk1OC45NTggMCAwIDEgLjI3NC0uMjg1Ljk3MS45NzEgMCAwIDEgLjMzNy0uMTRjLjExOS0uMDI2LjIyNy0uMDM0LjMyNS0uMDI2TDMuMjMyLjE2Yy4xNTkuMDE0LjMzNi4wMy40NTkuMDgyYTEuMTczIDEuMTczIDAgMCAxIC41NDUuNDQ3Yy4wNi4wOTQuMTA5LjE5Mi4xNDQuMjkzYTEuMzkyIDEuMzkyIDAgMCAxIC4wNzguNThsLS4wMjkuMzJaIiBmaWxsPSIjRjI3NzdBIi8+CiAgPHBhdGggZD0iTTQuMDgyIDIuMDA3YTEuNDU1IDEuNDU1IDAgMCAxLS4wOTguNDI3Yy0uMDUuMTI0LS4xMTQuMjMyLS4xOTIuMzI0YTEuMTMgMS4xMyAwIDAgMS0uMjU0LjIyNyAxLjM1MyAxLjM1MyAwIDAgMS0uNTk1LjIxNGMtLjEuMDEyLS4xOTMuMDE0LS4yOC4wMDZsLTEuNTYtLjEwOC4wMzQtLjQwNi4wMy0uMzQ4IDEuNTU5LjE1NGMuMDkgMCAuMTczLS4wMS4yNDgtLjAzM2EuNjAzLjYwMyAwIDAgMCAuMi0uMTA2LjUzMi41MzIgMCAwIDAgLjEzOS0uMTcyLjY2LjY2IDAgMCAwIC4wNjQtLjI0MWwuMDI5LS4zMjFhLjk0Ljk0IDAgMCAwLS4wMzYtLjI1LjU3LjU3IDAgMCAwLS4xMDMtLjIwMi41MDIuNTAyIDAgMCAwLS4xNjgtLjEzOC42MDUuNjA1IDAgMCAwLS4yNC0uMDY3TDEuMjczLjgyN2MtLjA5NC0uMDA4LS4xNjguMDEtLjIyMS4wNTUtLjA1My4wNDUtLjA4NC4xMTQtLjA5Mi4yMDZMLjcwNSA0IDAgMy45MzhsLjI1NS0yLjkxMUExLjAxIDEuMDEgMCAwIDEgLjM5My41NzIuOTYyLjk2MiAwIDAgMSAuNjY2LjI4NmEuOTcuOTcgMCAwIDEgLjMzOC0uMTRDMS4xMjIuMTIgMS4yMy4xMSAxLjMyOC4xMTlsMS41OTMuMTRjLjE2LjAxNC4zLjA0Ny40MjMuMWExLjE3IDEuMTcgMCAwIDEgLjU0NS40NDhjLjA2MS4wOTUuMTA5LjE5My4xNDQuMjk1YTEuNDA2IDEuNDA2IDAgMCAxIC4wNzcuNTgzbC0uMDI4LjMyMloiIGZpbGw9IndoaXRlIi8+CiAgPHBhdGggZD0iTTQuMDgyIDIuMDA3YTEuNDU1IDEuNDU1IDAgMCAxLS4wOTguNDI3Yy0uMDUuMTI0LS4xMTQuMjMyLS4xOTIuMzI0YTEuMTMgMS4xMyAwIDAgMS0uMjU0LjIyNyAxLjM1MyAxLjM1MyAwIDAgMS0uNTk1LjIxNGMtLjEuMDEyLS4xOTMuMDE0LS4yOC4wMDZsLTEuNTYtLjEwOC4wMzQtLjQwNi4wMy0uMzQ4IDEuNTU5LjE1NGMuMDkgMCAuMTczLS4wMS4yNDgtLjAzM2EuNjAzLjYwMyAwIDAgMCAuMi0uMTA2LjUzMi41MzIgMCAwIDAgLjEzOS0uMTcyLjY2LjY2IDAgMCAwIC4wNjQtLjI0MWwuMDI5LS4zMjFhLjk0Ljk0IDAgMCAwLS4wMzYtLjI1LjU3LjU3IDAgMCAwLS4xMDMtLjIwMi41MDIuNTAyIDAgMCAwLS4xNjgtLjEzOC42MDUuNjA1IDAgMCAwLS4yNC0uMDY3TDEuMjczLjgyN2MtLjA5NC0uMDA4LS4xNjguMDEtLjIyMS4wNTUtLjA1My4wNDUtLjA4NC4xMTQtLjA5Mi4yMDZMLjcwNSA0IDAgMy45MzhsLjI1NS0yLjkxMUExLjAxIDEuMDEgMCAwIDEgLjM5My41NzIuOTYyLjk2MiAwIDAgMSAuNjY2LjI4NmEuOTcuOTcgMCAwIDEgLjMzOC0uMTRDMS4xMjIuMTIgMS4yMy4xMSAxLjMyOC4xMTlsMS41OTMuMTRjLjE2LjAxNC4zLjA0Ny40MjMuMWExLjE3IDEuMTcgMCAwIDEgLjU0NS40NDhjLjA2MS4wOTUuMTA5LjE5My4xNDQuMjk1YTEuNDA2IDEuNDA2IDAgMCAxIC4wNzcuNTgzbC0uMDI4LjMyMloiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=)](https://www.phorm.ai/query?projectId=c5863b56-6703-4a5d-87b6-7e6031bf16b6)\n\nLlamaIndex (GPT Index) is a data framework for your LLM application. Building with LlamaIndex typically involves working with LlamaIndex core and a chosen set of integrations (or plugins). There are two ways to start building with LlamaIndex in\nPython:\n\n1. **Starter**: `llama-index` (https://pypi.org/project/llama-index/). A starter Python package that includes core LlamaIndex as well as a selection of integrations.\n\n2. **Customized**: `llama-index-core` (https://pypi.org/project/llama-index-core/). Install core LlamaIndex and add your chosen LlamaIndex integration packages on
<以下省略>
md_docs = FlatReader().load_data(Path(“README.md”))
ファイルを読み込むためのメソッドです。ここでは README.md
ファイルの内容を読み込み、その内容を md_docs
に保存します。
parser = MarkdownNodeParser()
MarkdownNodeParser
インスタンスを使って、Markdown形式のデータをノード(チャンク)に分割する準備をします。
nodes = parser.get_nodes_from_documents(md_docs)
読み込んだ Markdown ファイルの内容 (md_docs
) を解析し、ノードに分割します。ファイル内の構造(見出し、段落など)に基づいてテキストをチャンクに分割します。nodes
に分割されたノードがリスト形式で格納されます。
長さベースのNode Parser
長さに基づくノードパーサーは、指定された文字数やトークン数に従ってテキストを分割する手法です。
これらはコードやテキストを指定された行数や文単位、文字数に基づいて分割し、各チャンクの間で必要に応じて重複を追加します。
長さに基づくノードパーサーは以下のようなものがあります。
- Code Splitter
- Sentence Splitter
- TokenText Splitter
- SentenceWindowNodeParser
事前準備
パッケージをインストールします。
pip install llama_index llama-index-core
Code Splitter
CodeSplitter は、コードを解析し、特定の言語に基づいてチャンク(ノード)に分割するためのクラスです。
PythonやJavaScriptなど、さまざまなプログラミング言語の構造に基づいてコードを分割でき、コード解析や検索、処理を行う際に役立ちます。
pip install -U "tree-sitter<0.22.0" "tree_sitter_languages<1.10.0"
!curl -O https://raw.githubusercontent.com/lancedb/vectordb-recipes/main/applications/talk-with-podcast/app.py
# CodeSplitter
from llama_index.core.node_parser import CodeSplitter
documents = FlatReader().load_data(Path("sentence_transformer.py"))
splitter = CodeSplitter(
language="python",
chunk_lines=40,
chunk_lines_overlap=15,
max_chars=1500,
)
nodes = splitter.get_nodes_from_documents(documents)
nodes[0].text
'"""Sentence Transformer Finetuning Engine."""\n\nfrom typing import Any, Optional\n\nfrom llama_index.core.base.embeddings.base import BaseEmbedding\nfrom llama_index.core.embeddings.utils import resolve_embed_model\nfrom llama_index.finetuning.embeddings.common import (\n EmbeddingQAFinetuneDataset,\n)\nfrom llama_index.finetuning.types import BaseEmbeddingFinetuneEngine'
documents = FlatReader().load_data(Path(“sentence_transformer.py”))
指定したコードファイルを読み込むためのメソッドです。ここでは、sentence_transformer.py
というPythonファイルを読み込み、その内容を documents
に格納しています。
splitter = CodeSplitter(…
language="python"
: 分割対象の言語をPythonに指定しています。chunk_lines=40
: 1チャンクに含まれるコードの行数を指定します。ここでは、40行ごとにコードをチャンクに分割します。chunk_lines_overlap=15
: 各チャンク間で重複する行数を指定しています。ここでは、15行のコードが次のチャンクにも重複して含まれる設定です。これにより、コードのコンテキストが途切れることなく次のチャンクに続く形になります。max_chars=1500
: 1チャンクの最大文字数を指定します。文字数が1,500文字を超えた場合、さらに分割が行われます。この設定により、チャンクのサイズが制御されます。
nodes = splitter.get_nodes_from_documents(documents)
このメソッドは、読み込んだ documents
をチャンクに分割します。指定されたパラメータに基づいて、コードを分割し、ノードリストを作成します。 分割されたチャンク(ノード)が nodes
というリストに格納されます。
Sentence Splitter
SentenceSplitter は、LlamaIndexでテキストを文単位に分割するためのクラスです。
テキストを文ごとに分割し、ノード(チャンク)として扱う際に非常に役立ちます。
特に大規模なテキストデータを処理する際、自然な文の区切りを保持しながらテキストを効率的に処理するために使われます。
# SentenceSplitter
from llama_index.core.node_parser import SentenceSplitter
documents = FlatReader().load_data(Path("第1章_働き方改革の推進などを通じた労働環境の整備など.txt"))
splitter = SentenceSplitter(
chunk_size=254,
chunk_overlap=20,
)
nodes = splitter.get_nodes_from_documents(documents)
nodes[0].text
'第1章 働き方改革の推進などを通じた労働環境の整備など\n\t 第1節\t 非正規雇用労働者の待遇改善、長時間労働の是正等\n\t1\t非正規雇用の現状と対策\n(1)非正規雇用の現状と課題\n近年、パートタイム労働者、有期雇用労働者、派遣労働者といった非正規雇用労働者は\n全体として増加傾向にあり、雇用者の約4割を占める状況にある。'
documents = FlatReader().load_data()
指定されたテキストファイルを読み込み、その内容をテキストデータとして取得します。このテキストデータは documents
に格納され、後にSentenceSplitter
で処理されます。
splitter = SentenceSplitter(…
chunk_size=254
: 1つのチャンクに含まれる最大文字数を指定します。ここでは254文字ごとにチャンクに分割されます。chunk_overlap=20
: 各チャンク間で重複する文字数を指定します。ここでは、20文字分が次のチャンクに重複して含まれるように設定されています。これにより、チャンク間で文脈が途切れることなく処理できます。
nodes = splitter.get_nodes_from_documents(documents)
読み込んだテキストデータdocuments
を文単位で分割し、それぞれをチャンクとしてノードに変換します。各ノードには、指定された chunk_size
と chunk_overlap
に基づいて分割されたテキストが含まれます。結果は nodes
というリストに格納されます。
TokenText Splitter
TokenTextSplitterは、テキストをトークン数に基づいて分割するための機能です。
多くのLLMは、特定のトークン数(単語や文の断片など)を超えると処理できなくなります。この制限を考慮して、テキストを指定されたトークン数に基づいてチャンクに分割する役割を果たします。
# TokenTextSplitting
from llama_index.core.node_parser import TokenTextSplitter
splitter = TokenTextSplitter(
chunk_size=254,
chunk_overlap=20,
separator=" ",
)
nodes = splitter.get_nodes_from_documents(documents)
nodes[0].text
'第1章 働き方改革の推進などを通じた労働環境の整備など\n\t 第1節\t 非正規雇用労働者の待遇改善、長時間労働の是正等\n\t1\t非正規雇用の現状と対策\n(1)非正規雇用の現状と課題\n近年、パートタイム労働者、有期雇用労働者、派遣労働者といった非正規雇用労働者は'
splitter = TokenTextSplitter(…
chunk_size=254
: 1つのチャンクに含まれるトークンの最大数を254トークンに設定しています。これにより、テキストが254トークンずつ分割されます。chunk_overlap=20
: 隣接するチャンク間で20トークンの重複が設定されています。これにより、文脈の連続性を保つことができ、モデルがより意味を理解しやすくなります。separator=" "
: トークンを分割する際の区切り文字として、スペース(" "
)を使用しています。これは、一般的に単語の区切りを意味します。
nodes = splitter.get_nodes_from_documents(documents)
指定したdocuments
をトークン単位で分割し、それぞれをノードに変換します。ノードはテキストの一部分を保持し、後でモデルに入力するためのチャンクとなります。
SentenceWindow NodeParser
SentenceWindowNodeParser は、テキストを文単位で分割し、さらに隣接する文を「ウィンドウ」としてグループ化するためのクラスです。
通常の文単位の分割に加え、前後の文脈を保持するために「ウィンドウ」を作り出します。
各ノードが持つ情報には、そのノード内の文に加え、前後の文も含まれるため、文脈を途切れさせずに処理が可能です。
# SentenceWindowNodeParser
import nltk
from llama_index.core.node_parser import SentenceWindowNodeParser
node_parser = SentenceWindowNodeParser.from_defaults(
window_size=3,
window_metadata_key="window",
original_text_metadata_key="original_sentence",
)
nodes = node_parser.get_nodes_from_documents(documents)
nodes[1].text
'脳・心臓疾患とは、業務における過重負荷により脳・心臓疾患(負傷に起因するものを除く。)を発症した事案(死\n亡を含む。)をいう。\n2. '
node_parser = SentenceWindowNodeParser.from_defaults(…
window_size=3
: 各ノードに含まれる文の数を3に設定しています。この設定により、連続する3文が1つのノード(ウィンドウ)として処理されます。window_metadata_key="window"
: 各ノードにウィンドウに関するメタデータが保存されます。メタデータキーは「window」です。original_text_metadata_key="original_sentence"
: 元の文に関するメタデータを追加します。メタデータキーは「original_sentence」です。これにより、各ノードが元のどの文から作成されたかが追跡可能です。
nodes = node_parser.get_nodes_from_documents(documents)
documents
からテキストを取得し、文単位で分割してノードに変換します。この場合、window_size=3
に基づいて、各ノードには3つの連続した文が含まれます。
意味ベースのNode Parser
意味ベースのノードパーサーは、テキストの意味的な構造に基づいて分割を行うノードパーサーです。
単に文や文字数で区切るのではなく、テキスト内の意味的なまとまりや変化に応じてチャンク(ノード)を生成するため、自然な文脈を維持しながら情報を処理することができます。
意味ベースのノードパーサーには、SemanticSplitter NodeParserがあります。
事前準備
パッケージをインストールします。
pip install llama_index llama-index-core llama-index-embeddings-huggingface
SemanticSplitter NodeParser
SemanticSplitterNodeParser は、テキストを意味的に分割するためのクラスです。
埋め込みモデルを使ってテキスト内の意味の変わり目や類似性を基にして、分割位置を動的に決定します。
コンテキストの意味的なまとまりを維持しながら分割できることが特徴です。
HuggingFaceの埋め込みモデルにはGPU環境が必要になります。
# SemanticSplitterNodeParser
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
embed_model = HuggingFaceEmbedding(model_name="intfloat/multilingual-e5-large")
splitter = SemanticSplitterNodeParser(
buffer_size=1, breakpoint_percentile_threshold=95, embed_model=embed_model
)
nodes = splitter.get_nodes_from_documents(documents)
nodes[0].text
'第1章 働き方改革の推進などを通じた労働環境の整備など\n\t 第1節\t 非正規雇用労働者の待遇改善、長時間労働の是正等\n\t1\t非正規雇用の現状と対策\n(1)非正規雇用の現状と課題\n近年、パートタイム労働者、有期雇用労働者、派遣労働者といった非正規雇用労働者は\n全体として増加傾向にあり、雇用者の約4割を占める状況にある。これは、高齢者が増え\nる中、高齢層での継続雇用により非正規雇用が増加していることや、女性を中心にパート\nなどで働き始める労働者が増加していることなどの要因が大きい。なお、新型コロナウイ\nルス感染症の感染拡大の影響もあり、2020(令和2)年、2021(令和3)年の非正規雇\n用労働者は対前年比で減少したが、2022(令和4)年以降は増加し、2023(令和5)年\nは、2,124万人となっている。\n非正規雇用労働者は、雇用が不安定、賃金が低い、能力開発機会が乏しいなどの課題が\nあり、正規雇用を希望しながらそれがかなわず、非正規雇用で働く者(不本意非正規雇用\n労働者)が9.6%(2023年)存在し、年齢階級別では25~34歳の若年層で13.1%(2023\n年)と高くなっている。一方、非正規雇用労働者の中には「自分の都合のよい時間に働き\nたいから」等の理由により自ら非正規雇用を選ぶ方もおり、多様な働き方が進む中で、ど\nのような雇用形態を選択しても納得が得られる処遇を受けられることが重要である。\n(2)非正規雇用労働者への総合的な対策の推進\n1 正社員転換・待遇改善の推進\n正社員を希望する方の正社員転換や非正規雇用を選択する方の待遇改善を推進するた\nめ、キャリアアップ助成金において、非正規雇用労働者の正社員転換、処遇改善の取組み\nを図る事業主に対して助成を行っている。\nまた、どのような働き方を選択しても公正な待遇を受けられるようにし、人々が自分の\n希望に合わせて多様な働き方を自由に選択できるようにすることが重要である。\n2020(令和2)年4月1日に施行された「短時間労働者及び有期雇用労働者の雇用管理\nの改善等に関する法律」(平成5年法律第76号。以下「パートタイム・有期雇用労働法」\nという。同法の中小企業への適用は2021(令和3)年4月1日。)及び「労働者派遣事業\nの適正な運営の確保及び派遣労働者の保護等に関する法律」(昭和60年法律第88号)で\nは、雇用形態にかかわらない公正な待遇の確保に向け、①不合理な待遇差を解消するため\nの規定の整備、②労働者に対する待遇に関する説明義務の強化、③行政による法の履行確\n保措置及び裁判外紛争解決手続(行政ADR)が整備された。\nフリーター等*1の正社員就職支援のため、「わかものハローワーク」(2024(令和6)年\n4月1日現在21か所)等を拠点に、担当者制による個別支援、正社員就職に向けたセミ\n*1 おおむね35歳未満で正社員での就職を希望する求職者(新規学卒者、正規雇用の在職求職者は除く。)のうち、安定した就労の経験が\n少ない者。\n令和6年版\u3000厚生労働白書 187\n第2部\u3000現下の政策課題への対応\n第\n1\n章働き方改革の推進などを通じた労働環境の整備など\n\nナーやグループワーク等各種支援、就職後の定着支援を実施しており、2023(令和5)\n年度は約9.8万人が就職した。\nまた、職業経験、技能、知識の不足等から安定的な就職が困難な求職者について、正規\n雇用化等の早期実現を図るため、これらの者をハローワーク等の紹介を通じて一定期間試\n行雇用する事業主に対して助成措置(トライアル雇用助成金)を講じている。\n2
<以下余白>
embed_model = HuggingFaceEmbedding(model_name=”intfloat/multilingual-e5-large”)
Hugging Faceの埋め込みモデルを使用して、テキストの意味的なベクトルを生成します。intfloat/multilingual-e5-large
はHugging Faceで提供されている多言語対応の埋め込みモデルで、日本語にも対応しています。
splitter = SemanticSplitterNodeParser(…
SemanticSplitterNodeParser
: 意味的な類似性に基づいてテキストを分割するパーサを初期化します。buffer_size=1
: チャンクのバッファサイズを設定します。ここでは最小サイズとして「1」が設定されています。breakpoint_percentile_threshold=95
: チャンク間の意味的な違いが95%を超えた場合にテキストを分割します。テキストの意味的な変化が大きい箇所で分割されます。embed_model=embed_model
: Hugging Faceの埋め込みモデルを使用して、テキストの意味的なベクトルを計算します。
nodes = splitter.get_nodes_from_documents(documents)
documents
を意味的に分割し、それぞれのチャンクをノードとして取得します。
TokenText Splitter
TokenTextSplitterは、テキストをトークン数に基づいて分割するための機能です。
多くのLLMは、特定のトークン数(単語や文の断片など)を超えると処理できなくなります。この制限を考慮して、テキストを指定されたトークン数に基づいてチャンクに分割する役割を果たします。
# TokenTextSplitting
from llama_index.core.node_parser import TokenTextSplitter
splitter = TokenTextSplitter(
chunk_size=254,
chunk_overlap=20,
separator=" ",
)
nodes = splitter.get_nodes_from_documents(documents)
nodes[0].text
'第1章 働き方改革の推進などを通じた労働環境の整備など\n\t 第1節\t 非正規雇用労働者の待遇改善、長時間労働の是正等\n\t1\t非正規雇用の現状と対策\n(1)非正規雇用の現状と課題\n近年、パートタイム労働者、有期雇用労働者、派遣労働者といった非正規雇用労働者は'
splitter = TokenTextSplitter(…
chunk_size=254
: 1つのチャンクに含まれるトークンの最大数を254トークンに設定しています。これにより、テキストが254トークンずつ分割されます。chunk_overlap=20
: 隣接するチャンク間で20トークンの重複が設定されています。これにより、文脈の連続性を保つことができ、モデルがより意味を理解しやすくなります。separator=" "
: トークンを分割する際の区切り文字として、スペース(" "
)を使用しています。これは、一般的に単語の区切りを意味します。
nodes = splitter.get_nodes_from_documents(documents)
指定したdocuments
をトークン単位で分割し、それぞれをノードに変換します。ノードはテキストの一部分を保持し、後でモデルに入力するためのチャンクとなります。
リレーションベースのNode Parser
リレーションベースのノードパーサーは、テキストやドキュメントを階層的に分割し、ノード間に親子関係などのリレーション(関係性)を構築するための手法です。
テキストの内容をより大きなコンテキストから細部まで理解するために、ノードを階層的に管理します。
代表的なリレーションベースのノードパーサーにはHierarchical NodeParseがあります。
事前準備
パッケージをインストールします。
pip install llama_index llama-index-core llama-index-embeddings-huggingface
Hierarchical NodeParser
HierarchicalNodeParserは、ドキュメントを階層的に分割するためのノードパーサーです。
ドキュメントを大きなチャンクから小さなチャンクへと分割し、それぞれのチャンク間に親子関係を構築します。
大きなチャンクが親ノード、小さなチャンクが子ノードとして階層構造を形成するため、全体の文脈を保持しつつ、詳細な部分の解析も可能です。
# HierarchicalNodeParser
from llama_index.core.node_parser import HierarchicalNodeParser
node_parser = HierarchicalNodeParser.from_defaults(chunk_sizes=[512, 254, 128])
nodes = node_parser.get_nodes_from_documents(documents)
nodes[0].text
'第1章 働き方改革の推進などを通じた労働環境の整備など\n\t 第1節\t 非正規雇用労働者の待遇改善、長時間労働の是正等\n\t1\t非正規雇用の現状と対策\n(1)非正規雇用の現状と課題\n近年、パートタイム労働者、有期雇用労働者、派遣労働者といった非正規雇用労働者は\n全体として増加傾向にあり、雇用者の約4割を占める状況にある。これは、高齢者が増え\nる中、高齢層での継続雇用により非正規雇用が増加していることや、女性を中心にパート\nなどで働き始める労働者が増加していることなどの要因が大きい。なお、新型コロナウイ\nルス感染症の感染拡大の影響もあり、2020(令和2)年、2021(令和3)年の非正規雇\n用労働者は対前年比で減少したが、2022(令和4)年以降は増加し、2023(令和5)年\nは、2,124万人となっている。'
node_parser = HierarchicalNodeParser.from_defaults(chunk_sizes=[512, 254, 128])
chunk_sizes
パラメータに [512, 254, 128]
が指定されています。これは、ドキュメントが3つの異なるサイズのチャンクに分割されることを意味します。512が親ノード, 254が子ノード, 128孫ノードのように階層が作られ、親子関係が構築されます。
nodes = node_parser.get_nodes_from_documents(documents)
documents
の内容を指定されたチャンクサイズに基づいて分割します。このメソッドは、階層的に分割されたノードのリストを返します。
生成AI・LLMのコストでお困りなら
GPUのスペック不足で生成AIの開発が思うように進まないことはありませんか?
そんなときには、高性能なGPUをリーズナブルな価格で使えるGPUクラウドサービスがおすすめです!
GPUSOROBANは、生成AI・LLM向けの高速GPUを業界最安級の料金で使用することができます。
インターネット環境さえあれば、クラウド環境のGPUサーバーをすぐに利用可能です。
大規模な設備投資の必要がなく、煩雑なサーバー管理からも解放されます。