Elasticsearch для мобильного приложения: где ломается поиск
Поиск в приложении редко проектируют заранее: обычно он вырастает из запроса «найти подстроку в названии» к основной базе. Пока в каталоге сотни позиций и один сервер, это работает незаметно. Как только ассортимент растёт и пользователей становится больше, поиск превращается в узкое место, которое тормозит и каталог, и оформление заказа.
Первая точка отказа — релевантность выдачи. Поиск по точному вхождению не находит товар при опечатке, другом порядке слов или падеже: «кроссовки мужские» находится, «мужские кроссовки для бега» — уже нет. Elasticsearch закрывает это разбором запроса на словоформы, словарями синонимов и нечётким сопоставлением — но только когда анализаторы, веса полей и правила приоритета настроены под конкретный каталог, а не оставлены по умолчанию.
Вторая точка отказа — подсказки и автодополнение. Каждое нажатие клавиши отправляет запрос, и очередь растёт быстрее, чем каталог. Медленный поиск здесь виден сразу: пользователь набирает слово, не получает подсказок и закрывает приложение.
Третья — нагрузка на серверную часть. Поисковые запросы конкурируют за те же ресурсы, что транзакции и оплата: тяжёлые выборки по подстроке отнимают мощность у того, что должно отвечать мгновенно, и тормозит уже всё приложение. Поэтому поиск выносят в отдельный слой — разбираем, где именно он ломается и как это закрывается.
Эффект от переработки поискового слоя: скорость и точность
До переработки поиск в приложении выполнялся запросами к основной базе: каждый введённый символ порождал выборку по нескольким таблицам со сравнением по шаблону. На пиковых нагрузках такие запросы конкурировали с операциями оформления заказа, отклик выдачи рос до секунд, а часть обращений отваливалась по времени ожидания — пользователь видел пустой экран вместо результатов.
Поисковый слой вынесли на Elasticsearch и построили отдельные индексы под товары, категории и подсказки. Индексы обновляются по событиям изменения каталога, полная перестройка идёт в фоне и не блокирует выдачу. Время отклика сократилось на порядок и перестало зависеть от объёма каталога: то, что раньше деградировало при росте ассортимента, теперь держится ровно.
Точность выдачи выросла за счёт трёх механизмов. Автодополнение показывает варианты с первых введённых символов, исправление опечаток подхватывает запросы с ошибками в раскладке и пропущенными буквами, словарь синонимов сводит разные формулировки одного товара к общей выдаче. Доля релевантных результатов в первой десятке выросла с двух третей до почти полной — считаем её на размеченной выборке реальных запросов, а не на тестовых сценариях.
Отдельный эффект — снятая с основной базы нагрузка. Поисковые запросы больше до неё не доходят, поэтому пиковые всплески обслуживаются без деградации оформления заказов. Ушёл целый класс отказов: пустые выдачи и обрывы по времени ожидания на распродажах и в момент рассылок, которые раньше закрывали ручным масштабированием. Поисковый слой поглощает всплеск сам, а при недоступности подсказок выдача продолжает работать в урезанном режиме вместо полного отказа.
Варианты организации поиска: Elasticsearch и альтернативы
Поиск в приложении почти никогда не строится на одной технике: выбор зависит от объёма каталога, требований к релевантности и того, насколько терпимо приложение к задержке ответа. Ниже — четыре рабочих варианта, между которыми реально выбирают, и их ограничения.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Запросы к основной базе | Каталог до нескольких тысяч записей, поиск по названию, нет требований к опечаткам | Слабое ранжирование результатов; каждый запрос нагружает транзакционную базу |
| Отдельный поисковый сервис (Elasticsearch) | Большой каталог, нечёткий поиск, морфология, фасеты, опечатки | Нужен свой контур: индексация, репликация, мониторинг; данные живут с задержкой от основной базы |
| Кэш подсказок | Автодополнение и частотные запросы, где важна моментальность | Не заменяет полноценный поиск: покрывает только популярные запросы, требует прогрева и сброса при обновлении данных |
| Гибридная схема | Каталог растёт, поиск уже стал узким местом | Сложнее эксплуатация: два хранилища, синхронизация и правила, что считать источником истины |
Схемы совместимы и допускают переход: поиск прячется за единым интерфейсом приложения. Старт на запросах к базе, добавление кэша подсказок и вынос в отдельный поисковый сервис не требуют переписывать клиент — меняется только реализация за интерфейсом. Индексация идёт асинхронно из основной базы, поэтому поиск остаётся рабочим, пока строится новый индекс.
Этапы внедрения: от аудита запросов до передачи
Поиск в приложении ломается чаще не в момент подключения движка, а на стыке: фразы, которые вводят люди, не совпадают с тем, как размечены данные. Поэтому работы идём последовательно, и каждый этап заканчивается артефактом, который можно проверить до перехода к следующему.
- Аудит запросов. Собираем реальные поисковые фразы из логов и размечаем по сценариям — каталог, автодополнение, опечатки и раскладка, повторные запросы. На выходе карта узких мест: где выдача пустая, где релевантность проваливается, где пользователь уходит после первой страницы.
- Схема индексов. Проектируем структуру под эту разметку: какие поля текстовые, какие фильтруемые, где нужны синонимы, морфология и разбор опечаток. Отдельно решаем, что хранить в индексе, а что подтягивать из основной базы, чтобы данные не расходились.
- Настройка выдачи. Анализ языка, веса полей, правила ранжирования по категориям, постраничная выдача и подсказки. Логику релевантности описываем и версионируем — Elasticsearch здесь исполнитель, а не источник правил.
- Проверка на трафике. Новую выдачу включаем на часть реальных пользователей и сравниваем с прежней: доля запросов с переходом в карточку, позиция целевого товара, время ответа. Решение о полном включении принимаем по цифрам, а не по впечатлению.
- Наблюдаемость. Настраиваем метрики и оповещения: доля пустых выдач, ошибки индексации, отставание обновлений. Это раннее предупреждение вместо жалоб пользователей.
- Передача поддержки. Отдаём конфигурации в репозитории, схемы, инструкцию по переиндексации и откату, проводим разбор с командой заказчика. Готово, когда синонимы и правила меняются без нас.
Конфигурации, схемы индексов и регламенты сопровождения
Поиск, который мы настраиваем, передаётся вместе с полным комплектом артефактов — не «чёрным ящиком», а набором конфигураций и правил, по которым систему можно развивать и сопровождать своими силами. Ниже — что именно остаётся у вашей команды после сдачи.
- Схемы индексов — маппинги полей и настройки анализаторов под морфологию, опечатки и транслитерацию, с пояснением, почему поле хранится именно так.
- Правила обновления данных — что и с какой периодичностью попадает в индекс, как обрабатываются удаления и частичные сбои, как проходит полная переиндексация без простоя.
- Конфигурации окружений — параметры контуров разработки, тестирования и промышленного с явно описанными отличиями.
- Регламент сопровождения — что делать при росте каталога, смене структуры карточек и плановом обновлении движка.
- Мониторинг поиска — доля запросов без результатов, время ответа, доля запросов с переходом к заказу и пороги срабатывания оповещений.
- Резервное копирование и откат — полные и инкрементальные копии индексов, порядок восстановления и время возврата поиска в рабочее состояние.
- Документация — развёртывание с нуля, карта типовых отказов и точки, куда смотреть в первую очередь при деградации.
Каждый пункт проверяется на приёмке: мы показываем, как поднять контур с нуля по документации и воспроизвести конфигурацию. Такой комплект означает, что поиск в приложении можно развивать и сопровождать без нас — или вместе с нами, когда объём работ растёт.
Кейс: как поиск по каталогу ускорился после переработки
Каталог на несколько десятков тысяч позиций — тот случай, когда поиск перестаёт быть второстепенной функцией. В сервисе с широким ассортиментом запросы уходили напрямую в основную базу: каждый введённый символ порождал тяжёлый запрос по всей таблице товаров, подсказки возвращались за 1,5–2 секунды, а нужный товар попадал в первую пятёрку лишь в 38% запросов.
Причина была не только в скорости. Поиск не понимал опечаток, словоформ, синонимов и латинской раскладки, поднимал снятые с продажи позиции выше актуальных. Поддержка получала поток обращений «товар есть, но поиск его не находит».
Что сделали
Мы вынесли поиск в отдельный индекс на Elasticsearch — основная база перестала быть узким местом, а ранжирование стало управляемым. Настроили анализаторы под русский и латинский ввод: словоформы, синонимы, транслитерацию, устойчивость к опечаткам и лишним пробелам. Добавили бустинг по наличию на складе, популярности и новизне, чтобы редкие и снятые позиции не поднимались над ходовыми.
Эксплуатацию закрыли отдельно: индекс обновляется инкрементально при изменении каталога, без полной пересборки, а при недоступности поиска приложение отдаёт кэш и штатные категории вместо пустого экрана.
Метрики до и после
| Метрика | До | После |
|---|---|---|
| Время отклика подсказок | 1,5–2 с | около 0,2 с |
| Нужный товар в первой пятёрке | 38% запросов | 87% |
| Обращения в поддержку по поиску | базовый уровень | в 4 раза меньше |
Переключение прошло без остановки сервиса. Через месяц поиск перестал быть местом, куда страшно заходить: пользователи чаще ищут напрямую, а не листают категории, и доля сессий с поисковым запросом выросла без изменений в интерфейсе.
Что делать, если поиск уже развёрнут своими силами
Если поиск уже работает на встроенных средствах — запросах напрямую к базе или локальном индексе на устройстве, — начинать стоит не с переписывания, а с замеров. Смотрим, на каком объёме каталога время ответа перестаёт укладываться в комфортное, как ведёт себя выдача при опечатках, синонимах и смене раскладки, что происходит с базой при пиковой нагрузке. Эти цифры и определяют, нужен ли вообще отдельный поисковый сервис.
Дальше разделяем функциональность по требованиям. Подсказки по вводу, фильтры, сортировка и полнотекстовый поиск с ранжированием — разные задачи, и часть из них спокойно остаётся на встроенном поиске. Обычно выносить имеет смысл только полнотекстовый сценарий, где важны релевантность, морфология и устойчивость к ошибкам ввода, — остальное трогать не нужно.
Переход на поисковый сервис вроде Elasticsearch делаем без простоя: индексы наполняются параллельно с работой приложения, старый контур продолжает отвечать пользователям, а новый получает тот же поток данных и отвечает в теневом режиме. Мы сверяем выдачу на одном наборе запросов, пока расхождения не объяснены, и только потом переключаем долю трафика — сначала на внутренних сотрудниках, затем на небольшом проценте аудитории.
Своя команда при этом не выключается: она держит доменную логику, правила обработки данных и приоритеты выдачи, а мы закрываем схему индексов, репликацию, переиндексацию и поведение при отказах. Откат — это возврат доли трафика и старый контур, который остаётся живым до момента, когда метрики нового стабильны. Поэтому миграция без простоя — не обещание, а следствие того, что две схемы какое-то время работают одновременно.
Технические сомнения: вопросы инженеров и техлидов
Сомнения по Elasticsearch в мобильном приложении сводятся к пяти темам: свежесть данных в индексе, поведение при отказе поискового сервиса, измеримость качества выдачи, рост объёма и поддержка после передачи. Разберём каждую.
Насколько свежие данные попадают в поиск?
Изменения идут в индекс через очередь, а не прямой записью из базы, поэтому сбой поиска не блокирует заказы. Задержка — секунды, у массовых пересборок каталога минуты, а её рост ловит отдельное оповещение.
Что увидит пользователь при отказе поиска?
Несколько узлов с репликами шардов — потеря одного выдачу не прерывает. Если недоступен весь поиск, приложение уходит на резервный путь: запрос к базе по ключевым полям с базовыми фильтрами вместо экрана ошибки.
Как проверить качество выдачи?
До релиза прогоняем эталонный набор запросов с ожидаемыми результатами и считаем полноту и точность. В продакшене смотрим запросы без клика и переформулировки: растут — правим анализатор, синонимы и веса полей.
Выдержит ли поиск рост объёма данных?
Шарды разбиты по времени и типу контента: рост каталога не требует полной переиндексации. Старое уезжает в холодный индекс с меньшим числом реплик, а регламент жизненного цикла чистит его автоматически.
Сможем ли поддерживать поиск своими силами?
Передаём маппинги, анализаторы, политики жизненного цикла, панели мониторинга и оповещения, разбираем с командой типовые операции: добавить поле, переиндексировать, изменить ранжирование. Дальше контур ведёте сами.
Обсудим задачу: разберём схему поиска и вернёмся с планом
Разговор о поиске быстро уходит в общие слова, если прийти к нему без фактов. Чтобы обсудить задачу предметно, достаточно того, что уже есть в проекте: описания текущей схемы индекса, выгрузки реальных запросов пользователей, примеров удачной и неудачной выдачи, ограничений по персональным данным и точек, где приложение обращается к поисковому сервису.
- сценарии поиска: подсказки по мере ввода, исправление опечаток, поиск по фильтрам и сортировкам;
- объём каталога, темп его обновления и требования к свежести выдачи;
- целевое время ответа на запрос и поведение приложения, если поиск недоступен;
- правила доступа: какие поля видны разным ролям и что индексировать нельзя;
- текущая конфигурация Elasticsearch: индексы, анализаторы под языки приложения, реплики;
- план выпуска приложения, к которому нужно привязать работы.
На созвоне проходим по этим данным и разбираем, где именно теряется релевантность: в разборе текста, в наборе полей, в весах или в кэшировании на стороне приложения. Отдельно фиксируем, как переиндексация пройдёт без остановки поиска и на какой схеме откатываемся, если качество выдачи просядет.
Возвращаемся с планом работ: состав работ по этапам, порядок этапов, точки контроля и критерии приёмки — например, доля запросов, где нужный товар или документ попадает в первые три результата. Опишите задачу в свободной форме — вернёмся с оценкой и планом.







