見出し画像

LlamaIndexのインデックスに含まれるドキュメントとノードの確認と管理

「LlamaIndex」のインデックスに含まれる「ドキュメント」と「ノード」の確認と管理の手順をまとめました。

・LlamaIndex v0.9.26


1. LlamaIndexによるRAGの作成

はじめに、「LlamaIndex」でシンプルなRAGを作成します。

(1) パッケージのインストール。

# パッケージのインストール
!pip install llama-index==0.9.26

(2) 環境変数の準備。
左端の鍵アイコンで「OPENAI_API_KEY」に自分のOpenAI APIキーを設定してからセルを実行してください。

import os
from google.colab import userdata

# 環境変数の準備 (左端の鍵アイコンでOPENAI_API_KEYを設定)
os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")

(3) ログレベルの設定。

import logging
import sys

# ログレベルの設定
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, force=True)

(4) ドキュメントの読み込み。
左端のフォルダアイコンでdataフォルダとadd_dataフォルダを作成して、ドキュメントをアップロードしてからセルを実行してください。

・data : ChatGPTに書かせた7章構成のサイバーパンク赤ずきんの物語
・add_data : 追加の第8章 (実験で利用)

from llama_index import SimpleDirectoryReader

# ドキュメントの読み込み
documents = SimpleDirectoryReader("data").load_data()

(5) インデックスとクエリの作成。

from llama_index import ServiceContext, VectorStoreIndex

# ServiceContextの準備
service_context = ServiceContext.from_defaults(
    chunk_size=250  # チャンクの最大サイズ
)

# インデックスの作成
index = VectorStoreIndex.from_documents(
    documents,
    show_progress=True,
    service_context=service_context
)

# クエリエンジンの作成
query_engine = index.as_query_engine(
    similarity_top_k=2  # 取得するチャンク数
)

(6) 質問応答。
正解です。

# 質問応答
print(query_engine.query("ミコの幼馴染の名前は?"))
リョウ

2. インデックスの読み書き

インデックスの読み書きの手順は、次のとおりです。

2-1. インデックスの書き込み

# インデックスの書き込み
index.storage_context.persist()

storageフォルダに以下のファイルが保存されます。

・default__vector_store.json : 埋め込み
・docstore.json : ドキュメントストア
・graph_store.json : グラフストア
・image__vector_store.json : 画像ベクトルストア
・index_store.json : ノード情報

2-2. インデックスの読み込み

from llama_index import StorageContext, load_index_from_storage

# インデックスの読み込み
storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)

3. ドキュメントとノードの確認

インデックスに含まれるドキュメントとノードの確認の手順は、次のとおりです。

3-1. ドキュメント群に含まれるドキュメント情報の確認

ドキュメントIDとドキュメント先頭20文字を出力しています。

# ドキュメント群に含まれるドキュメント情報の確認
for document in documents:
    print(document.id_, ":", document.text[:20].replace("\n", " "))
b653520b-a020-4ffd-8d90-7637acf403ee : 第1章:データフロント  夜の煌びやかな
3988d560-334f-4a39-b656-1e88860e78ec : 第2章:ウルフ・コーポレーションの罠  
f0580902-f08f-4b0d-b534-c6cd2f404efe : 第3章:裏切りと再会  バー「グランマズ
0786d647-a1c6-4e38-b754-f7c9c4c2f616 : 第4章:ウルフ・コーポレーションの崩壊 
c83c7785-f69b-4cd7-8db4-bb8ebe11ad2d : 第5章:決戦の時  ミコとリョウはついに
03645b40-a90c-4556-8829-e515c3fe44f2 : 第6章:真実の解放  ミコはウルフ博士の
4c33528c-f1a5-4914-945a-213057ac55fc : 第7章:新たなる旅立ち  ウルフ・コーポ

3-2. インデックスに含まれるドキュメント情報の確認

ドキュメントIDとノードID群を出力しています。1章と3章が2つのノードに分割されていることがわかります。

# インデックスに含まれるドキュメント情報の確認
for doc_id, doc_info in index.ref_doc_info.items():
    print(doc_id, ":", doc_info.node_ids)

