# Как KupujemProdajem ищет по 5,6 миллиона объявлений примерно за 10 мс с помощью Manticore Search

Как крупнейшая площадка объявлений Сербии использует Manticore Search, чтобы искать по 5,6 миллиона активных объявлений примерно за 10 мс, обновлять индекс в реальном времени и готовится к гибридному поиску.

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

[KupujemProdajem](https://www.kupujemprodajem.com/) — крупнейшая площадка объявлений в Сербии. Для пользователей поиск — один из главных способов найти нужный товар: им пользуются и на сайте, и в мобильных приложениях. Сотрудникам поиск тоже нужен для модерации и работы службы поддержки. Поэтому от релевантности и скорости ответа напрямую зависят и вовлечённость пользователей, и то, насколько легко покупатели находят объявления продавцов.

Сегодня KupujemProdajem использует Manticore Search для поиска примерно по **5,6 миллиона активных объявлений**, а отдельные внутренние индексы содержат около **70 миллионов строк** актуальных и исторических данных. Продакшен-кластер в среднем обрабатывает около **150 поисковых запросов в секунду**, а Manticore отвечает на запрос примерно за **10 мс**.

На той же поисковой инфраструктуре команда теперь может решать более сложную задачу — внедрять [гибридный поиск](/blog/hybrid-search/), который объединит лексический и семантический поиск с учётом особенностей сербского языка и самих объявлений.

## Поиск — одна из главных функций продукта

В KupujemProdajem два основных типа поисковых индексов. Первый обслуживает пользовательский поиск. В нём около 5,6 миллиона активных объявлений: заголовки, описания, категории и структурированные атрибуты. Именно по этим данным пользователи ищут на сайте и в мобильных приложениях.

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

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

Как говорит [Димитрие Маринкович](https://www.linkedin.com/in/dimitrije-marinkovi%C4%87-131bb62bb/), бэкенд-разработчик KupujemProdajem:

> «Поиск — основной способ находить объявления на площадке. Поэтому от релевантности и скорости ответа напрямую зависят вовлечённость пользователей и то, насколько успешно продавцы находят покупателей».

## Как выбирали поисковый движок для растущего продукта

KupujemProdajem много лет использовал выделенный поисковый движок. Раньше это был Sphinx. Когда он перестал активно развиваться, команде понадобилась альтернатива с активной поддержкой, которую можно было встроить в существующую архитектуру без полной переделки поисковой интеграции.

Но одной совместимости было недостаточно. Новый движок должен был:

- обеспечивать стабильно низкую задержку;
- [обновлять миллионы объявлений в реальном времени](https://manual.manticoresearch.com/Creating_a_table/Local_tables/Real-time_table);
- поддерживать [репликацию](https://manual.manticoresearch.com/Creating_a_cluster/Setting_up_replication/Setting_up_replication);
- давать [SQL-интерфейс](https://manual.manticoresearch.com/Connecting_to_the_server/MySQL_protocol), совместимый с PHP-стеком команды, построенным вокруг MySQL;
- совмещать [полнотекстовый поиск](https://manual.manticoresearch.com/Searching/Full_text_matching/Basic_usage) с [фильтрацией по структурированным атрибутам](https://manual.manticoresearch.com/Searching/Filters);
- позволять гибко [настраивать релевантность](https://manual.manticoresearch.com/Searching/Options#ranker);
- оставлять возможность в будущем добавить [векторный](/blog/vector-search-deep-dive/) и [гибридный поиск](https://manual.manticoresearch.com/Searching/Hybrid_search).

В Manticore всё это есть в одном движке. И последний пункт со временем становится всё важнее.

KupujemProdajem планирует дополнить традиционный лексический поиск векторным на базе собственной [модели эмбеддингов](/blog/vector-search-in-databases/#embeddings). Manticore поддерживает и [KNN-поиск](https://manual.manticoresearch.com/Searching/KNN), и полнотекстовый поиск в одном движке, поэтому эту функцию можно будет добавить в существующую инфраструктуру без отдельной векторной базы и синхронизации данных с ней.

## Миллионы объявлений обновляются в реальном времени

MySQL по-прежнему остаётся основным источником данных площадки. Когда объявление создают, изменяют или удаляют, Manticore сразу получает соответствующее обновление. В продакшене в среднем выполняется около **40 операций [`REPLACE`](https://manual.manticoresearch.com/Data_creation_and_modification/Updating_documents/REPLACE) в секунду**, а также операции [`UPDATE`](https://manual.manticoresearch.com/Data_creation_and_modification/Updating_documents/UPDATE) и [`DELETE`](https://manual.manticoresearch.com/Data_creation_and_modification/Deleting_documents).

Для площадки объявлений это особенно важно: данные меняются постоянно. Продавцы публикуют новые предложения, обновляют цены и описания, меняют статус объявлений и удаляют товары, которых больше нет в наличии.

Поэтому от поисковой системы одновременно нужны две вещи:

1. быстро находить релевантные результаты;
2. показывать актуальное состояние площадки.

Обновления идут в реальном времени, поэтому поисковый индекс Manticore остаётся синхронизирован с MySQL.

## Поиск — это не только слова

Искать по объявлениям сложнее, чем по обычным документам. Помимо текста, у каждого объявления есть структурированные данные: категория, цена, местоположение, статус и другие свойства. В Manticore KupujemProdajem совмещает полнотекстовый поиск с фильтрацией по этим атрибутам.

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

Кроме того, KupujemProdajem использует [собственный ранкер](https://manual.manticoresearch.com/Searching/Sorting_and_ranking#Ranking-overview), настроенный под свои требования к релевантности, и [группирует результаты](https://manual.manticoresearch.com/Searching/Grouping) по объявлениям. Это позволяет учитывать особенности площадки, а не полагаться только на универсальную формулу ранжирования.

## Небольшой кластер с репликацией

Manticore работает на четырёх виртуальных машинах. Три ноды образуют продакшен-кластер с репликацией, четвёртая используется как резервная. Все записи идут на одну ноду и реплицируются на остальные, а запросы на чтение приложение распределяет между всеми тремя продакшен-нодами.

Архитектура выглядит довольно просто: **MySQL → обновления в реальном времени → нода Manticore для записи → реплики Manticore → поиск на сайте, в мобильном приложении и админке**

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

## 5,6 миллиона активных объявлений и 70 миллионов строк во внутренних индексах

Пользовательские индексы сейчас содержат около **5,6 миллиона активных объявлений** и занимают примерно **9 ГБ**. Более крупные внутренние индексы содержат около **70 миллионов строк**, в том числе исторические данные о части удалённых объявлений, и занимают примерно **90 ГБ**.

Основные показатели продакшен-кластера из трёх нод:

| Метрика | Значение в продакшене |
|---|---:|
| Активные объявления | ~5,6 миллиона |
| Строки во внутренних индексах | ~70 миллионов |
| Размер пользовательских индексов | ~9 ГБ |
| Размер внутренних индексов | ~90 ГБ |
| Поисковая нагрузка | ~150 запросов/с в среднем |
| Поисковая нагрузка на ноду | ~50 запросов/с в среднем |
| Операции `REPLACE` | ~40 операций/с |
| Среднее время запроса | ~10 мс |
| Инфраструктура | 3 виртуальные машины в продакшене + 1 резервная |

При обычной нагрузке кластер работает стабильно: зависших и долгих запросов нет. Иногда время ответа ненадолго вырастает примерно до 150 мс, но в среднем остаётся около 10 мс. Это не синтетический бенчмарк, а показатели реальной продакшен-нагрузки, на которой работает основной поиск крупной площадки объявлений.

## Что эта архитектура даёт пользователям

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

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

## Следующий шаг — лучше понимать запросы на сербском языке

Следующий проект команды KupujemProdajem — [гибридный поиск](/blog/hybrid-search/). Традиционный полнотекстовый поиск лучше всего работает, когда в запросе есть те же слова, что и в объявлении. Но покупатель и продавец могут описывать один и тот же товар совершенно по-разному.

С сербским языком задача становится ещё сложнее. Команде нужно учитывать:

- богатую [морфологию](https://manual.manticoresearch.com/Creating_a_table/NLP_and_tokenization/Morphology);
- два алфавита — латиницу и кириллицу;
- [синонимы](https://manual.manticoresearch.com/Creating_a_table/NLP_and_tokenization/Wordforms);
- то, что покупатели и продавцы по-разному описывают один и тот же товар.

Поэтому KupujemProdajem готовит собственную модель эмбеддингов для объявлений на сербском языке. Идея такая: выполнять [лексический поиск](/use-case/lexical-search/) и KNN-поиск по векторам, а затем объединять их результаты прямо во время запроса.

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

Димитрие формулирует ожидаемый результат так:

> «Семантический поиск поможет пользователям находить подходящие объявления, даже если в запросе нет тех же слов, что и в самом объявлении».

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

## Основа для дальнейшего развития поиска

KupujemProdajem уже использует Manticore в одном из самых важных процессов на площадке: в поиске доступны примерно **5,6 миллиона активных объявлений**, а среднее время запроса к движку составляет **около 10 мс**. Обновления идут непрерывно, репликация даёт несколько поисковых нод, а внутренние команды используют ту же технологию для поиска по гораздо большему объёму исторических данных.

Следующий этап — эксперименты с семантическим поиском и гибридным ранжированием. Для этого команде не придётся менять поисковую инфраструктуру или обслуживать отдельную векторную базу данных.

Сегодня Manticore уже обеспечивает KupujemProdajem быстрый поиск по актуальному каталогу и при этом оставляет команде понятный путь для дальнейшего улучшения поиска.
