Closed9

LlamaIndexモジュールガイドを試してみる: Loading Data

kun432kun432

https://docs.llamaindex.ai/en/stable/module_guides/loading/loading.html

RAGで使用するインデックスは以下の2つのプロセスになる。

  1. Loading
  • ReaderやLlamaHubのライブラリを使ってデータを読み込んでDocumentオブジェクトにする
  1. Transformations
  • Node Parserを使って、DocumentオブジェクトをパースしてNodeオブジェクトに分割する

これらを一つにまとめてパイプライン化したのがingestion pipeline

kun432kun432

SimpleDirectoryReader

https://docs.llamaindex.ai/en/stable/module_guides/loading/simpledirectoryreader.html

  • ローカルファイルを配置したディレクトリからデータを読み込むReader。
  • 様々なファイル形式に対応している

こんな感じで色々用意してみた。

テキストファイル

from pathlib import Path
import requests

# Wikipediaからのデータ読み込み
wiki_titles = ["イクイノックス", "ドウデュース"]
for title in wiki_titles:
    response = requests.get(
        "https://ja.wikipedia.org/w/api.php",
        params={
            "action": "query",
            "format": "json",
            "titles": title,
            "prop": "extracts",
            # 'exintro': True,
            "explaintext": True,
        },
    ).json()
    page = next(iter(response["query"]["pages"].values()))
    wiki_text = page["extract"]

    data_path = Path("data")
    if not data_path.exists():
        Path.mkdir(data_path)

    with open(data_path / f"{title}.txt", "w") as fp:
        fp.write(wiki_text)

PDFファイル

https://www.jcci.or.jp/news/2023/1024150051.html

!wget -O data/202203invoice_booklet.pdf https://www.jcci.or.jp/chusho/202203invoice_booklet.pdf

読み込む

from llama_index import SimpleDirectoryReader

reader = SimpleDirectoryReader(input_dir="./data", recursive=True)
documents = reader.load_data()

以下のような感じで、ファイル形式によってはパッケージ追加インストールが必要になる場合もある

ImportError: pypdf is required to read PDF files: `pip install pypdf`

パッケージ追加して再度実行してみるとうまくいく

!pip install pypdf
from llama_index import SimpleDirectoryReader

reader = SimpleDirectoryReader(input_dir="./data", recursive=True)     # recursiveでディレクトリ内を再帰的に読む
documents = reader.load_data()
len(documents)
32

32個のDocumentオブジェクトとして読み込まれている。試しにいくつか見てみる。

documents[0]
Document(
  id_='e75460c6-393f-422a-93af-df28969d54f3',
  embedding=None,
  metadata={
    'page_label': '1',
    'file_name': '202203invoice_booklet.pdf',
    'file_path': 'data/202203invoice_booklet.pdf',
    'file_type': 'application/pdf',
    'file_size': 5412574,
    'creation_date': '2023-12-27',
    'last_modified_date': '2023-07-20',
    'last_accessed_date': '2023-12-27'
  },
  excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
  excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
  relationships={},
  hash='a3da613bb7a38e38476e3418b4e4c9cf74ead4291441961a0a5298dfca642cbc',
  text='中 小 企 業・小 規 模 事 業 者 のための\nインボイス制度 対 策 [第3版]\n中 小 企 業・小 規 模 事 業 者 のための\nインボイス制度 対策  [第3版]2023年10月から\nインボイス制度がスタート!\n大切な\nポイントが\nわかる!\n請 求 書\n※は軽減税率対象東京商店 (株) 御中\n2023年10月分\n登録番号\u3000\nT1234・ ・ ・\n10月15日\n550円 10月15日割りばし\n牛\u3000肉※5,400円\n合\u3000計\n43,600円 (10%対象\u300022,000円\u3000消費税\n 2,000円)(8%対象\u300021,600円\u3000消費税\n 1,600円)(株) 大阪商事令和5年度\n税制改正対応版\n令和5年度\n税制改正対応版', 
  start_char_idx=None,
  end_char_idx=None,
  text_template='{metadata_str}\n\n{content}',
  metadata_template='{key}: {value}', metadata_seperator='\n'
)
documents[-1]
Document(
  id_='18f2bf2b-f00a-446d-ab97-aabc65d25e7c',
  embedding=None,
  metadata={
    'file_path': 'data/ドウデュース.txt',
    'file_name': 'ドウデュース.txt',
    'file_type': 'text/plain',
    'file_size': 9481,
    'creation_date': '2023-12-27',
    'last_modified_date': '2023-12-27',
    'last_accessed_date': '2023-12-27'
 },
 excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
 excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
 relationships={},
 hash='b64e5a99cfc2bf24436e0651f7ff3dd8d2dfadeddbea9d50a7e0e90a4bfeaa99',
 text='ドウデュース(欧字名:Do Deuce、2019年5月7日 - )は、日本の競走馬。主な勝ち鞍は2021年の朝日杯フューチュリティステークス、2022年の東京優駿、2023年の有馬記念。(sni@)曾祖母Darling Dameは1986年凱旋門賞馬ダンシングブレーヴのいとこにあたる。\n\n\n== 脚注 ==\n\n\n=== 注釈 ===\n\n\n=== 出典 ===\n\n\n== 外部リンク ==\n\n競走馬成績と情報 netkeiba、スポーツナビ、JBISサーチ、Racing Post',
 start_char_idx=None,
 end_char_idx=None,
 text_template='{metadata_str}\n\n{content}',
 metadata_template='{key}: {value}',
 metadata_seperator='\n'
 )