b653520b-a020-4ffd-8d90-7637acf403ee : ['a5789477-5c19-477b-bd8c-9dc90e1a50ee', 'b8471cee-d258-4eea-bd23-8efa43a166b4']
3988d560-334f-4a39-b656-1e88860e78ec : ['29449bcb-4387-4904-b78b-3287b5fecb14']
f0580902-f08f-4b0d-b534-c6cd2f404efe : ['516fee3a-f537-4bd3-9264-558103bb030e', '6f07f7da-3392-4f24-8214-b7563627a081']
0786d647-a1c6-4e38-b754-f7c9c4c2f616 : ['9e0df461-d7f0-4ddc-96b5-67c75ae12787']
c83c7785-f69b-4cd7-8db4-bb8ebe11ad2d : ['bcc78a65-6736-4dda-a3cd-c2ab4f55b515']
03645b40-a90c-4556-8829-e515c3fe44f2 : ['07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c']
4c33528c-f1a5-4914-945a-213057ac55fc : ['7aba730d-1aef-497c-af3e-bc2c25db16b9']

3-3. インデックスに含まれるノード情報の確認

ノードIDとテキスト先頭20文字を出力しています。

# インデックスに含まれるノード情報の確認
node_doc_ids = index.index_struct.nodes_dict.values()
for node in index.docstore.get_nodes(node_doc_ids):
    print(node.id_, ":", node.text[:20].replace("\n", " "))
a5789477-5c19-477b-bd8c-9dc90e1a50ee : 第1章:データフロント  夜の煌びやかな
b8471cee-d258-4eea-bd23-8efa43a166b4 : その街で、赤いフードをかぶった少女・ミコ
29449bcb-4387-4904-b78b-3287b5fecb14 : 第2章:ウルフ・コーポレーションの罠  
516fee3a-f537-4bd3-9264-558103bb030e : 第3章:裏切りと再会  バー「グランマズ
6f07f7da-3392-4f24-8214-b7563627a081 : リョウは彼女の幼馴染であり、彼もまたウル
9e0df461-d7f0-4ddc-96b5-67c75ae12787 : 第4章:ウルフ・コーポレーションの崩壊 
bcc78a65-6736-4dda-a3cd-c2ab4f55b515 : 第5章:決戦の時  ミコとリョウはついに
07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c : 第6章:真実の解放  ミコはウルフ博士の
7aba730d-1aef-497c-af3e-bc2c25db16b9 : 第7章:新たなる旅立ち  ウルフ・コーポ

3-4. インデックスに含まれるノードの埋め込みの確認

ノードIDと埋め込みを出力しています。

from llama_index.indices.utils import async_embed_nodes, embed_nodes

# インデックスに含まれるノードの埋め込みの確認
id_to_embed_map = embed_nodes(
    index.docstore.get_nodes(node_doc_ids), 
    index._service_context.embed_model, 
    show_progress=True
)
for node_id, node_embed in id_to_embed_map.items():
    print(node_id, ":", node_embed)
a5789477-5c19-477b-bd8c-9dc90e1a50ee : [0.00018566509243100882, -0.0021640199702233076, ...]
b8471cee-d258-4eea-bd23-8efa43a166b4 : [-0.00792342983186245, -0.007546788081526756, ...]
29449bcb-4387-4904-b78b-3287b5fecb14 : [-0.02438954822719097, -0.014492749236524105, ...]
516fee3a-f537-4bd3-9264-558103bb030e : [-0.01839890517294407, -0.00596889853477478, ...]
6f07f7da-3392-4f24-8214-b7563627a081 : [-0.018981723114848137, -0.004142286255955696, ...]
9e0df461-d7f0-4ddc-96b5-67c75ae12787 : [-0.020520830526947975, -0.006756193935871124, ...]
bcc78a65-6736-4dda-a3cd-c2ab4f55b515 : [-0.018631653860211372, -0.008409645408391953, ...]
07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c : [-0.010659953579306602, 0.0013720471179112792, ...]
7aba730d-1aef-497c-af3e-bc2c25db16b9 : [-0.01590215414762497, -0.005675919819623232, ...]

3-5. レスポンスのソースノードの確認

# 質問応答
response = query_engine.query("ミコの幼馴染の名前は?")
print(response)

# ソースノードの確認
for node in response.source_nodes:
    print(node.id_, ":", node.text[:20].replace("\n", " "), "(Score:", node.score, ")")
