Загрузчик JSON

  • JSON (JavaScript Object Notation) - это открытый стандартный формат файла и формат обмена данными, который использует читаемый текст для хранения и передачи объектов данных, состоящих из пар атрибут-значение и массивов (или других сериализуемых значений).

JSON Lines - это формат файла, в котором каждая строка является допустимым значением JSON.

JSONLoader разбирает JSON-файлы с использованием указанного шаблона jq и использует пакет 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_of_some_picture.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

Предположим, что мы хотим извлечь значения из поля content под ключом messages в JSON-данных. Используя JSONLoader, эту задачу легко можно выполнить.

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

data = loader.load()
pprint(data)
[Документ(содержание_страницы='Пока!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1}),
     Документ(содержание_страницы='О, не волнуйтесь! Пока', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2}),
     Документ(содержание_страницы='Нет, извините, это была моя ошибка, синий не продаётся', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 3}),
     Документ(содержание_страницы='Я думал, что вы продаёте синий!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 4}),
     Документ(содержание_страницы='Мне не интересна эта сумка. Мне интересен синий!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 5}),
     Документ(содержание_страницы='Вот $129', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 6}),
     Документ(содержание_страницы='', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 7}),
     Документ(содержание_страницы='Онлайн как минимум $100', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 8}),
     Документ(содержание_страницы='Сколько вы хотите?', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 9}),
     Документ(содержание_страницы='Доброе утро! $50 слишком мало.', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 10}),
     Документ(содержание_страницы='Привет! Я заинтересован в вашей сумке. Я предлагаю $50. Скажите мне, если вас заинтересовало. Спасибо!', метаданные={'источник': '/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 для извлечения page_content из одного JSON-объекта.

file_path = './example_data/facebook_chat_messages.jsonl'
pprint(Path(file_path).read_text())
('{"sender_name": "Пользователь 2", "timestamp_ms": 1675597571851, "content": "Пока!"}\n'
     '{"sender_name": "Пользователь 1", "timestamp_ms": 1675597435669, "content": "О, ничего страшного! Пока"}\n'
     '{"sender_name": "Пользователь 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='Пользователь 2', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 1}),
     Document(page_content='Пользователь 1', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat_messages.jsonl', 'seq_num': 2}),
     Document(page_content='Пользователь 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" отвечает за определение информации о записи, которая должна быть включена в метаданные, которые будут сохранены в итоговом объекте "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)
[Документ(page_content='Пока!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'отправитель': 'Пользователь 2', 'временная_отметка_ms': 1675597571851}),
     Документ(page_content='О, ничего страшного! Пока', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2, 'отправитель': 'Пользователь 1', 'временная_отметка_ms': 1675597435669}),
     Документ(page_content='Нет, извините, это была моя ошибка. Синий не продается', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 3, 'отправитель': 'Пользователь 2', 'временная_отметка_ms': 1675596277579}),
     Документ(page_content='Я подумал, что вы продаёте синий!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 4, 'отправитель': 'Пользователь 1', 'временная_отметка_ms': 1675595140251}),
     Документ(page_content='Мне не интересна эта сумка. Мне интересен синий!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 5, 'отправитель': 'Пользователь 1', 'временная_отметка_ms': 1675595109305}),
     Документ(page_content='Вот $129', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 6, 'отправитель': 'Пользователь 2', 'временная_отметка_ms': 1675595068468}),
     Документ(page_content='', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 7, 'отправитель': 'Пользователь 2', 'временная_отметка_ms': 1675595060730}),
     Документ(page_content='Онлайн это по крайней мере $100', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 8, 'отправитель': 'Пользователь 2', 'временная_отметка_ms': 1675595045152}),
     Документ(page_content='Сколько вы хотите?', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 9, 'отправитель': 'Пользователь 1', 'временная_отметка_ms': 1675594799696}),
     Документ(page_content='Доброе утро! $50 это слишком мало.', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 10, 'отправитель': 'Пользователь 2', 'временная_отметка_ms': 1675577876645}),
     Документ(page_content='Привет! Мне интересна ваша сумка. Предлагаю $50. Дайте знать, если заинтересованы. Спасибо!', метаданные={'источник': '/Users/avsolatorio/WBG/langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 11, 'отправитель': 'Пользователь 1', 'временная_отметка_ms': 1675549022673})]

Здесь мы можем видеть, что эти файлы уже содержат метаданные, связанные с извлеченным содержимым.

Функция metadata_func

Как показано выше, функция metadata_func получает метаданные по умолчанию, сгенерированные JSONLoader. Это позволяет пользователям полностью контролировать формат метаданных.

Например, метаданные по умолчанию содержат ключи source и seq_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='Пока!', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 1, 'sender_name': 'Пользователь 2', 'timestamp_ms': 1675597571851}),
     Document(page_content='О, не беспокойся! Пока', metadata={'source': 'langchain/docs/modules/indexes/document_loaders/examples/example_data/facebook_chat.json', 'seq_num': 2, 'sender_name': 'Пользователь 1', 'timestamp_ms': 1675597435669}),
     ...
     ...
     ... (оставшееся содержимое неизменно для краткости) ...
     ...
     ...
]

Общие структуры JSON для использования шаблонов jq

Нижеприведенный список предоставляет возможные jq_schema, которые пользователи могут использовать в качестве справки для извлечения содержимого из JSON-данных на основе структуры.

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

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

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