Apache Solr — поисковый сервер на базе Lucene, который умеет полнотекстовый поиск, фасеты, подсветку, геопоиск, подсказки и распределённые коллекции. Для каталога на сотни тысяч товаров он решает то, с чем плохо справляется реляционная база: релевантность, морфологию, фильтры и быструю выдачу фасетов. Актуальная ветка — Solr 10.1; серверу нужна Java 21.
Когда Solr оправдан
Solr стоит брать, когда поиск — самостоятельная ценность: каталог, документация, вакансии, маркетплейс. Он не заменяет основную базу и не является источником истины: данные индексируются асинхронно. Зато фильтры, фасеты и сортировки работают по индексу, а не по таблицам с JOIN.
- нужен поиск по тексту с русской морфологией и опечатками;
- важны фасеты по бренду, категории, цене и наличию;
- каталог растёт и не помещается в память одного узла;
- допустима задержка индексации в секунды.
Если достаточно поиска по нескольким полям в PostgreSQL, не тащите отдельный кластер: SolrCloud требует ZooKeeper, мониторинга, бэкапов и понимания шардирования. Цена ошибки в конфигурации здесь выше.
Установка и запуск
Скачайте архив Solr 10.1, распакуйте и запустите в режиме SolrCloud. Для разработки допустим встроенный ZooKeeper, в production нужен отдельный ансамбль из трёх или пяти узлов. Не запускайте Solr от root и не держите на публичном интерфейсе без аутентификации.
java -version
tar xzf solr-10.1.0.tgz
cd solr-10.1.0
bin/solr start -c -p 8983 -m 4g
Параметр -m 4g задаёт heap; для среднего каталога это разумный старт, но размер зависит от индекса и кэшей. Не ставьте heap больше половины RAM хоста. Коллекция создаётся с числом шардов и реплик; для одного сервера начните с одного шарда и одной реплики.
bin/solr create -c catalog -s 2 -rf 2
bin/solr healthcheck -c catalog
bin/solr post -c catalog products.json
-s 2 — два шарда, -rf 2 — две реплики на шард. Такая схема переживает потерю одного узла, но требует нескольких хостов. healthcheck показывает состояние коллекции, а post загружает документы из JSON или XML.
Схема и русская морфология
Схема управляемая: файл managed-schema генерируется, править его вручную не стоит. Поля и типы добавляются через Schema API. Для русского текста нужен анализатор с нормализацией регистра, стоп-словами и стеммингом; Snowball даёт предсказуемый результат без внешних словарей.
{"add-field-type":{"name":"text_ru","class":"solr.TextField",
"analyzer":{"tokenizer":{"class":"solr.StandardTokenizerFactory"},
"filters":[{"class":"solr.LowerCaseFilterFactory"},
{"class":"solr.SnowballPorterFilterFactory","language":"Russian"}]}}}
Отправьте JSON в /solr/catalog/schema методом POST. Добавьте поля: title и description типа text_ru, brand_s как строку с docValues, price_i как целое, in_stock_b как булево. Для поиска «по всему» заведите поле text и скопируйте туда заголовок и описание через copyField.
curl -X POST -H 'Content-Type: application/json' \
--data-binary @schema.json \
http://localhost:8983/solr/catalog/schema
curl 'http://localhost:8983/solr/catalog/schema/fields?wt=json'
Для сортировки и фасетов включайте docValues=true, для больших текстов без возврата — stored=false. Подсветка обычно требует stored-поля или term vectors. index=false подходит для полей, нужных только для сортировки, если есть docValues.
Индексация
Документы отправляются в update-handler. Для пакетной загрузки используйте bin/solr post или JSON через curl. Не делайте commit=true на каждый документ: это перестраивает сегменты и убивает производительность. Достаточно commitWithin или периодического soft commit.
curl -X POST -H 'Content-Type: application/json' \
--data-binary @products.json \
'http://localhost:8983/solr/catalog/update?commitWithin=1000'
curl 'http://localhost:8983/solr/catalog/select?q=*:*&rows=0'
Идентификатор должен быть стабильным: повторная отправка с тем же id обновляет документ. Для частичных изменений используйте atomic updates, но каждое обновление — переиндексация. Полную переиндексацию делайте в новую коллекцию и переключайте алиас, чтобы не останавливать поиск.
Запросы и релевантность
Для каталога используют eDisMax: он ищет по нескольким полям с весами, применяет минимальное совпадение и повышает точные фразы. Фильтры выносите в fq — они кэшируются и не влияют на score. Сортировку и фасеты стройте по docValues.
curl -G 'http://localhost:8983/solr/catalog/select' \
--data-urlencode 'q=ноутбук' \
--data-urlencode 'defType=edismax' \
--data-urlencode 'qf=title^3 description' \
--data-urlencode 'fq=in_stock_b:true' \
--data-urlencode 'facet=true' \
--data-urlencode 'facet.field=brand_s'
qf задаёт вес полей, pf повышает фразовые совпадения, mm управляет минимумом совпавших слов. Не ставьте mm=100% для длинных запросов: выдача будет пустой. Для подсказок используйте Suggester, для опечаток — SpellCheck.
Глубокую пагинацию через start=100000 не используйте: координатору придётся собрать весь результат. Для выгрузок берите cursorMark с сортировкой по id. Для подсчёта достаточно rows=0, а фасеты запрашивайте только видимые в интерфейсе.
Эксплуатация
Следите за heap, garbage collection, размером индекса и временем запросов. Метрики Solr отдаёт через /admin/metrics, состояние коллекции — Collections API, логи — server/logs/solr.log. В production включите аутентификацию, TLS и ограничьте доступ к порту 8983.
bin/solr healthcheck -c catalog
curl 'http://localhost:8983/solr/admin/collections?action=CLUSTERSTATUS&wt=json'
curl 'http://localhost:8983/solr/admin/metrics?wt=json&prefix=CONTAINER'
tail -f server/logs/solr.log
Бэкап делайте через Collections API на общий для узлов каталог. Реплики защищают от отказа узла, но не от ошибочного удаления коллекции, поэтому храните копии отдельно. Обновление планируйте с учётом release notes: мажорные версии меняют требования к Java и конфигурации.
curl 'http://localhost:8983/solr/admin/collections?action=BACKUP&name=catalog-2026-11&collection=catalog&location=/srv/backup'
bin/solr auth enable -type basicAuth
Типичные ошибки: один шард на растущий каталог, отсутствие реплик, фасеты по анализируемому тексту, гигантский heap без настройки кэшей и правка managed-schema руками. Это лечится на этапе проектирования, а не в пик нагрузки.
Итог
Solr 10.1 — зрелый поисковый сервер для больших каталогов: морфология, фасеты, подсветка, геопоиск и масштабирование через SolrCloud. Начните с одной коллекции, одного шарда и одной реплики, настройте русский анализатор и вынесите фильтры в fq. Затем добавьте мониторинг, бэкап и алиасы для переиндексации. Если поиск — не ключевая функция продукта, возможно, достаточно средств основной базы — но для каталога с высокими требованиями Solr остаётся предсказуемым выбором.