リョウ
516fee3a-f537-4bd3-9264-558103bb030e : 第3章:裏切りと再会  バー「グランマズ (Score: 0.8254593648709416 )
29449bcb-4387-4904-b78b-3287b5fecb14 : 第2章:ウルフ・コーポレーションの罠   (Score: 0.8199444604824183 )

4. ドキュメントとノードの管理

4-1. ドキュメントの追加

ドキュメントの追加手順は、次のとおりです。

(1) ドキュメントの追加。

from llama_index import SimpleDirectoryReader

# ドキュメントの読み込み
documents = SimpleDirectoryReader("add_data").load_data()

# ドキュメントの追加
for document in documents:
    index.insert(document)

(2) インデックスに含まれるドキュメント情報の確認。
8章が4つのノードとして追加されていることがわかります。

# インデックスに含まれるドキュメント情報の確認
for doc_id, doc_info in index.ref_doc_info.items():
    print(doc_id, ":", doc_info.node_ids)
b653520b-a020-4ffd-8d90-7637acf403ee : ['a5789477-5c19-477b-bd8c-9dc90e1a50ee', 'b8471cee-d258-4eea-bd23-8efa43a166b4']
3988d560-334f-4a39-b656-1e88860e78ec : ['29449bcb-4387-4904-b78b-3287b5fecb14']
f0580902-f08f-4b0d-b534-c6cd2f404efe : ['516fee3a-f537-4bd3-9264-558103bb030e', '6f07f7da-3392-4f24-8214-b7563627a081']
0786d647-a1c6-4e38-b754-f7c9c4c2f616 : ['9e0df461-d7f0-4ddc-96b5-67c75ae12787']
c83c7785-f69b-4cd7-8db4-bb8ebe11ad2d : ['bcc78a65-6736-4dda-a3cd-c2ab4f55b515']
03645b40-a90c-4556-8829-e515c3fe44f2 : ['07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c']
4c33528c-f1a5-4914-945a-213057ac55fc : ['7aba730d-1aef-497c-af3e-bc2c25db16b9']
dde82b24-70d8-4299-aaa6-58d3c61107d6 : ['a5bc1535-09b5-44b1-8aed-b41d1d111a6e', '3fa560e4-e837-40a5-8775-31ff0671682a', 'bb85bf11-6fce-407c-b2d7-5068ad2f6978', '8c60010b-036f-45a5-a584-16caea865796']

(3) インデックスに含まれるノード情報の確認。
8章が4つのノードとして追加されていることがわかります。

# インデックスに含まれるノード情報の確認
node_doc_ids = index.index_struct.nodes_dict.values()
for node in index.docstore.get_nodes(node_doc_ids):
    print(node.id_, ":", node.text[:20].replace("\n", " "))
a5789477-5c19-477b-bd8c-9dc90e1a50ee : 第1章:データフロント  夜の煌びやかな
b8471cee-d258-4eea-bd23-8efa43a166b4 : その街で、赤いフードをかぶった少女・ミコ
29449bcb-4387-4904-b78b-3287b5fecb14 : 第2章:ウルフ・コーポレーションの罠  
516fee3a-f537-4bd3-9264-558103bb030e : 第3章:裏切りと再会  バー「グランマズ
6f07f7da-3392-4f24-8214-b7563627a081 : リョウは彼女の幼馴染であり、彼もまたウル
9e0df461-d7f0-4ddc-96b5-67c75ae12787 : 第4章:ウルフ・コーポレーションの崩壊 
bcc78a65-6736-4dda-a3cd-c2ab4f55b515 : 第5章:決戦の時  ミコとリョウはついに
07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c : 第6章:真実の解放  ミコはウルフ博士の
7aba730d-1aef-497c-af3e-bc2c25db16b9 : 第7章:新たなる旅立ち  ウルフ・コーポ
a5bc1535-09b5-44b1-8aed-b41d1d111a6e : 第8章:未来への道  ネオ東京、ウルフ・
3fa560e4-e837-40a5-8775-31ff0671682a : ミコとリョウは、市民を支え、ネットワーク
bb85bf11-6fce-407c-b2d7-5068ad2f6978 : その平穏な生活に一石を投じるように、ミコ
8c60010b-036f-45a5-a584-16caea865796 : このメッセージは彼女の過去に繋がり、新た

