Задача
Большой каталог образовательного портала построен программатик-способом: страницы генерируются по всем сочетаниям параметров — «тип объекта × станция метро», «тип × район», «тип × город», «профиль × регион». Комбинаторика даёт десятки тысяч посадочных страниц, и это ровно то, за счёт чего такой портал собирает низкочастотный трафик.
Проблема в том, что комбинации генерируются по формуле, а данные распределены неравномерно. Я прогнал полный перебор и посчитал: примерно 4160 сгенерированных страниц не содержали ни одного объекта. Пользователь приходил из поиска на заголовок «частные школы у метро N» и видел пустой экран. Для поисковика это тонкая страница, а тысячи тонких страниц на одном разделе портят оценку всего раздела, а не только самих пустышек.
Отдельно нашлись 4 типа, под которые в базе не было ни одной записи вообще — все страницы этих типов были заведомо пустыми с момента запуска.
Решение
Соблазн — просто убрать пустые страницы из генерации. Я так делать не стал: часть этих комбинаций реально ищут, и удалить страницу значит отдать запрос конкуренту.
Вместо этого — правило ступенчатого расширения выборки. Если по строгому фильтру пусто, страница показывает ближайшее осмысленное расширение, по ступеням:
- тот же тип объекта рядом — у соседних станций в радиусе 3 км;
- тот же тип шире — по всему городу или региону;
- соседние категории — близкие по смыслу типы в той же точке.
Ключевое условие, на котором я настоял: блок расширения всегда честно подписан. Не «12 объектов у метро N», когда их там ноль, а прямая формулировка вида «у этой станции таких нет, вот ближайшие в радиусе 3 км». Расширение выборки не должно выдаваться за точный ответ на запрос — иначе это обман пользователя, и поведенческие метрики это рано или поздно покажут.
Внедрение
Чтобы правило «рядом» вообще работало, нужны координаты. Я собрал их из открытой картографической базы: 88 станций метро и 20 городов области — 108 гео-точек, сложенных в отдельный сгенерированный файл с указанием источника и лицензии. Скрипт сбора лежит в репозитории, так что набор точек можно обновить одной командой, а не руками.
Из четырёх «мёртвых» типов для трёх нашёлся эквивалент среди уже размеченных характеристик объектов — эти страницы теперь фильтруют по нему и наполняются реальными карточками, без всякого расширения. Четвёртый тип я закрыл отдельно, загрузив данные из открытого государственного реестра (об этом — во втором кейсе).
Попутно вылезли два дефекта, которые видно только когда начинаешь считать:
- страница считала объекты поиском по подстроке, а каталог фильтровал точным совпадением — подпись «N объектов» расходилась со списком под ней, а на двух страницах каталог вообще оказывался пустым и при этом без блока расширения;
- заголовки собирались из словаря коротких прилагательных, покрывавшего 12–15 типов из 23. Всё остальное давало H1 вида «Шахматные у метро Сокол» и «Языковые в Химках». Завёл полные названия для всех 23 типов.
Результат
Ни одна из ~4160 страниц больше не отдаёт пустой экран: на каждой есть релевантный список с честной подписью, откуда он взят. Три типа страниц из четырёх «мёртвых» наполнены реальными данными. Заголовки читаемы на всех 23 типах, а расхождение счётчика со списком устранено.
Честная оговорка про сроки: это SEO-изменение, и позиции по таким страницам зреют неделями — писать сюда красивый процент роста через неделю после релиза было бы враньём. Что измеримо прямо сейчас: 4160 тонких страниц перестали быть тонкими, а логика расширения работает на весь каталог сразу, а не на конкретные страницы, — то есть покрывает и все комбинации, которые появятся при следующем пополнении базы.