Перейти к содержимому
TelegramGitHub

Кейс 2: разбор

Вернитесь к условию кейса, если нужно вспомнить задачу.

Начните с вопросов, не с запросов.

  • Зачем поиск? Чтобы быстро найти человека, группу или обсуждение.
  • Как понять, что поиск справляется? Пользователь ищет и находит. После поиска он нажимает на результат. Потом возвращается к поиску снова.
  • Как измерить качество? Через сессию. Мы смотрим, что пользователь делает за один визит.

Наши гипотезы:

ГипотезаКак проверить
Поиском пользуются часто, он нужен.Доля сессий с подсказками и с полным поиском.
Если поиск хороший, пользователи нажимают на результаты.Клики после search_run.
Если ранжирование хорошее, кликают в основном по первым результатам.Клики по позициям 1–10.
Довольные пользователи возвращаются к поиску.Сколько сессий с функцией в следующие 30 дней.

Поиск удобно оценивать по сессиям. В данных сессии нет, её нужно определить самим.

В этом разборе: сессия — это события одного пользователя без паузы в 10 минут и больше. Если пауза 10 минут или дольше, начинается новая сессия.

Алгоритм:

  1. Для каждого события найдите время предыдущего события этого же пользователя (LAG).
  2. Если предыдущего нет или пауза от 10 минут, пометьте событие как начало сессии.
  3. Нарастающая сумма этих меток даёт номер сессии (SUM() OVER).
  4. Сгруппируйте по пользователю и номеру сессии. Посчитайте события поиска.

Создадим временную таблицу sessions. Она живёт, пока открыта сессия DuckDB, и не меняет вашу базу.

CREATE TEMP TABLE sessions AS
WITH ordered AS (
SELECT user_id, occurred_at, event_name,
LAG(occurred_at) OVER (PARTITION BY user_id ORDER BY occurred_at) AS prev_at
FROM tutorial.yammer_events
WHERE event_type = 'engagement'
), flagged AS (
SELECT *,
CASE WHEN prev_at IS NULL OR occurred_at - prev_at >= INTERVAL 10 MINUTE
THEN 1 ELSE 0 END AS is_new_session
FROM ordered
), numbered AS (
SELECT *,
SUM(is_new_session) OVER (PARTITION BY user_id ORDER BY occurred_at
ROWS UNBOUNDED PRECEDING) AS session_no
FROM flagged
)
SELECT user_id, session_no,
MIN(occurred_at) AS session_start,
COUNT(*) FILTER (WHERE event_name = 'search_autocomplete') AS autocompletes,
COUNT(*) FILTER (WHERE event_name = 'search_run') AS runs,
COUNT(*) FILTER (WHERE event_name LIKE 'search_click_result_%') AS clicks
FROM numbered
GROUP BY user_id, session_no;

Одна строка в sessions — одна сессия. Всего их 67 989. В колонках: сколько раз пользователь использовал подсказки (autocompletes), запустил полный поиск (runs) и нажал на результат (clicks).

Доля сессий с подсказками и с полным поиском по неделям:

-- не запускать отдельно: нужна таблица sessions
SELECT DATE_TRUNC('week', session_start)::DATE AS week,
COUNT(*) AS sessions,
ROUND(AVG((autocompletes > 0)::INT), 3) AS share_autocomplete,
ROUND(AVG((runs > 0)::INT), 3) AS share_search_run
FROM sessions
WHERE session_start >= '2014-06-30'
GROUP BY 1
ORDER BY 1;
НеделяСессийДоля с подсказкамиДоля с полным поиском
2014-07-2142540.2500.081
2014-07-2843430.2630.071
2014-08-0437240.2530.082
2014-08-1135760.2510.082
2014-08-2537210.2500.081

За весь период: подсказки — 25.2% сессий, полный поиск — 8.3%.

Вывод:

  • Доли стабильны по времени.
  • Подсказки используют в каждой четвёртой сессии. Значит, людям нужно искать информацию. Функция заслуживает внимания.
  • Полный поиск используют реже.

Сколько раз пользователь выбирает подсказку за сессию (только сессии, где он это делает):

-- не запускать отдельно: нужна таблица sessions
SELECT autocompletes, COUNT(*) AS sessions
FROM sessions
WHERE autocompletes > 0
GROUP BY 1
ORDER BY 1;
Подсказок за сессиюСессий
110290
24590
31568
4668

Подсказкой пользуются один или два раза. Это нормально.

Теперь то же для полного поиска:

-- не запускать отдельно: нужна таблица sessions
SELECT runs, COUNT(*) AS sessions
FROM sessions
WHERE runs > 0
GROUP BY 1
ORDER BY 1;
Запусков за сессиюСессий
1672
21224
31386
41016
5558
6393
7204
8157