(4) 質問応答。
インデックス更新したらクエリエンジンの更新も必要です。

# クエリエンジンの作成
query_engine = index.as_query_engine(
    similarity_top_k=2
)

# 質問応答
print(query_engine.query("8章のタイトルは?"))
未来への道

4-2. ドキュメントの更新

ドキュメントの更新手順は、次のとおりです。

(1) ドキュメントの更新。
今回は、「akazukin8.txt」の1行目のタイトルを変更します。

第8章:未来への道

第8章:暗号メッセージ

(2) ドキュメントの更新。
ドキュメントIDには自身の8章のIDを指定してください。

from llama_index import SimpleDirectoryReader

# ドキュメントの読み込み
documents = SimpleDirectoryReader("add_data").load_data()

# ドキュメントの更新
documents[0].id_ = "dde82b24-70d8-4299-aaa6-58d3c61107d6"  # 自身の8章のIDを指定
index.update_ref_doc(
    documents[0],
    update_kwargs={"delete_kwargs": {"delete_from_docstore": True}},
)

(3) インデックスに含まれるドキュメント情報の確認。

# インデックスに含まれるドキュメント情報の確認
for doc_id, doc_info in index.ref_doc_info.items():
    print(doc_id, ":", doc_info.node_ids)
b653520b-a020-4ffd-8d90-7637acf403ee : ['a5789477-5c19-477b-bd8c-9dc90e1a50ee', 'b8471cee-d258-4eea-bd23-8efa43a166b4']
3988d560-334f-4a39-b656-1e88860e78ec : ['29449bcb-4387-4904-b78b-3287b5fecb14']
f0580902-f08f-4b0d-b534-c6cd2f404efe : ['516fee3a-f537-4bd3-9264-558103bb030e', '6f07f7da-3392-4f24-8214-b7563627a081']
0786d647-a1c6-4e38-b754-f7c9c4c2f616 : ['9e0df461-d7f0-4ddc-96b5-67c75ae12787']
c83c7785-f69b-4cd7-8db4-bb8ebe11ad2d : ['bcc78a65-6736-4dda-a3cd-c2ab4f55b515']
03645b40-a90c-4556-8829-e515c3fe44f2 : ['07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c']
4c33528c-f1a5-4914-945a-213057ac55fc : ['7aba730d-1aef-497c-af3e-bc2c25db16b9']
dde82b24-70d8-4299-aaa6-58d3c61107d6 : ['7205b543-0de5-404e-9673-d6884a209a09', 'ddb20c92-abba-4beb-b6ca-2ae44131a9b7', '1dbdc072-a2a6-450f-ae23-1a88ac92b6dc', '0b5e16e4-5321-49e5-ae16-e8739867568c']

(4) インデックスに含まれるノード情報の確認。
タイトルが更新されていることがわかります。

# インデックスに含まれるノード情報の確認
node_doc_ids = index.index_struct.nodes_dict.values()
for node in index.docstore.get_nodes(node_doc_ids):
    print(node.id_, ":", node.text[:20].replace("\n", " "))
a5789477-5c19-477b-bd8c-9dc90e1a50ee : 第1章:データフロント  夜の煌びやかな
b8471cee-d258-4eea-bd23-8efa43a166b4 : その街で、赤いフードをかぶった少女・ミコ
29449bcb-4387-4904-b78b-3287b5fecb14 : 第2章:ウルフ・コーポレーションの罠  
516fee3a-f537-4bd3-9264-558103bb030e : 第3章:裏切りと再会  バー「グランマズ
6f07f7da-3392-4f24-8214-b7563627a081 : リョウは彼女の幼馴染であり、彼もまたウル
9e0df461-d7f0-4ddc-96b5-67c75ae12787 : 第4章:ウルフ・コーポレーションの崩壊 
bcc78a65-6736-4dda-a3cd-c2ab4f55b515 : 第5章:決戦の時  ミコとリョウはついに
07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c : 第6章:真実の解放  ミコはウルフ博士の
7aba730d-1aef-497c-af3e-bc2c25db16b9 : 第7章:新たなる旅立ち  ウルフ・コーポ
7205b543-0de5-404e-9673-d6884a209a09 : 第8章:暗号メッセージ  ネオ東京、ウル
ddb20c92-abba-4beb-b6ca-2ae44131a9b7 : ミコとリョウは、市民を支え、ネットワーク
1dbdc072-a2a6-450f-ae23-1a88ac92b6dc : その平穏な生活に一石を投じるように、ミコ
0b5e16e4-5321-49e5-ae16-e8739867568c : このメッセージは彼女の過去に繋がり、新た

