Перейти к содержанию

Счётчики событий и качество данных

Таблица logical_events выбирает одну версию каждого события. Теперь можно строить первые отчёты «Событий»: количество действий по уроку, число анонимных браузеров и календарную динамику. Одновременно добавим показатели качества, чтобы красивое число не скрывало позднюю или повторную доставку.

Результат урока — несколько SQL-запросов с определёнными единицами измерения. Все они используют авторскую фикстуру и не запускались. Ожидаемые значения получены из её содержания. Число уникальных UUID не объявляется числом реальных людей, потому что один человек способен пользоваться несколькими браузерами, а идентификатор может исчезнуть.

Событие и посетитель в одной строке отчёта

Для одного урока количество просмотров может превышать число anon_id: читатель возвращается к материалу. Завершение тоже является событием, а не доказательством нового человека. Поэтому в отчёте нужны отдельные столбцы с ясными названиями.

Полный запрос sql/04-lesson-metrics.sql считает три действия и уникальные браузерные идентификаторы. Читаем логический слой, а не исходные доставки.

SELECT lesson_id,
  countIf(event_name = 'lesson_view') AS views,
  countIf(event_name = 'lesson_complete') AS completions,
  countIf(event_name = 'bookmark') AS bookmarks,
  uniqExact(anon_id) AS anonymous_browsers
FROM events_lab.logical_events
WHERE occurred_at >= toDateTime64('2026-10-01 00:00:00', 3, 'UTC')
  AND occurred_at < toDateTime64('2026-10-05 00:00:00', 3, 'UTC')
GROUP BY lesson_id
ORDER BY lesson_id;

Ожидаем для html-start четыре просмотра, три завершения и две закладки, для css-layout два, два и одну, для js-events один просмотр без остальных действий. По всему набору суммы равны семи, пяти и трём. Повторная доставка завершения a не увеличивает логический счётчик; позднее завершение b увеличивает его после получения.

uniqExact возвращает точное число различных значений выбранного столбца. Документация функции объясняет точный характер и связанную стоимость памяти. Для нашей маленькой фикстуры выбираем точность ради понятного результата; масштабный отчёт может потребовать обсуждения приближённого счёта с обозначенной погрешностью.

Что означает доля завершения

Деление завершений на просмотры даёт отношение событий, а не обязательно конверсию читателей. Посетитель b открыл html-start дважды и завершил один раз. В знаменателе окажутся два просмотра одного браузера, в числителе одно завершение. Если редактор спрашивает, какая доля читателей завершила урок, нужна иная единица наблюдения.

Сначала можно сгруппировать пары anon_id, lesson_id, определить наличие просмотра и завершения, затем считать долю пар. Но даже это не гарантирует порядок действий: завершение могло произойти до рассматриваемого просмотра или вне периода. Следующая глава построит воронку с временным порядком и окном, вместо того чтобы называть любое отношение конверсией.

Показатель должен сопровождаться определением. «Завершения на просмотр» и «доля браузеров с просмотром и последующим завершением за сутки» могут иметь разные значения и одновременно быть корректными. Ошибка начинается, когда одно название скрывает два разных способа расчёта.

Календарные дни без пропусков смысла

Группировка по toDate(occurred_at) показывает день действия в UTC. В логической фикстуре ожидаем шесть событий первого октября, четыре второго, четыре третьего и одно четвёртого. Пятое число имеет доставки, но не новые действия из нашего набора. Это прямое следствие разделения двух времён.

SELECT toDate(occurred_at) AS day, count() AS events
FROM events_lab.logical_events
GROUP BY day
ORDER BY day;

Если за день нет строк, обычный результат не обязательно содержит строку с нулём. Для графика может понадобиться календарь и заполнение отсутствующих дней. Нельзя считать пропущенную строку неизвестным значением в одном графике и нулём в другом без описания. При подключении dashboard договоримся о явном диапазоне и заполнении.

Выбранный период должен быть виден читателю отчёта. Без него название «просмотры» может означать всю историю, текущий месяц или только загруженную фикстуру. Для учебного результата указываем даты и UTC, а время среза добавим в экспорт.

Контроль физической доставки

На исходном слое полезно считать count() - uniqExact(event_id) как грубый признак дополнительных доставок. Для нашей фикстуры ожидаем один повтор. Это не универсальное число дубликатов, если одинаковый идентификатор нарушает контракт или несколько версий описывают исправление. У показателя должен быть предметный смысл первой версии потока.

Задержку анализируем по received_at и occurred_at. Отдельно посчитаем отрицательные значения и строки с задержкой больше суток. Они не обязательно отбрасываются из основного отчёта: позднее реальное завершение должно уточнить историю, если договор допускает такое время. Однако редактор должен знать, что период ещё меняется.

SELECT
  countIf(received_at < occurred_at) AS clock_anomalies,
  countIf(received_at > occurred_at + INTERVAL 1 DAY) AS late_deliveries
FROM events_lab.deliveries;

Здесь поздними будут и позднее событие, и повторная доставка старого завершения. Для анализа работы отправителя это полезно. Для числа поздних уникальных действий нужно выбрать другой слой и другое определение. Единица наблюдения снова меняет вывод.

Когда цифре нельзя доверять

Счётчик может быть математически правильным и предметно неверным. Например, lesson_view отправляется дважды при одном отображении с разными UUID. Дедупликация по event_id не заметит проблему. Или завершение уходит до подтверждения основного приложения: аналитика покажет действие, которого в кабинете нет. Такие ошибки требуют проверки производителя, а не только SQL.

Сравнение периодов одного отчёта

При сравнении октября и сентября сохраните одинаковые определения события, периода и идентификатора. Если в октябре изменилось правило отправки просмотра, рост счётчика может отражать новый производитель, а не аудиторию. Версия контракта и дата изменения помогают объяснить такую границу.

Размер курса тоже влияет на общие суммы. Добавление новых материалов увеличивает возможности просмотра, поэтому изменение общего числа завершений не всегда говорит об улучшении прохождения одного урока. Можно сравнивать одинаковый набор материалов или показывать состав периода отдельно.

Не скрывайте малые числа за красивым процентом. Для одного просмотра и одного завершения получится сто процентов, но это совершенно другой объём наблюдения, чем тысяча пар. Dashboard должен сохранять числитель и знаменатель рядом с долей. Такое представление помогает редактору оценить практический масштаб различия до принятия решения.

В учебных исходниках сохранены контракт и фикстура, чтобы различать качество входа и вычисления. Отчёт должен иметь источник, период, единицу и статус обновления. Следующий урок применит эти требования к воронке: сгруппируем браузер и урок, зададим порядок просмотра и завершения и объясним, почему число дошедших до второго шага ограничено окном времени.

Оглавление серии