PDFは各ページごとにDocumentオブジェクト化されているのに対し、テキストファイルは1ファイルがそのまま1Documentオブジェクトになっていた。このあたりはファイル形式によって異なる模様。

また、試しにExcelファイルを置いてみたが、文字化けしてて読めなかった(そもそもExcelには対応していルトは書いてないのだけども)

ファイル形式によって、読み込めるか、読み込まれた場合にどういうふうに読み込まるか、は変わるということだけをとりあえず覚えておけば良い。

その他色々あるけども、まあ必要になったら見ればいいと思う。

kun432kun432

Data Connectors (LlamaHub)

https://docs.llamaindex.ai/en/stable/module_guides/loading/connector/root.html

様々なデータソースやデータ形式に対応するデータコネクタ(Reader)を集めたレポジトリがLlamaHub。これを使うにはdownload_loaderを使う。

例えば、上の例でダメだったExcelファイルの場合は、Pandas Excel Loaderが使えそう。

https://llamahub.ai/l/file-pandas_excel?from=all

from pathlib import Path
from llama_index import download_loader

PandasExcelReader = download_loader("PandasExcelReader")

loader = PandasExcelReader(pandas_config={"header": 0})
excel_documents = loader.load_data(file=Path('./data.xlsx'))
excel_documents
[
  Document(
    id_='9d951670-9014-4c1f-a76a-75f11ac42762',
    embedding=None,
    metadata={},
    excluded_embed_metadata_keys=[],
    excluded_llm_metadata_keys=[],
    relationships={},
    hash='594f1fd0db524834019e83ef9855b12f4c96af38b351a0d79cee3930f91805a1',
    text='1\n1\n母子手帳を受け取りたいのですが、手続きを教えてください。\n窓口で妊娠届をご記入いただき、母子手帳をお渡しします。(snip)ご利用するWebサイトまたはチャットボットの説明資料などに明記ください。\nA:\u3000CC-BY 4.0 子育てオープンデータ協議会\u3000(文字表記)\nB:\u3000https://licensebuttons.net/l/by/3.0/88x31.png By 子育てオープンデータ協議会 (画像表記)',
    start_char_idx=None,
    end_char_idx=None,
    text_template='{metadata_str}\n\n{content}',
    metadata_template='{key}: {value}',
    metadata_seperator='\n'
  )
]
kun432kun432

Document/Node/Node Parser

https://docs.llamaindex.ai/en/stable/module_guides/loading/documents_and_nodes/root.html

  • Document
    • データソース(たとえばPDF、APIの出力、データベースから取得したデータなど)を含む一般的なコンテナ。
    • データローダーを使って自動で作成 or 手動で作成が可能
    • 複数の属性とともにテキストを格納する
      • メタデータ: テキストに付与するアノテーション情報
      • リレーション: 他のドキュメント/ノードとの関係性に関する情報
  • Node
    • LlamaIndexのデータの最小単位であり、ソースとなるDocumentの「チャンク」
    • Documentと同様に、メタデータやリレーション情報を含む

Node ParserはDocumentオブジェクトをNode=チャンクに分割する、要はxxxxSpliterと考えれば良さそう。

https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/root.html

上で作ったdocumentsを使う。

# SimpleDirectoryReaderで読み込んだdocumentsにPandasExcelReader出読み込んだものを追加
documents.extend(excel_documents)
from llama_index import Document
from llama_index.node_parser import SentenceSplitter

node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=50)

nodes = node_parser.get_nodes_from_documents(
    documents, show_progress=True
)
len(nodes)

449個のNodeに分割された。

449

ピックアップしてみてみる。

