JSONローダー

  • JSON(JavaScript Object Notation)は、属性と値のペアおよび配列(またはその他の直列化可能な値)からなるデータオブジェクトを格納および転送するために可読性の高いテキストを使用するオープン標準のファイル形式およびデータ交換形式です。

JSON Linesは、各行が有効なJSON値であるファイル形式です。

JSONLoaderは、指定されたjqパターンを使用してJSONファイルを解析し、jq Pythonパッケージを利用します。jq構文の詳細なドキュメントについては、関連するPythonドキュメントを参照してください。

from langchain_community.document_loaders import JSONLoader
import json
from pathlib import Path
from pprint import pprint

file_path = './example_data/facebook_chat.json'
data = json.loads(Path(file_path).read_text())
pprint(data)
{'image': {'creation_timestamp': 1675549016, 'uri': 'image_of_the_chat.jpg'},
     'is_still_participant': True,
     'joinable_mode': {'link': '', 'mode': 1},
     'magic_words': [],
     'messages': [{'content': 'バイ!',
                   'sender_name': 'ユーザー2',
                   'timestamp_ms': 1675597571851},
                  {'content': '大丈夫です!バイ',
                   'sender_name': 'ユーザー1',
                   'timestamp_ms': 1675597435669},
                  {'content': '違います、申し訳ありません。青いものは販売対象ではありません',
                   'sender_name': 'ユーザー2',
                   'timestamp_ms': 1675596277579},
                  {'content': '青いものを販売していると思っていました!',
                   'sender_name': 'ユーザー1',
                   'timestamp_ms': 1675595140251},
                  {'content': 'このバッグには興味がありません。青いものに興味があります!',
                   'sender_name': 'ユーザー1',
                   'timestamp_ms': 1675595109305},
                  {'content': 'こちらは$129',
                   'sender_name': 'ユーザー2',
                   'timestamp_ms': 1675595068468},
                  {'photos': [{'creation_timestamp': 1675595059,
                               'uri': 'いくつかの写真のURL.jpg'}],
                   'sender_name': 'ユーザー2',
                   'timestamp_ms': 1675595060730},
                  {'content': 'オンラインでは最低$100です',
                   'sender_name': 'ユーザー2',
                   'timestamp_ms': 1675595045152},
                  {'content': 'いくら欲しいですか?',
                   'sender_name': 'ユーザー1',
                   'timestamp_ms': 1675594799696},
                  {'content': 'おはようございます!$50は低すぎます。',
                   'sender_name': 'ユーザー2',
                   'timestamp_ms': 1675577876645},
                  {'content': 'こんにちは!あなたのバッグに興味があります。 $50で提供しています。興味があれば教えてください。ありがとう!',
                   'sender_name': 'ユーザー1',
                   'timestamp_ms': 1675549022673}],
     'participants': [{'name': 'ユーザー1'}, {'name': 'ユーザー2'}],
     'thread_path': 'inbox/ユーザー1 と ユーザー2 チャット',
     'title': 'ユーザー1 と ユーザー2 チャット'}

JSONLoaderの使用

JSONデータのmessagesキーの下のcontentフィールドから値を抽出したいとします。JSONLoaderを使用することで、このタスクを簡単に達成できます。

loader = JSONLoader(
    file_path='./example_data/facebook_chat.json',
    jq_schema='.messages[].content')

data = loader.load()
pprint(data)
[Document(page_content='バイ!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1}),
     Document(page_content='大丈夫です!バイ', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2}),
     Document(page_content='いや、申し訳ありません。青い方は売り物ではありませんでした', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 3}),
     Document(page_content='青い方を販売していると思っていました!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 4}),
     Document(page_content='私はこのバッグに興味がありません。青い方に興味があります!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 5}),
     Document(page_content='こちらは$129です', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 6}),
     Document(page_content='', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 7}),
     Document(page_content='オンラインでは少なくとも$100です', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 8}),
     Document(page_content='いくらほしいですか?', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 9}),
     Document(page_content='おはようございます!$50は低すぎます。', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 10}),
     Document(page_content='こんにちは!あなたのバッグに興味があります。$50をオファーしています。興味があれば教えてください。ありがとうございます!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11})]

JSON Linesファイル

JSON Linesファイルからドキュメントを読み込みたい場合は、json_lines=Trueを渡し、jq_schemaを指定して単一のJSONオブジェクトからpage_contentを抽出する必要があります。

file_path = './example_data/facebook_chat_messages.jsonl'
pprint(Path(file_path).read_text())
('{"sender_name": "User 2", "timestamp_ms": 1675597571851, "content": "さようなら!"}\n'
     '{"sender_name": "User 1", "timestamp_ms": 1675597435669, "content": "大丈夫、さようなら"}\n'
     '{"sender_name": "User 2", "timestamp_ms": 1675596277579, "content": "いやごめん、私のミスだった、青いのは売り物じゃないんだ"}\n')
loader = JSONLoader(
    file_path='./example_data/facebook_chat_messages.jsonl',
    jq_schema='.content',
    json_lines=True)

data = loader.load()
pprint(data)
[Document(page_content='さようなら!', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 1}),
     Document(page_content='大丈夫、さようなら', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 2}),
     Document(page_content='いやごめん、私のミスだった、青いのは売り物じゃないんだ', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 3})]

他のオプションとして、jq_schema='.'を設定し、content_keyを指定します:

