Files
anti-plagiarism/docs/INGESTION.md
jze9 99bf14fe6a feat(admin): честная длительность прогона + добор эмбеддингов
Разбор итогов массовой заливки показал в отладке «среднюю длительность прогона»
в 2.8 часа там, где парсинг занимал 50 секунд: started_at пишется в момент
постановки в очередь, а очередь из 173 источников разбирается часами. Теперь
момент реального старта пишется отдельно (run_started_at, миграция 006), а
схема отдаёт обе величины — сколько ждал очереди и сколько работал.

Плюс scripts/ops/reembed_missing.py: документ попадает в корпус сразу, а вектор
для L3 считает отдельная задача; когда worker-gpu или Ollama недоступны, эти
задачи теряются и документ остаётся невидимым для семантического поиска. Скрипт
находит faiss_id IS NULL и переотправляет пачками (dry-run по умолчанию) —
сейчас таких 23 101 из 177 147.

Документация: актуальные цифры корпуса, дубли при повторном прогоне, лимит
OpenAlex, и главное — гипервизор .254 зафиксирован в DR-HA как самая широкая
единая точка отказа (брокер, эмбеддинги, секреты и прокси на одном железе;
подтверждено аварией 28.08).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 16:51:25 +05:00

7.5 KiB
Raw Blame History

Наполнение корпуса — runbook

Текущее состояние (на 2026-08-28)

  • 177 147 документов, русский большинство: ru 99 884, en 76 936, остальные языки — единицы/десятки. Проблема «не с чем сравнивать русские работы» из более ранней версии этого документа закрыта.
  • По источникам: CyberLeninka 99 883, OpenAlex 49 276, PMC 14 910, arXiv 13 077, user_submission (проверенные пользователями работы, не источник для сравнения сами с собой — см. ARCHITECTURE.md §7) 1.
  • Повторный прогон по уже залитым источникам даёт почти одни дубли (типично 1490 из 1500 на источник): прирост дают только новые публикации. Реальный рост корпуса — поднятый limit или новые темы, а не повторный запуск.
  • OpenAlex при массовом запуске упирается в лимит вежливого пула (10 req/s на mailto, общий для всех воркеров) — пауза между страницами поднята до 1с.
  • Добавлен 4-й парсер — PMC (PubMed Central, scripts/parsers/pmc.py), англоязычные научные статьи открытого доступа.
  • Массовое расширение по дисциплинам теперь двумя сидерами: seed_ru_sources.py (русскоязычные, CyberLeninka/OpenAlex lang=ru) и scripts/seed_broad_corpus.py (англоязычные — OpenAlex/arXiv/PMC по широкому списку дисциплин, добавлен позже первой волны).
  • Операционный риск массовой докачки (consumer_timeout RabbitMQ vs долгие таски) закрыт бюджетом времени прогона и worker_prefetch_multiplier=1 — подробности и почему префетч тут главный, см. DR-HA.md §6.

Что подготовлено

  • Парсер CyberLeninka починен (scripts/parsers/cyberleninka.py): раньше слал GET на /api/search → HTTP 405; теперь POST с JSON-телом (mode=articles), authors из списка, чистка <b>/HTML-сущностей. Проверено вживую (5/5 тем) + юнит-тесты (scripts/parsers/tests/), в гейте CI.
  • Прод-путь готов: index.run_parser(source_id) уже умеет cyberleninka и openalex c lang=ru.
  • Сидер источников: scripts/seed_ru_sources.py — 30 студенческих дисциплин.

Запуск русской заливки

# 1. (на app-хосте / в контейнере worker-indexer, где есть psycopg2 и прод-.env
#    — .env на проде теперь генерируется из Infisical на каждом деплое, см.
#    ARCHITECTURE.md §10, руками его не редактировать)
#    Посмотреть план:
python scripts/seed_ru_sources.py
#    Создать источники в parse_sources (лимит на дисциплину):
python scripts/seed_ru_sources.py --apply --limit 500

# 2. Проверить пару источников на темпе/качестве, затем запустить заливку:
#    • Админ-панель → «Источники» → «Запустить» (или «Запустить всё»), ЛИБО
#    • Celery: index.run_parser.delay(source_id) по каждому id

Управление заливкой из админки

Всё, что ниже, доступно на странице «Источники» — CLI для этого больше не нужен:

  • Шкала загрузки у каждого источника: стадия (выборка → индексация), сколько получено из скольки, сколько добавлено/дублей/ошибок. Раскрытая строка — журнал прогона по шагам с таймингами (таблица parse_runs).
  • «Запустить всё» — прогон по всем включённым источникам; уже идущие пропускаются. «Остановить всё» и остановка по одному — кооперативная отмена: воркер останавливается сам на ближайшем тике, не обрывая запись в базу.
  • Пакетное добавление — один тип источника + список тем (по строке), опционально с немедленным запуском. Заменяет seed_*.py для разовых расширений.
  • Загрузка работ в базу — PDF/DOCX/TXT прямо в корпус сравнения (index.ingest_upload, source=manual_upload), минуя проверку и отстойник.
  • Страница «Отладка» — очереди, воркеры, покрытие эмбеддингами, зависшие и упавшие прогоны (см. ARCHITECTURE.md §12).

После большой заливки стоит свериться с покрытием L3 (панель отладки, строка «без вектора»): эмбеддинги считаются отдельной задачей на worker-gpu, и если он или Ollama были недоступны, документы останутся без вектора. Догнать — scripts/ops/reembed_missing.py (dry-run по умолчанию, --apply отправляет).

Прогон со статусом partial — это не ошибка: сработал бюджет времени (PARSER_TIME_BUDGET_S, 1500с), заливка остановилась раньше consumer_timeout RabbitMQ. Остаток добирается повторным запуском источника.

Заливка сама: fetch (rate-limit 1 req/s) → add_document (дедуп по ext_id, fingerprints L1, MinHash L2) → батч-эмбеддинги gpu.embed_documents (L3). ~30 тем × 500 ≈ 15K русских документов на первый заход.

Проверка результата

SELECT lang, count(*) FROM documents GROUP BY lang ORDER BY 2 DESC;   -- должен появиться ru
SELECT source, count(*) FROM documents WHERE source='cyberleninka';   -- > 0

Масштаб (следующий уровень)

  • Больше тем + выше --limit; добавить OpenAlex lang=ru (качество ниже — англ. заголовки с меткой ru).
  • Для миллионов — bulk (снапшот OpenAlex на S3), а не постраничный API.
  • На масштабе обязателен VECTOR_BACKEND=qdrant (FAISS flat не тянет), а таблица fingerprints (уже ~113M строк на 177K доков — партиционирование стоит планировать заранее, не постфактум) потребует партиционирования. См. ARCHITECTURE.md и DR-HA.md.