(5) 質問応答。

# クエリエンジンの作成
query_engine = index.as_query_engine(
    similarity_top_k=2
)

# 質問応答
print(query_engine.query("8章のタイトルは?"))
暗号メッセージ

4-3. ドキュメントの削除

ドキュメントの削除手順は、次のとおりです。

(1) ドキュメントの削除。
ドキュメントIDには自身の8章のIDを指定してください。

# ドキュメントの削除
index.delete_ref_doc(
    "dde82b24-70d8-4299-aaa6-58d3c61107d6", 
    delete_from_docstore=True
)

(2) インデックスに含まれるドキュメント情報の確認。

# インデックスに含まれるドキュメント情報の確認
for doc_id, doc_info in index.ref_doc_info.items():
    print(doc_id, ":", doc_info.node_ids)
b653520b-a020-4ffd-8d90-7637acf403ee : ['a5789477-5c19-477b-bd8c-9dc90e1a50ee', 'b8471cee-d258-4eea-bd23-8efa43a166b4']
3988d560-334f-4a39-b656-1e88860e78ec : ['29449bcb-4387-4904-b78b-3287b5fecb14']
f0580902-f08f-4b0d-b534-c6cd2f404efe : ['516fee3a-f537-4bd3-9264-558103bb030e', '6f07f7da-3392-4f24-8214-b7563627a081']
0786d647-a1c6-4e38-b754-f7c9c4c2f616 : ['9e0df461-d7f0-4ddc-96b5-67c75ae12787']
c83c7785-f69b-4cd7-8db4-bb8ebe11ad2d : ['bcc78a65-6736-4dda-a3cd-c2ab4f55b515']
03645b40-a90c-4556-8829-e515c3fe44f2 : ['07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c']
4c33528c-f1a5-4914-945a-213057ac55fc : ['7aba730d-1aef-497c-af3e-bc2c25db16b9']

(3) インデックスに含まれるノード情報の確認。

# インデックスに含まれるノード情報の確認
node_doc_ids = index.index_struct.nodes_dict.values()
for node in index.docstore.get_nodes(node_doc_ids):
    print(node.id_, ":", node.text[:20].replace("\n", " "))
a5789477-5c19-477b-bd8c-9dc90e1a50ee : 第1章:データフロント  夜の煌びやかな
b8471cee-d258-4eea-bd23-8efa43a166b4 : その街で、赤いフードをかぶった少女・ミコ
29449bcb-4387-4904-b78b-3287b5fecb14 : 第2章:ウルフ・コーポレーションの罠  
516fee3a-f537-4bd3-9264-558103bb030e : 第3章:裏切りと再会  バー「グランマズ
6f07f7da-3392-4f24-8214-b7563627a081 : リョウは彼女の幼馴染であり、彼もまたウル
9e0df461-d7f0-4ddc-96b5-67c75ae12787 : 第4章:ウルフ・コーポレーションの崩壊 
bcc78a65-6736-4dda-a3cd-c2ab4f55b515 : 第5章:決戦の時  ミコとリョウはついに
07dc2a7a-fb5c-48b0-98ff-cfe3a20a6d8c : 第6章:真実の解放  ミコはウルフ博士の
7aba730d-1aef-497c-af3e-bc2c25db16b9 : 第7章:新たなる旅立ち  ウルフ・コーポ

(4) 質問応答。
英語ですが正解です。デフォルトのプロンプトテンプレートが英語なのが原因と思われます。

# クエリエンジンの作成
query_engine = index.as_query_engine(
    similarity_top_k=2
)

# 質問応答
print(query_engine.query("8章のタイトルは?"))
I'm sorry, but I cannot answer the query as it requires prior knowledge of the content in Chapter 8.

【翻訳】申し訳ありませんが、第8章の内容についての事前知識が必要なため、お答えできません。



この記事が気に入ったらサポートをしてみませんか?