2025, Dec 15 12:02
Как импортировать PDF с метаданными в Google Cloud Discovery Engine без ошибки CONTENT REQUIRED
Разбираем ошибку CONTENT REQUIRED при импорте JSONL в Google Cloud Discovery Engine и даем решение: data_schema=documents, ссылки на PDF в GCS, без id_field.
Загрузка неструктурированных документов вместе с метаданными в хранилище Google Cloud Discovery Engine звучит просто, пока конвейер импорта не начинает отвечать загадочными ошибками. Если вы направляете манифест JSONL на PDF-файлы в Cloud Storage и сталкиваетесь со сбоями, связанными с содержимым, почти наверняка причина — несоответствие между вашей схемой данных и конфигурацией контента в хранилище.
Обзор проблемы
Сценарий простой: создаёте хранилище данных, кладёте в бакет GCS PDF-файлы и манифест JSONL, затем запускаете импорт через Python SDK. В JSONL для каждого документа указаны метаданные и content.uri со ссылкой на PDF. Хранилище настроено как CONTENT REQUIRED. Во время импорта операция падает с сообщениями вида «To create document without content, content config of data store must be NO_CONTENT», повторяющимися для каждой строки JSONL.
Проблемный пример кода
Следующий фрагмент Python вызывает ошибку, если JSONL содержит неструктурированные документы с метаданными, а хранилище настроено как CONTENT REQUIRED:
from google.api_core.client_options import ClientOptions
from google.cloud import discoveryengine
REGION = "your-region"
PROJECT = "your-project-id"
STORE_ID = "your-store-id"
META_URI = "gs://your-bucket/metadata.jsonl"
client_opts = (
ClientOptions(api_endpoint=f"{REGION}-discoveryengine.googleapis.com")
if REGION != "global"
else None
)
svc = discoveryengine.DocumentServiceClient(client_options=client_opts)
parent_branch = svc.branch_path(
project=PROJECT,
location=REGION,
data_store=STORE_ID,
branch="default_branch",
)
req = discoveryengine.ImportDocumentsRequest(
parent=parent_branch,
gcs_source=discoveryengine.GcsSource(
input_uris=[META_URI],
data_schema="custom",
),
id_field="id",
reconciliation_mode=discoveryengine.ImportDocumentsRequest.ReconciliationMode.FULL,
)
op = svc.import_documents(request=req)
print(f"Waiting for operation to complete: {op.operation.name}")
res = op.result()
print(res)
Манифест JSONL выглядит так: в каждой строке описаны метаданные и content.uri, указывающий на PDF в GCS:
{"id": "1", "structData": {"title": "Coldsmokesubmittal", "category": "212027"}, "content": {"mimeType": "application/pdf", "uri": "gs://meta-data-testing/ColdSmokeSubmittal.pdf"}}
{"id": "2", "structData": {"title": "Defssubmittal", "category": "212027"}, "content": {"mimeType": "application/pdf", "uri": "gs://meta-data-testing/DEFSSubmittal.pdf"}}
{"id": "3", "structData": {"title": "Cmu Submittal", "category": "222039"}, "content": {"mimeType": "application/pdf", "uri": "gs://meta-data-testing/CMU_Submittal.pdf"}}
{"id": "4", "structData": {"title": "Concrete Mix Submittal", "category": "222039"}, "content": {"mimeType": "application/pdf", "uri": "gs://meta-data-testing/Concrete_Mix_Submittal.pdf"}}
Что происходит на самом деле
Сообщение об ошибке корректно. Использование data_schema="custom" означает, что вы импортируете только метаданные. В этом режиме Discovery Engine ожидает, что хранилище принимает документы без содержимого, то есть конфигурацию NO_CONTENT. Если же хранилище требует контент (CONTENT REQUIRED), система отклоняет такие записи как неполные. Поэтому переключение хранилища на NO_CONTENT позволяет пройти импорт, но оставляет документы непоисковыми — потому что контент не загружается и, соответственно, не индексируется.
Исправление
Переключите импорт на data_schema="documents", чтобы конвейер загрузил и метаданные, и связанное неструктурированное содержимое. Параметр id_field также нужно опустить. Импорт по‑прежнему указывает на манифест JSONL, где содержатся ссылки content.uri на PDF в Cloud Storage. Схема "documents" правильно интерпретирует ваш JSONL и импортирует PDF вместе с метаданными. Чёткие определения параметра data_schema приведены в официальной документации.
Исправленный пример кода
Ниже приведён скорректированный фрагмент Python, который успешно импортирует PDF вместе с метаданными в хранилище с конфигурацией CONTENT REQUIRED:
from google.api_core.client_options import ClientOptions
from google.cloud import discoveryengine
REGION = "your-region"
PROJECT = "your-project-id"
STORE_ID = "your-store-id"
META_URI = "gs://your-bucket/metadata.jsonl"
client_opts = (
ClientOptions(api_endpoint=f"{REGION}-discoveryengine.googleapis.com")
if REGION != "global"
else None
)
svc = discoveryengine.DocumentServiceClient(client_options=client_opts)
parent_branch = svc.branch_path(
project=PROJECT,
location=REGION,
data_store=STORE_ID,
branch="default_branch",
)
req = discoveryengine.importDocumentsRequest(
parent=parent_branch,
gcs_source=discoveryengine.GcsSource(
input_uris=[META_URI],
data_schema="documents",
),
reconciliation_mode=discoveryengine.ImportDocumentsRequest.ReconciliationMode.FULL,
)
op = svc.import_documents(request=req)
print(f"Waiting for operation to complete: {op.operation.name}")
res = op.result()
print(res)
Почему это важно
От правильного выбора схемы данных зависит, загрузите ли вы только метаданные или действительно внесёте неструктурированный контент для поиска. Схема "documents" обрабатывает content.uri, подтягивает PDF‑файлы и индексирует их текст, сохраняя ваши кастомные поля в structData. Это позволяет обогащать выдачу полями вроде project_number и фильтровать результаты поиска через API на основе этих метаданных.
Результат
После перехода на data_schema="documents" и удаления id_field импорт завершается успешно. Пользовательское поле project_number из манифеста корректно разбирается, и по нему можно фильтровать результаты поиска через API.
Вывод
Если в вашем манифесте JSONL указаны content.uri для неструктурированных файлов, а хранилище ожидает реальный контент, не импортируйте с data_schema="custom". Используйте data_schema="documents" и оставьте конфигурацию хранилища CONTENT REQUIRED. Этот подход импортирует и содержимое файлов, и ваши метаданные, делая документы доступными для поиска и сохраняя поля, необходимые для фильтрации и управления релевантностью.