nodes[149:151]
[
  TextNode(
    id_='9b687c00-5841-4ae4-9649-882713d8fc20',
    embedding=None,
    metadata={
      'file_path': 'data/ドウデュース.txt',
      'file_name': 'ドウデュース.txt',
      'file_type': 'text/plain',
      'file_size': 9481,
      'creation_date': '2023-12-27',
      'last_modified_date': '2023-12-27',
      'last_accessed_date': '2023-12-27'
    },
    excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
    excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
    relationships={
      <NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(
        node_id='568f4341-6bf9-4e26-8b77-182a95d936e0',
        node_type=<ObjectType.DOCUMENT: '4'>,
        metadata={
          'file_path': 'data/ドウデュース.txt',
          'file_name': 'ドウデュース.txt',
          'file_type': 'text/plain',
          'file_size': 9481,
          'creation_date': '2023-12-27',
          'last_modified_date': '2023-12-27',
          'last_accessed_date': '2023-12-27'
        },
        hash='b64e5a99cfc2bf24436e0651f7ff3dd8d2dfadeddbea9d50a7e0e90a4bfeaa99'
      ),
      <NodeRelationship.PREVIOUS: '2'>: RelatedNodeInfo(
        node_id='d12f6d8e-9fab-467a-8b7d-1d90432ad999',
        node_type=<ObjectType.TEXT: '1'>,
        metadata={
          'file_path': 'data/イクイノックス.txt',
          'file_name': 'イクイノックス.txt',
          'file_type': 'text/plain',
          'file_size': 25415,
          'creation_date': '2023-12-27',
          'last_modified_date': '2023-12-27',
          'last_accessed_date': '2023-12-27'
        },
        hash='1d09584cb35290a2642b0c6bf5d296be2353136b8943fcba860cccae2d6b31e4'
      ),
      <NodeRelationship.NEXT: '3'>: RelatedNodeInfo(
        node_id='5dee61bf-3b74-482d-b612-00c412d3be98',
        node_type=<ObjectType.TEXT: '1'>,
        metadata={},
        hash='d29995ad87707ad3415b1985c05b30a73015ff3211b85f18fd0228b4c2413d39'
      )
    },
    hash='0f62a418d1e1d6de46fe1faa0305161cb264586ec836ee125bd067bc499d8fb3',
    text='ドウデュース(欧字名:Do Deuce、2019年5月7日 - )は、日本の競走馬。主な勝ち鞍は2021年の朝日杯フューチュリティステークス、2022年の東京優駿、2023年の有馬記念。\n馬名の意味は「する+テニス用語(勝利目前の意味)」。愛称は「おドウ」。   2021年のJRA賞最優秀2歳牡馬である。\n\n\n== 戦績 ==\n\n\n=== デビュー前 ===\n2019年5月7日、北海道安平町のノーザンファームで誕生。松島正昭が代表を務める株式会社キーファーズの所有馬となり、ノーザンファーム空港牧場で育成の後、栗東トレーニ   ングセンターの友道康夫厩舎に入厩した。',
    start_char_idx=0,
    end_char_idx=279,
    text_template='{metadata_str}\n\n{content}',
    metadata_template='{key}: {value}',
    metadata_seperator='\n'
  ),
  TextNode(
    id_='5dee61bf-3b74-482d-b612-00c412d3be98',
    embedding=None,
    metadata={
      'file_path': 'data/ドウデュース.txt',
      'file_name': 'ドウデュース.txt',
      'file_type': 'text/plain',
      'file_size': 9481,
      'creation_date': '2023-12-27',
      'last_modified_date': '2023-12-27',
      'last_accessed_date': '2023-12-27'
    },
    excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
    excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'],
    relationships={
      <NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(
        node_id='568f4341-6bf9-4e26-8b77-182a95d936e0',
        node_type=<ObjectType.DOCUMENT: '4'>,
        metadata={
          'file_path': 'data/ドウデュース.txt',
          'file_name': 'ドウデュース.txt',
          'file_type': 'text/plain',
          'file_size': 9481,
          'creation_date': '2023-12-27',
          'last_modified_date': '2023-12-27',
          'last_accessed_date': '2023-12-27'
        },
        hash='b64e5a99cfc2bf24436e0651f7ff3dd8d2dfadeddbea9d50a7e0e90a4bfeaa99'
      ),
      <NodeRelationship.PREVIOUS: '2'>: RelatedNodeInfo(
        node_id='9b687c00-5841-4ae4-9649-882713d8fc20',
        node_type=<ObjectType.TEXT: '1'>,
        metadata={
          'file_path': 'data/ドウデュース.txt',
          'file_name': 'ドウデュース.txt',
          'file_type': 'text/plain',
          'file_size': 9481,
          'creation_date': '2023-12-27',
          'last_modified_date': '2023-12-27',
          'last_accessed_date': '2023-12-27'
        },
        hash='0f62a418d1e1d6de46fe1faa0305161cb264586ec836ee125bd067bc499d8fb3'
      ),
      <NodeRelationship.NEXT: '3'>: RelatedNodeInfo(
        node_id='4b3e0968-4178-459b-911c-f8759d084b42',
        node_type=<ObjectType.TEXT: '1'>,
        metadata={},
        hash='e45c32813d927fb3b2cfc5d4897bb6156d42b7e042c509d9a2ecfb7ca869098f'
      )
    },
    hash='d29995ad87707ad3415b1985c05b30a73015ff3211b85f18fd0228b4c2413d39',
    text='=== 2歳(2021年) ===\n9月5日に小倉競馬場で行われた2歳新馬戦(芝1800メートル)に武豊鞍上で出走。1番人気に推されると、レースは直線でガイアフォースとの追い比べをクビ差制してデビュー勝ちを果たした。\n次走はリステッド競走のアイビーステークスを選択。2番人気に推され、レースでは追い比べから抜け出すと、最後は追い込んできたグランシエロをクビ差凌いで優勝、デビュー2連勝とした。\n続いて朝日杯フューチュリティステークスに出走。重賞勝ち馬セリフォスやジオグリフをはじめとした自身と同じ無敗馬が多く顔を揃える中、3番人気に支持される。レースでは直線で外に出すと、先に抜け出していたセリフォスを半馬身差で差し切り優勝、無傷3連勝でGI初制覇を果たした。鞍上の武豊はこの競走22回目の挑戦で初制覇となり、日本の中央競馬 (JRA) の平地GI完全制覇までホープフルステークスを残すのみとした。また馬主である松島及びキーファーズにとっては初の単独所有馬によるGI勝利、並びに国内GI初制覇となった。',
    start_char_idx=282,
    end_char_idx=733,
    text_template='{metadata_str}\n\n{content}',
    metadata_template='{key}: {value}',
    metadata_seperator='\n'
  )
]

テキストが分割されるだけではなく、メタデータでファイルの情報や、あと他のNodeとの関係性の情報が付与されているのがわかる。

今回SentenceSplitterを使ったけども、果たしてこれ日本語でも正しく動作するのかな?すくなくともchunk_overlapは効いていないような気もする。

Node Parserはいくつかの種類がある。

https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/modules.html

少し気になったので、いくつかテキストベースのものの動きだけ確認してみたい。