Вывод: если человек запускает полный поиск, он обычно запускает его несколько раз подряд. Чаще всего 2–4 раза. Это странно для функции, которой пользуются реже. Возможные причины:

  • результаты плохие, и пользователь пробует другие слова;
  • есть маленькая группа людей, которым поиск нравится, и они ищут много.

Посмотрим клики в сессиях, где был полный поиск:

-- не запускать отдельно: нужна таблица sessions
SELECT clicks, COUNT(*) AS sessions
FROM sessions
WHERE runs > 0
GROUP BY 1
ORDER BY 1;
Кликов за сессиюСессий
04364
1950
2296

Вывод: в 78% сессий с поиском (4364 из 5610) нет ни одного клика. Пользователь искал и ничего не выбрал.

Растут ли клики, если искать больше?

-- не запускать отдельно: нужна таблица sessions
SELECT runs,
COUNT(*) AS sessions,
ROUND(AVG(clicks), 2) AS avg_clicks
FROM sessions
WHERE runs > 0
GROUP BY 1
ORDER BY 1;
ЗапусковСессийКликов в среднем
16720.26
212240.26
313860.30
410160.29
55580.28
63930.29
72040.21
81570.25

Вывод: среднее число кликов почти не растёт. Больше поисков не приносит больше кликов. Поиск не помогает находить.

Если ранжирование хорошее, клики собираются на первых 2–3 позициях. Проверим:

SELECT REPLACE(event_name, 'search_click_result_', '')::INT AS position,
COUNT(*) AS clicks
FROM tutorial.yammer_events
WHERE event_name LIKE 'search_click_result_%'
GROUP BY 1
ORDER BY 1;
ПозицияКликов
1147
2175
3147
4151
5169
6152
7157
8139
9134
10171

Вывод: клики распределены почти равномерно по всем 10 позициям. Первый результат не лучше десятого. Значит, ранжирование плохое.

Для каждого пользователя берём первую сессию с функцией. Считаем, в скольких сессиях с этой функцией он был за следующие 30 дней (включая первую). Берём только пользователей, чья первая сессия была до 1 августа. Так виден полный месяц.

-- не запускать отдельно: нужна таблица sessions
WITH firsts AS (
SELECT user_id,
MIN(session_start) FILTER (WHERE runs > 0) AS first_run,
MIN(session_start) FILTER (WHERE autocompletes > 0) AS first_auto
FROM sessions
GROUP BY user_id
), run_ret AS (
SELECT f.user_id, COUNT(*) AS n_sessions
FROM firsts f
JOIN sessions s
ON s.user_id = f.user_id AND s.runs > 0
AND s.session_start >= f.first_run
AND s.session_start < f.first_run + INTERVAL 30 DAY
WHERE f.first_run < '2014-08-01'
GROUP BY f.user_id
), auto_ret AS (
SELECT f.user_id, COUNT(*) AS n_sessions
FROM firsts f
JOIN sessions s
ON s.user_id = f.user_id AND s.autocompletes > 0
AND s.session_start >= f.first_auto
AND s.session_start < f.first_auto + INTERVAL 30 DAY
WHERE f.first_auto < '2014-08-01'
GROUP BY f.user_id
)
SELECT LEAST(n_sessions, 6) AS sessions_in_30d, COUNT(*) AS users, 'search_run' AS feature
FROM run_ret GROUP BY 1
UNION ALL
SELECT LEAST(n_sessions, 6), COUNT(*), 'autocomplete'
FROM auto_ret GROUP BY 1
ORDER BY 3, 1;

Значение 6 означает «6 и больше».

Сессий за 30 днейПользователей, полный поискПользователей, подсказки
126471453
23661062
342647
48347
5—192
6 и больше—309

Вывод:

  • Из 3063 пользователей полного поиска 2647 (86%) использовали его только один раз за месяц.
  • Из 4010 пользователей подсказок только 1453 (36%) остановились на одной сессии. Остальные вернулись.

Подсказки удерживают пользователей. Полный поиск — нет.

Что мы увидели:

ФактЦифра
Подсказки используют25% сессий
Полный поиск используют8% сессий
Сессии с поиском без кликов78%
Клики по позициямпочти равномерно
Вернулись к полному поиску14%
Вернулись к подсказкам64%

Вывод: подсказки работают нормально. Полный поиск работает плохо.

Что предложить:

  • Главный фокус — порядок результатов на странице полного поиска.
  • Люди идут в полный поиск, когда подсказки не дали нужного. Возможно, стоит сделать результаты полного поиска немного другими, чем подсказки.
  • Есть разные способы улучшить поиск. Важно, что фокус — полный поиск.

Как проверить, что стало лучше:

  • Запустить A/B-тест нового ранжирования.
  • Метрики успеха: доля сессий поиска с хотя бы одним кликом, сдвиг кликов к первым позициям, возврат к полному поиску в течение 30 дней.
  • Следить и за побочными метриками: использование подсказок не должно упасть.