loader = JSONLoader(
    file_path='./example_data/facebook_chat_messages.jsonl',
    jq_schema='.',
    content_key='sender_name',
    json_lines=True)

data = loader.load()
pprint(data)
[Document(page_content='User 2', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 1}),
     Document(page_content='User 1', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 2}),
     Document(page_content='User 2', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 3})]

メタデータの抽出

通常、JSONファイルからドキュメントに含めるメタデータを抽出したいと思います。

次の例では、JSONLoaderを使用してメタデータを抽出する方法を示します。

前の例では、メタデータを収集しませんでしたが、スキーマでpage_contentの値を直接抽出できる場所を指定しました。

.messages[].content

現在の例では、ローダーにレコードをmessagesフィールドで繰り返すように指示する必要があります。そのため、jq_schemaは次のようにする必要があります。:

.messages[]

これにより、レコード(辞書)を"metadata_func"に渡して、実装する必要のある"metadata_func"に含めるべきレコード情報を識別します。"metadata_func"は最終的に"Document"オブジェクトに格納されるメタデータを含める責任があります。

さらに、ローダーで明示的にcontent_keyパラメータを指定して、レコード内のどのキーから"page_content"の値を抽出するかを指定する必要があります。

def metadata_func(record: dict, metadata: dict) -> dict:

    metadata["sender_name"] = record.get("sender_name")
    metadata["timestamp_ms"] = record.get("timestamp_ms")

    return metadata

loader = JSONLoader(
    file_path='./example_data/facebook_chat.json',
    jq_schema='.messages[]',
    content_key="content",
    metadata_func=metadata_func
)

data = loader.load()
pprint(data)
[Document(page_content='さようなら!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'User 2', 'timestamp_ms': 1675597571851}),
     Document(page_content='大丈夫です!さようなら', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2, 'sender_name': 'User 1', 'timestamp_ms': 1675597435669}),
     Document(page_content='いいえ、私の間違いでした。青いのは販売していません', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 3, 'sender_name': 'User 2', 'timestamp_ms': 1675596277579}),
     Document(page_content='青いのを販売していると思っていました!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 4, 'sender_name': 'User 1', 'timestamp_ms': 1675595140251}),
     Document(page_content='このバッグには興味がありません。青いのに興味があります!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 5, 'sender_name': 'User 1', 'timestamp_ms': 1675595109305}),
     Document(page_content='$129です', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 6, 'sender_name': 'User 2', 'timestamp_ms': 1675595068468}),
     Document(page_content='', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 7, 'sender_name': 'User 2', 'timestamp_ms': 1675595060730}),
     Document(page_content='オンラインでは少なくとも$100です', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 8, 'sender_name': 'User 2', 'timestamp_ms': 1675595045152}),
     Document(page_content='いくらほしいですか?', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 9, 'sender_name': 'User 1', 'timestamp_ms': 1675594799696}),
     Document(page_content='おはようございます!$50はあまりにも安いです。', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 10, 'sender_name': 'User 2', 'timestamp_ms': 1675577876645}),
     Document(page_content='こんにちは!バッグに興味があります。$50で提供します。興味があれば知らせてください。ありがとうございます!', metadata={'source': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11, 'sender_name': 'User 1', 'timestamp_ms': 1675549022673})]

ここでは、これらのファイルにはすでに抽出したコンテンツに関連するメタデータが含まれていることが分かります。

metadata_func 関数

上記のようにして、metadata_funcJSONLoader によって生成されたデフォルトのメタデータを受け取ります。これにより、ユーザーはメタデータのフォーマットを完全に制御できます。

例えば、デフォルトのメタデータには sourceseq_num のキーが含まれています。しかし、JSONデータにはこれらのキーが含まれることもあります。ユーザーは metadata_func を使用して、デフォルトのキーの名前を変更し、JSONデータからキーを使用することができます。

以下の例は、source を修正して langchain ディレクトリに関連するファイルソース情報のみを含める方法を示しています。

def metadata_func(record: dict, metadata: dict) -> dict:

    metadata["sender_name"] = record.get("sender_name")
    metadata["timestamp_ms"] = record.get("timestamp_ms")

    if "source" in metadata:
        source = metadata["source"].split("/")
        source = source[source.index("langchain"):]
        metadata["source"] = "/".join(source)

    return metadata

loader = JSONLoader(
    file_path='./example_data/facebook_chat.json',
    jq_schema='.messages[]',
    content_key="content",
    metadata_func=metadata_func
)

data = loader.load()
pprint(data)
[Document(page_content='Bye!', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'User 2', 'timestamp_ms': 1675597571851}),
     Document(page_content='Oh no worries! Bye', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2, 'sender_name': 'User 1', 'timestamp_ms': 1675597435669}),
     ...
     ...
     ...(簡潔さのために残りのコンテンツは変更せずに省略されています)...
     ...
     ...
]

jqパターンを使用した一般的なJSON構造

以下のリストは、構造に基づいてJSONデータからコンテンツを抽出する際に参考にできる可能性のある jq_schema を提供しています。

JSON        -> [{"text": ...}, {"text": ...}, {"text": ...}]
jq_schema   -> ".[].text"

JSON        -> {"key": [{"text": ...}, {"text": ...}, {"text": ...}]}
jq_schema   -> ".key[].text"

JSON        -> ["...", "...", "..."]
jq_schema   -> ".[]"