kun432kun432

Sentence Splitter

documentを直接作成する。

from llama_index import Document

text_list = [
    "イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。\n2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」。2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。\n主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。",
    "吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。この書生というのは時々我々を捕えて煮て食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。",
    "Repeat after me. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
]
documents = [Document(text=t) for t in text_list]
for i, d in enumerate(documents):
    print(i, d.to_dict()["text"])

各行ごとにdocumentになっている。

0 イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。
2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」。2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。
主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。
1 吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。この書生というのは時々我々を捕えて煮て食うという話である。しかしその当時は何という考もなかったから別段恐しいとも思わなかった。ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。
2 Repeat after me. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

SentenceSplitterでチャンクサイズとオーバーラップを指定してみる。

from llama_index import Document
from llama_index.node_parser import SentenceSplitter

node_parser = SentenceSplitter(chunk_size=20, chunk_overlap=5)

nodes = node_parser.get_nodes_from_documents(
    documents, show_progress=True
)

for i, n in enumerate(nodes):
    print(i, n.to_dict()["text"])
Metadata length (0) is close to chunk size (20). Resulting chunks are less than 50 tokens. Consider increasing the chunk size or decreasing the size of your metadata to avoid this.
Metadata length (0) is close to chunk size (20). Resulting chunks are less than 50 tokens. Consider increasing the chunk size or decreasing the size of your metadata to avoid this.
Metadata length (0) is close to chunk size (20). Resulting chunks are less than 50 tokens. Consider increasing the chunk size or decreasing the size of your metadata to avoid this.
0 イクイノックス(欧字名:Equino
1 quinox、2019年3月23日 -
2 月23日 - )は、日本の競走馬。
3 2022年にキタサンブラック産駒
4 産駒として初のGI制覇を果たし、
5 を果たし、2023年には秋春グランプ
6 グランプリ制覇を達成した。馬名の意
7 馬名の意味は「昼と夜の長さが
8 の長さがほぼ等しくなる時」。202
9 」。2022年度のJRA賞年度代表馬
10 度代表馬、最優秀3歳牡馬であ
11 馬である。
主な勝ち鞍は2022
12 は2022年・2023年の天皇賞(
13 皇賞(秋)連覇、2022年の有
14 22年の有馬記念、2023年のドバイ
15 年のドバイシーマクラシック、宝塚記
16 宝塚記念、ジャパンカップ。
17 吾輩は猫である。
18 名前はまだ無い。
19 どこで生れたかとんと見当がつかぬ。何で
20 何でも薄暗いじめじめした所でニャー
21 所でニャーニャー泣いていた事だけは記
22 事だけは記憶している。吾輩はこ
23 輩はここで始めて人間というものを見た
24 ものを見た。しかもあとで聞くとそれは
25 くとそれは書生という人間中で一番獰
26 で一番獰悪な種族であったそうだ。
27 たそうだ。この書生というのは時々我
28 は時々我々を捕えて煮て食うと
29 て食うという話である。しかしその当時は
30 その当時は何という考もなかったから別段
31 から別段恐しいとも思わなかった。ただ
32 った。ただ彼の掌に載せられてスー
33 られてスーと持ち上げられた時何だかフ
34 時何だかフワフワした感じがあったばか
35 あったばかりである。
36 Repeat after me. Lorem ipsum dolor sit amet, consectetur adipiscing elit,
37 consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
38 Ut enim ad minim veniam,
39 quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
40 Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
41 esse cillum dolore eu fugiat nulla pariatur.
42 nulla pariatur. Excepteur sint occaecat cupidatat non proident,
43 sunt in culpa qui officia deserunt mollit anim id est laborum.

ふむ、日本語でも英語でもチャンクサイズとオーバーラップは効いている。ただ、「我輩は猫である」のところだけ文章単位で分割されていてオーバーラップされていないところと、ちゃんとオーバーラップされているところの両方がある。

Warningっぽいものが出ているので、チャンクサイズ等を少し少しいじってみる。

from llama_index import Document
from llama_index.node_parser import SentenceSplitter

node_parser = SentenceSplitter(chunk_size=50, chunk_overlap=10)

nodes = node_parser.get_nodes_from_documents(
    documents, show_progress=True
)

for i, n in enumerate(nodes):
    print(i, n.to_dict()["text"])
0 イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。
2022年にキタサンブ
1 022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制
2 秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」。
3 2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。
主な勝ち鞍は2022年・20
4 は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシー
5 023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。
6 吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。
7 何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
8 吾輩はここで始めて人間というものを見た。
9 しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。
10 この書生というのは時々我々を捕えて煮て食うという話である。
11 しかしその当時は何という考もなかったから別段恐しいとも思わなかった。
12 ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。
13 Repeat after me. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
14 Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
15 Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

オーバーラップなしにしてみる。

from llama_index import Document
from llama_index.node_parser import SentenceSplitter

node_parser = SentenceSplitter(chunk_size=50, chunk_overlap=0) 

nodes = node_parser.get_nodes_from_documents(
    documents, show_progress=True
)

for i, n in enumerate(nodes):
    print(i, n.to_dict()["text"])
0 イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。
2022年にキタサンブ
1 ラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。
2 馬名の意味は「昼と夜の長さがほぼ等しくなる時」。
3 2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。
主な勝ち鞍は2022年・20
4 23年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝
5 塚記念、ジャパンカップ。
6 吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。
7 何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
8 吾輩はここで始めて人間というものを見た。
9 しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。
10 この書生というのは時々我々を捕えて煮て食うという話である。
11 しかしその当時は何という考もなかったから別段恐しいとも思わなかった。
12 ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。
13 Repeat after me. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
14 Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
15 Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

んー、なんだろう、短すぎる文章だとむしろわかりにくいかもしれない。

ざっとコード見た限り、

  • デフォルトのチャンクサイズは1024「トークン」で、オーバーラップのデフォルトは200「文字」かな?日本語の場合はどのみち文字数で考えてれば良い気がする。
  • チャンク時のセパレータは日本語の文末(「。」「!」「?」)にも対応している様子。

には見えるのである程度信頼しても良さそうではある。

https://github.com/run-llama/llama_index/blob/main/llama_index/node_parser/text/sentence.py

kun432kun432

Node Parserいろいろあるみたいなので、どういうものがあるのか少しだけ。

https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/modules.html

ファイルベースのNode Parser

特定のファイル形式に特化したNode Parser。

  • SimpleFileNodeParser
    • FlatFileReaderと組み合わせて使うもっともシンプルなもの
    • ざっくり見た感じシンプルにテキストデータにメタデータつけるだけに見える。
  • HTMLNodeParser
    • BeautifulSoupを使ってHTMLタグごとにNode分割する
  • JSONNodeParser
    • JSONをパースしてNode分割する。オブジェクトごとにやってくれたりするんだろうか?
  • MarkdownNodeParser
    • MarkdownをパースしてNode分割する。セクションごとにやってくれる感じ?

Text Splitter

テキストに特化したNodeParser。上で実際に動かしたSentenceSplitter以外にも以下のようなものがある。

  • CodeSplitter
    • シンタックスハイライトのための構文解析ライブラリであるtree-sitterを使ったNodeParser
    • py-tree-sitter-languagesを使っている、対応している言語もここにある
  • LangchainNodeParser
    • LangChainのTextSplitterを使ってNode分割する
  • SentenceWindowNodeParser
    • サンプル見てみたけどいまいちよくわからない。。。
  • TokenTextSplitter
    • 単語単位でNode分割する
    • セパレータが文字列でしか指定できなさそうなので、日本語だと難しそうな気がする

Relation-Based Node Parsers

Node間の関係性に基づいたNodeParser。

  • HierarchicalNodeParser
    • 各Nodeを親子関係に紐づけてNode分割する。
    • AutoMergingRetrieverを使うことで、親子関係に基づいて関連したNodeだけをピックアップする。一貫したコンテキストだけを拾うことができる。

Markdownや、Unstructuredを使った埋め込みテーブルのパースなんかもあるみたい。RAGでは最適なコンテキストだけを渡したいという思いがあるので、とても興味がある。

https://github.com/run-llama/llama_index/tree/main/llama_index/node_parser/relational

kun432kun432

Node Parserの使い方のバリエーション

https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/root.html

上で書いたのはNodeParserを直接使う使い方。これ以外に以下のようなやり方もある。

  1. Service Contextで使う
  2. Integtion Pipelineで使う

どちらもNodeParserをラップして使う抽象化モジュールのようなイメージ。

Service Contextで使う

Service Contextは、Modelsでも触れたけど、よく使うリソースの「設定」を定義しておけば、個々のリソースを使う処理を書く場合に細かい設定を書かなくてもよいというもの。

https://zenn.dev/link/comments/63ff2bbaa438ad

https://docs.llamaindex.ai/en/stable/module_guides/supporting_modules/service_context.html

Service Contextを使う場合はこんな感じ。

from llama_index import SimpleDirectoryReader, VectorStoreIndex, ServiceContext
from llama_index.text_splitter import SentenceSplitter
from llama_index.embeddings import OpenAIEmbedding

embed_model = OpenAIEmbedding()
text_splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=20)

