Заливка корпуса была чёрным ящиком: у источника только last_status (idle/running/done/error), без «сколько из скольки», без причины падения и без способа остановить начатое. Теперь каждый запуск создаёт строку parse_runs, куда воркер раз в ~2с пишет стадию, счётчики и журнал событий. Админка: - шкала загрузки у каждого источника (0→50% выборка, 50→100% индексация), раскрытая строка — журнал прогона по шагам с таймингами; - «Запустить всё» / «Остановить всё» и остановка по одному источнику (кооперативная отмена: воркер останавливается сам, не рвя запись в базу); - пакетное добавление источников (тип + список тем), тип pmc в форме; - загрузка PDF/DOCX/TXT прямо в базу сравнения (index.ingest_upload); - страница «Отладка»: воркеры Celery и их текущие таски, очереди RabbitMQ, покрытие корпуса эмбеддингами, зависшие и упавшие прогоны, конфиг бэкендов. Защита от краш-лупа по consumer_timeout RabbitMQ (docs/DR-HA.md §6), без неё массовый запуск 170+ источников гарантированно ронял воркер: - PARSER_TIME_BUDGET_S (1500с) — прогон закругляется сам и помечается partial; - worker_prefetch_multiplier=1 — таймаут считается от ДОСТАВКИ сообщения, и с дефолтным префетчем очередь долгих run_parser убивала канал на задачах, которые ещё не начинались. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
88 lines
6.4 KiB
Markdown
88 lines
6.4 KiB
Markdown
# Наполнение корпуса — runbook
|
||
|
||
## Текущее состояние (на 2026-08-27)
|
||
|
||
- **165 480 документов**, русский теперь большинство: `ru` 97 507, `en` 67 646,
|
||
остальные языки — единицы/десятки. Проблема «не с чем сравнивать русские
|
||
работы» из более ранней версии этого документа закрыта.
|
||
- По источникам: CyberLeninka 97 506, OpenAlex 49 218, PMC 10 451, arXiv 8 304,
|
||
`user_submission` (проверенные пользователями работы, не источник для сравнения
|
||
сами с собой — см. ARCHITECTURE.md §7) 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](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 студенческих дисциплин.
|
||
|
||
## Запуск русской заливки
|
||
|
||
```bash
|
||
# 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).
|
||
|
||
Прогон со статусом `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 русских документов на первый заход.
|
||
|
||
## Проверка результата
|
||
|
||
```sql
|
||
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` (уже ~88M строк на 165K доков — партиционирование стоит планировать
|
||
заранее, не постфактум) потребует партиционирования. См.
|
||
[ARCHITECTURE.md](ARCHITECTURE.md) и [DR-HA.md](DR-HA.md).
|