Research Protocol
Методология Affiliate.Careers
Открытый и воспроизводимый протокол: как данные собираются, очищаются, оцениваются и публикуются в каталоге и аналитике.
1. Цель исследования
Собрать рынок вакансий affiliate / iGaming / crypto из Telegram-источников, очистить шум, объединить дубли, оценить качество карточек и публиковать результаты в формате открытых данных.
Важно: это срез рынка Telegram-каналов, а не полная модель всего рынка труда.
2. Источники и слои данных
tg_messages: неизменяемый RAW-слой сообщений.tg_message_parse_runs: результаты парсинга и классификации (версионированно).jobs: канонические вакансии после дедупликации.job_sources: связи вакансии с источниками/постами.analytics_daily_*: ежедневные агрегаты для публичной аналитики.analytics_mv_*: materialized views для ускорения тяжелых аналитических запросов и weekly-отчетов.
3. Пайплайн обработки
- Ingest: импорт сообщений Telegram в RAW-слой.
- Classify: типизация сообщения (vacancy/promo/resume/other).
- Split: деление мульти-вакансий на отдельные элементы.
- Extract: извлечение полей (заголовок, компания, зарплата, контакты, теги).
- Dedup: объединение дублей в каноническую вакансию.
- AI moderation: автопроверка спорных кейсов и применение high-confidence решений.
- Publish: публикация в каталог/feeds и обновление аналитических rollup.
Плановый цикл обновления: каждый час.
4. Правила фильтрации
- Украинский язык: сообщения с устойчивыми украинскими маркерами исключаются из публикации.
- Каналы-исключения: источники без контактов для отклика или с системным редиректом на внешний сайт могут быть отключены.
- Промо/шум: сообщения с рекламными паттернами и отсутствием структуры вакансии отправляются в review.
5. Формула Quality Score (0..100)
Итоговый quality score вакансии рассчитывается как сумма компонент:
Q = T + C + S + Sn + L + W + A + D + R + V Где: T (title quality) = 0..7 C (company present) = 0..18 S (salary raw present) = 0..18 Sn (salary numeric parsed) = 0..8 L (location present) = 0..10 W (work_format != unknown) = 0..10 A (apply contacts present) = 0..14 D (description richness) = 0..8 R (multi-source confidence) = 0..3 V (direct/verified bonus) = 0..7
Актуальная версия формулы: qscore-v1.0. Значения и флаги сохраняются в jobs.quality_score и jobs.quality_flags.
6. Публичные индексы и формулы
Salary Transparency Index (%) = jobs_seen_with_salary_raw / jobs_seen_count * 100 Salary Numeric Share (%) = jobs_seen_with_salary_numeric / jobs_seen_count * 100 Employer Transparency Index (%)= jobs_seen_with_company / jobs_seen_count * 100 Contacts Coverage (%) = jobs_seen_with_contacts / jobs_seen_count * 100 Remote Share (%) = jobs_seen_remote / jobs_seen_count * 100 Channel Noise Rate (%) = repost_jobs_total / unique_jobs_total * 100
Индексы публикуются на страницах /market-pulse/ и /channels/.
7. Воспроизводимость: как повторить расчеты
Ниже минимальный набор шагов для независимой перепроверки.
# 1) Миграции / Migrations bash scripts/db/migrate.sh # 2) Полный hourly-проход / Full hourly pass bash scripts/pipeline/run_hourly_pipeline.sh # 3) Пересчет quality + rollup за 90 дней / Rebuild quality + rollups php scripts/analytics/build_rollups.php --days=90
Для ретроспективы можно запускать: --from=YYYY-MM-DD, --quality_only=1, --rollup_only=1.
Проверка через SQL (сырые данные vs витрины)
-- Raw -> published sanity SELECT count(*) AS raw_messages FROM tg_messages; SELECT count(*) AS active_jobs FROM jobs WHERE status='active'; -- Index quality coverage SELECT count(*) FILTER (WHERE salary_raw IS NOT NULL AND btrim(salary_raw) <> '') AS jobs_with_salary_raw, count(*) FILTER (WHERE company_raw IS NOT NULL AND btrim(company_raw) <> '') AS jobs_with_company, count(*) FILTER (WHERE work_format <> 'unknown') AS jobs_with_format FROM jobs WHERE status='active'; -- Check latest day in analytics rollups SELECT day, jobs_seen_count, jobs_seen_with_salary_raw, jobs_seen_with_company FROM analytics_daily_jobs ORDER BY day DESC LIMIT 7;
Проверка через публичные API/feed
- /feeds/jobs.json.php?limit=50 — карточки вакансий
- /feeds/analytics.json.php?limit=30 — ежедневные индексы
- /feeds/changelog.ndjson.php?limit=50 — изменения вакансий
- /feeds/product-changelog.ndjson.php?limit=20 — изменения системы
8. Ограничения и риски
- Смещение выборки: охватываются только выбранные Telegram-каналы.
- Неполные поля: зарплата/компания/локация могут отсутствовать в источнике.
- Извлечение не идеально: возможны ошибки в тегировании и классификации.
- Дедуп и AI-модерация имеют пороговые решения, а не абсолютную истину.
9. Проверка корректности публикации
- Сверка raw-поста и карточки вакансии через
job_sources. - Сверка индексов с daily-таблицами
analytics_daily_jobs/channels. - Проверка трендов и полноты данных через публичные feeds.
10. Публичные агрегированные данные и мониторинг
- Daily индексы рынка: /feeds/analytics.json.php
- Daily индексы (табличный формат): /feeds/analytics.csv.php
- Недельные отчеты: /reports/ и URL-паттерн
/reports/weekly-YYYY-WW/. - Мониторинг свежести и качества пайплайна:
/admin/analytics/
Система алертов отправляет Telegram-уведомления при падении hourly-пайплайна и резком росте доли unknown_work_format.
11. Извлечение skill-тегов
Скиллы выделяются детерминированно (regex v2) по словарю алиасов RU/EN из config/skills_aliases.php. Это снижает шум и делает тренды воспроизводимыми без black-box модели.
- Источник версии:
analytics_daily_skills.source = regex_v2. - Покрытие: рекламные источники трафика, трекеры, ad-networks, CRM/BI, языки программирования.
- Механика: normalize text → match aliases → dedupe tags → daily aggregation.