service_context = ServiceContext.from_defaults(
  embed_model=embed_model,
  text_splitter=text_splitter,
)

documents = SimpleDirectoryReader("./data").load_data()

index = VectorStoreIndex.from_documents(
    documents, service_context=service_context
)

コードを見てる感じ、service_contextは、node_parserとtext_splitterを設定できるのだけど、明確な違いはなくて、どちらか片方を設定すれば良さそう。なので以下のようにも書ける。

node_parser = SentenceSplitter(chunk_size=1024, chunk_overlap=20)

service_context = ServiceContext.from_defaults(
  embed_model=embed_model,
  node_parser=node_parser,
)

コンポーネントのコンセプトというか言葉の定義というか、LangChainにもよく見られるパターンで、この辺が曖昧なんだよね。まあやってるうちにだんだん変わっていったってところなんだと思うのだけど、初学者には結構辛いところ。。。

Ingestion Pipelineで使う

Service Contextは設定を一連の処理で使うのに対して、Ingestion Pipelineはその名の通りパイプライン処理を定義して実行する。

from llama_index import Document
from llama_index.embeddings import OpenAIEmbedding
from llama_index.text_splitter import SentenceSplitter
from llama_index.ingestion import IngestionPipeline, IngestionCache
from llama_index import SimpleDirectoryReader

pipeline = IngestionPipeline(
    transformations=[
        SentenceSplitter(chunk_size=400, chunk_overlap=50),
        OpenAIEmbedding(),
    ],
)

reader = SimpleDirectoryReader(input_dir="./data", recursive=True)
documents = reader.load_data()

nodes = pipeline.run(documents=documents)
nodes[0]
TextNode(
    id_='8ec6d7c8-8b6d-4213-ab2c-9d9ce9ec252c',
    embedding=[
      -0.027578644454479218,
      -0.012237600050866604,
      -0.0008724202634766698,
      (snip)
      -0.015463014133274555,
      0.012359569780528545,
      -0.04813726991415024
    ],
    metadata={
       (snip)
    ,
    text='イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。\n2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」。2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。\n主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。',
    (snip)
)

SentenceSplitterで分割され、Embeddingsが付与された、ノードができているのがわかる。

さらにこれをベクトルDBに保存まで一気に行ってみる。ベクトルDBにはQdrantをオンメモリモードで。

from llama_index import Document
from llama_index.embeddings import OpenAIEmbedding
from llama_index.text_splitter import SentenceSplitter
from llama_index.ingestion import IngestionPipeline, IngestionCache
from llama_index import SimpleDirectoryReader
from llama_index.vector_stores.qdrant import QdrantVectorStore

import qdrant_client

client = qdrant_client.QdrantClient(location=":memory:")
vector_store = QdrantVectorStore(client=client, collection_name="test_store")

pipeline = IngestionPipeline(
    transformations=[
        SentenceSplitter(chunk_size=400, chunk_overlap=50),
        OpenAIEmbedding(),
    ],
    vector_store= vector_store,
)

reader = SimpleDirectoryReader(input_dir="./data", recursive=True)
documents = reader.load_data()

pipeline.run(documents=documents)

ベクトルDBに対して検索をかけてみる。

from llama_index import VectorStoreIndex

index = VectorStoreIndex.from_vector_store(vector_store)
retriever = index.as_retriever(similarity_top_k=5)

result = retriever.retrieve("有馬記念を勝ったのはなんという馬?")

for i in result:
    print("Score: {}\nDocument: {}\nText: {}\n".format(i.get_score(), i.metadata["file_name"], i.get_text().replace("\n","")))
Score: 0.8571984363543428
Document: ドウデュース.txt
Text: 2023年最終戦として有馬記念へ出走。鞍上には武豊が復帰した。鞍上横山和生と本レースがラストランとなっており、レースを牽引して尚直線粘るタイトルホルダーと、二番手から先に仕掛けていた鞍上クリストフ・ルメールのスターズオンアースを抜き去り、先頭でゴール板を駆け抜けて見事復活の勝利を挙げた。武豊は2017年のキタサンブラック以来、6年ぶりの制覇となった。また、54歳9カ月10日での有馬記念勝利は最年長勝利記録であり、同時に自身が持つJRA・GI最年長勝利記録(54歳19日)を更新。ドリームジャーニーやオルフェーヴル、ブラストワンピースに騎乗し歴代最多の有馬記念4勝を挙げている池添謙一に並ぶ勝利数となった。

Score: 0.8510159573066383
Document: イクイノックス.txt
Text: ジャパンカップの親子制覇は史上7度目である。天皇賞(秋)・ジャパンカップを連勝するのは史上5頭目で、宝塚記念を含む3連勝はテイエムオペラオー以来23年ぶり2頭目となる。2着にリバティアイランドが入ったため、馬連のオッズが1.8倍となり、2005年の秋華賞を制したエアメサイアと2着馬のラインクラフトと並び、馬連の低額配当タイの記録となった。GI6連勝はグレード制が導入された1984年以降では、テイエムオペラオー、ロードカナロアのGI競走の連勝記録に並んだ。芝平地の古馬GⅠ6勝は日本馬歴代最多タイ。木村哲也調教師は本競走初制覇。また、クリストフ・ルメールは武豊と並ぶジャパンカップ最多4勝目。そのほかにも、3着に5番人気のスターズオンアースが入ったため、3連単のオッズが11.

Score: 0.8505653801437312
Document: イクイノックス.txt
Text: 鞍上のルメールは「直線は勝ち馬をマークして外に出して追いだしたら、(相手が)伸び返す形になってしまったかな」と振り返った。次走として天皇賞(秋)に出走することを表明した。東京優駿出走後の左前脚のダメージについては、経過は良好とした。10月30日、予定通り天皇賞(秋)に出走。1番人気に推され、好スタートを切ると、前半1000メートルを57秒4で通過するというハイペースで大逃げを図ったパンサラッサを追う形で馬群の中団を追走。最後の直線に入って鞍上のルメールがムチを入れると、逃げ粘るパンサラッサをゴール寸前で後方(ルメール曰く、パンサラッサとの差は約15馬身はあった)からやはりメンバー最速の上がり3ハロン32秒7という末脚を発揮し差し切って勝利。GI初勝利を飾った。

Score: 0.8486584400128439
Document: イクイノックス.txt
Text: 父のキタサンブラックは現役時代に宝塚記念を勝利することがなかったが、産駒である本馬がリベンジを果たすことに成功した。これにより、史上16頭目の有馬記念と宝塚記念の秋春グランプリ制覇を成し遂げたほか、史上21頭目となるJRA獲得賞金10億円を突破した。キャリア8戦目での10億円突破は史上最速。また、騎乗したルメールはJRA・GI通算45勝目、木村調教師は同GI5勝目を挙げた。								次走として連覇のかかる天皇賞(秋)に出走すると表明した。10月12日、ロンジンワールドベストレースホースランキング(2023年1月1日から10月8日までの世界の主要レースを対象)が発表され、イクイノックスはレーティングは129ポンドで変わらず世界第1位となった。10月29日、予定通り天皇賞(秋)に出走。

Score: 0.8478901801718797
Document: イクイノックス.txt
Text: 688票を集め3位となった。12月25日、予定通り有馬記念に出走。単勝2.3倍の1番人気に推された。レースがスタートすると、タイトルホルダーを先頭にそれを追う形で馬群中団のやや後方を追走。3コーナー手前の辺りで外めにつけて動き始め、4コーナーを回って持ったまま上昇。最後の直線に入ってムチを入れると加速していき、他馬の追随を許さず優勝。3歳馬の有馬記念制覇は前年のエフフォーリア以来2年連続、史上21頭目。3歳馬の天皇賞(秋)、有馬記念制覇は前年のエフフォーリア以来2年連続、史上3頭目。キャリア6戦での有馬記念制覇は史上最短。キタサンブラックとの父子制覇を達成した。なお、2着に菊花賞2着のボルドグフーシュが入り、3歳馬がワンツーフィニッシュを飾った。
kun432kun432

Transformation

ここまでに触れてきたTextSplitterやNodeParser、またIngestionPipelineのtransformationオプションで指定したオブジェクトは全てTransformation、つまり変換にあたる。Transformationの定義は、ノードのリストを入力として受け取り、何らかの変換を行って、ノードのリストを返すということらしい。

Transformationオブジェクトは以下のようなものになる。

  • TextSplitter
  • NodeParser
  • Extractors
  • ModelsのEmbeddingモデル

これらはService Contextのtransformations、Ingestion Pipelineのtransformationsで指定できるが、直接使うこともできる。

from llama_index.text_splitter import SentenceSplitter
from llama_index.extractors import TitleExtractor

node_parser = SentenceSplitter(chunk_size=400, chunk_overlap=50)
extractor = TitleExtractor()

nodes = node_parser(documents)
print("ID: {}\nDocument: {}\nTitle: {}\nText: {}\n".format(nodes[0].id_, nodes[0].metadata["file_name"], nodes[0].metadata.get("document_title"), nodes[0].get_text().replace("\n","")))

nodes = await extractor.acall(nodes)
print("ID: {}\nDocument: {}\nTitle: {}\nText: {}\n".format(nodes[0].id_, nodes[0].metadata["file_name"], nodes[0].metadata.get("document_title"), nodes[0].get_text().replace("\n","")))

SentenceSplitterでdocumentをnodeに分割したあと、TitleExtractorというテキストからタイトルを生成してメタデータを付与するTransformationで変換してみた。

結果はこうなる。

ID: 829272ab-14f5-4d1e-9d29-7653b36bc54b
Document: イクイノックス.txt
Title: None
Text: イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」。2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。

ID: 829272ab-14f5-4d1e-9d29-7653b36bc54b
Document: イクイノックス.txt
Title: The Rise and Success of Equinox: A Journey of a Champion Racehorse and the Legacy of Kitasan Black
Text: イクイノックス(欧字名:Equinox、2019年3月23日 - )は、日本の競走馬。2022年にキタサンブラック産駒として初のGI制覇を果たし、2023年には秋春グランプリ制覇を達成した。馬名の意味は「昼と夜の長さがほぼ等しくなる時」。2022年度のJRA賞年度代表馬、最優秀3歳牡馬である。主な勝ち鞍は2022年・2023年の天皇賞(秋)連覇、2022年の有馬記念、2023年のドバイシーマクラシック、宝塚記念、ジャパンカップ。

SentenceSplitterでnodeに分割されたあと、そのnodeがTitleExtractorを通したあとはTitleが生成されているのがわかる。

ちなみにTitleExtractorだけども、

[n.metadata["document_title"] for n in nodes]
['Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats',
 'Equinox: The Journey of a Champion Racehorse from Debut to Triple Crown Victory, with a Look at the Controversy and Close Defeats']

となっていて、複数のnodeからタイトルを生成してくれているようだけども、異なるdocumentの場合も同じドキュメントになっていたりする。他のExtractorも同じかどうかはわからないけど、少し注意したほうがいいかも。

Service ContextでTransformationsを使うパターン。nest_asyncio.apply()しないとエラーになってしまう。Extractorにもよるのかもだけど、TitleExtractorはAsyncでしか使えないような気がする。

from llama_index import SimpleDirectoryReader, ServiceContext, VectorStoreIndex, StorageContext
from llama_index.text_splitter import SentenceSplitter
from llama_index.extractors import TitleExtractor
from llama_index.embeddings import OpenAIEmbedding
from llama_index.vector_stores.qdrant import QdrantVectorStore
import qdrant_client
import nest_asyncio

nest_asyncio.apply()

client = qdrant_client.QdrantClient(location=":memory:")
vector_store = QdrantVectorStore(client=client, collection_name="test_store")

service_context = ServiceContext.from_defaults(
  transformations=[
    SentenceSplitter(chunk_size=400, chunk_overlap=50),
    TitleExtractor(),
    OpenAIEmbedding()
    ]
)

storage_context = StorageContext.from_defaults(
    vector_store=vector_store
)

reader = SimpleDirectoryReader(input_dir="./data", recursive=True)
documents = reader.load_data()

index = VectorStoreIndex.from_documents(
    documents,
    service_context=service_context,
    storage_context=storage_context
)

retriever = index.as_retriever()
result = retriever.retrieve("有馬記念を勝ちました")

for i in result:
    print("Score: {}\nDocument: {}\nText: {}\n".format(i.get_score(), i.metadata.get("document_title"), i.get_text().replace("\n","")))
Score: 0.8198825622551921
Document: イクイノックス(Equinox): キタサンブラック産駒の活躍と血統について
Text: ジャパンカップの親子制覇は史上7度目である。天皇賞(秋)・ジャパンカップを連勝するのは史上5頭目で、宝塚記念を含む3連勝はテイエムオペラオー以来23年ぶり2頭目となる。2着にリバティアイランドが入ったため、馬連のオッズが1.8倍となり、2005年の秋華賞を制したエアメサイアと2着馬のラインクラフトと並び、馬連の低額配当タイの記録となった。GI6連勝はグレード制が導入された1984年以降では、テイエムオペラオー、ロードカナロアのGI競走の連勝記録に並んだ。芝平地の古馬GⅠ6勝は日本馬歴代最多タイ。木村哲也調教師は本競走初制覇。また、クリストフ・ルメールは武豊と並ぶジャパンカップ最多4勝目。そのほかにも、3着に5番人気のスターズオンアースが入ったため、3連単のオッズが11.

Score: 0.8193934592761234
Document: イクイノックス(Equinox): キタサンブラック産駒の活躍と血統について
Text: 2023年最終戦として有馬記念へ出走。鞍上には武豊が復帰した。鞍上横山和生と本レースがラストランとなっており、レースを牽引して尚直線粘るタイトルホルダーと、二番手から先に仕掛けていた鞍上クリストフ・ルメールのスターズオンアースを抜き去り、先頭でゴール板を駆け抜けて見事復活の勝利を挙げた。武豊は2017年のキタサンブラック以来、6年ぶりの制覇となった。また、54歳9カ月10日での有馬記念勝利は最年長勝利記録であり、同時に自身が持つJRA・GI最年長勝利記録(54歳19日)を更新。ドリームジャーニーやオルフェーヴル、ブラストワンピースに騎乗し歴代最多の有馬記念4勝を挙げている池添謙一に並ぶ勝利数となった。

Ingestion Pipelineを使うパターン。

from llama_index import SimpleDirectoryReader, VectorStoreIndex
from llama_index.text_splitter import SentenceSplitter
from llama_index.extractors import TitleExtractor
from llama_index.embeddings import OpenAIEmbedding
from llama_index.vector_stores.qdrant import QdrantVectorStore
from llama_index.ingestion import IngestionPipeline, IngestionCache
import qdrant_client
import nest_asyncio

nest_asyncio.apply()

client = qdrant_client.QdrantClient(location=":memory:")
vector_store = QdrantVectorStore(client=client, collection_name="test_store")

pipeline = IngestionPipeline(
    transformations=[
        SentenceSplitter(chunk_size=400, chunk_overlap=50),
        TitleExtractor(),
        OpenAIEmbedding(),
    ],
    vector_store= vector_store,
)

reader = SimpleDirectoryReader(input_dir="./data", recursive=True)
documents = reader.load_data()

pipeline.run(documents=documents)

index = VectorStoreIndex.from_vector_store(vector_store)

retriever = index.as_retriever()
result = retriever.retrieve("有馬記念を勝ちました")

for i in result:
    print("Score: {}\nDocument: {}\nText: {}\n".format(i.get_score(), i.metadata.get("document_title"), i.get_text().replace("\n","")))
Score: 0.8374040739117069
Document: The Rise and Triumph of Equinox: The Journey of Japan's Champion Racehorse
Text: 2023年最終戦として有馬記念へ出走。鞍上には武豊が復帰した。鞍上横山和生と本レースがラストランとなっており、レースを牽引して尚直線粘るタイトルホルダーと、二番手から先に仕掛けていた鞍上クリストフ・ルメールのスターズオンアースを抜き去り、先頭でゴール板を駆け抜けて見事復活の勝利を挙げた。武豊は2017年のキタサンブラック以来、6年ぶりの制覇となった。また、54歳9カ月10日での有馬記念勝利は最年長勝利記録であり、同時に自身が持つJRA・GI最年長勝利記録(54歳19日)を更新。ドリームジャーニーやオルフェーヴル、ブラストワンピースに騎乗し歴代最多の有馬記念4勝を挙げている池添謙一に並ぶ勝利数となった。

Score: 0.8313921709644743
Document: The Rise and Triumph of Equinox: The Journey of Japan's Champion Racehorse
Text: 688票を集め3位となった。12月25日、予定通り有馬記念に出走。単勝2.3倍の1番人気に推された。レースがスタートすると、タイトルホルダーを先頭にそれを追う形で馬群中団のやや後方を追走。3コーナー手前の辺りで外めにつけて動き始め、4コーナーを回って持ったまま上昇。最後の直線に入ってムチを入れると加速していき、他馬の追随を許さず優勝。3歳馬の有馬記念制覇は前年のエフフォーリア以来2年連続、史上21頭目。3歳馬の天皇賞(秋)、有馬記念制覇は前年のエフフォーリア以来2年連続、史上3頭目。キャリア6戦での有馬記念制覇は史上最短。キタサンブラックとの父子制覇を達成した。なお、2着に菊花賞2着のボルドグフーシュが入り、3歳馬がワンツーフィニッシュを飾った。

Transformation用のオブジェクトを自分で作ることもできる

https://docs.llamaindex.ai/en/stable/module_guides/loading/ingestion_pipeline/transformations.html#custom-transformations

このスクラップは4ヶ月前にクローズされました