Статья

Семантический поиск на Rust: как мы нашли сайты в каталоге

Зачем

В каталоге — 1117 сайтов с тайтлами и контентом. Нужен был поиск, который понимает смысл, а не только слова. Обычный LIKE-поиск и стемминг («шина» ≠ «автомобиль») не справлялись с естественными запросами.

Поиск по каталогу сайтов

Как выглядит

Пользователь печатает «куда сходить в Москве в выходные». Сервер:

  1. Берёт текст запроса, добавляет префикс query:
  2. Прогоняет через BERT-модель — получает вектор из 384 чисел
  3. Сравнивает косинусной близостью с векторами всех 1117 сайтов
  4. Сортирует по убыванию, отдаёт JSON-список

Почему Rust

Векторное сравнение — это миллионы операций с плавающей точкой. Rust скомпилировал это в машинный код без рантайма: запрос по 1117 сайтам выполняется за миллисекунды. Тот же прототип на Python отдавал результаты сотни миллисекунд.

Какая модель

intfloat/multilingual-e5-small — единственная серьёзная мультиязычная retrieval-модель с готовым ONNX-экспортом.

Ключевой нюанс: E5 требует префиксы. Документы индексируются с passage:, запросы — с query:. Без этого модель работает заметно хуже — она же обучалась именно на таких парах.

Гибридная выдача

Чистый BERT плохо находит точные вхождения вроде libarea.ru — он мыслит смыслами, а не строками. Мы добавили буст: если запрос дословно есть в URL или тайтле, результат поднимается вверх. Получился гибрид: семантика + точное совпадение.

Стек

  • Rust + Axum — HTTP-сервер
  • ort — ONNX Runtime, прогрев BERT на CPU
  • tokenizers — токенизация
  • MySQL — источник данных (items: url, title, content)
  • Всё хранится в памяти — 1117 векторов × 384 числа это ~1.7 МБ

Что дальше

  • Пагинация уже на фронте
  • Кэширование эмбеддингов в БД — чтобы не перекодировать 1117 сайтов при каждом перезапуске
  • Реальный поиск по контенту страниц (сейчас берётся URL + тайтл + первые 500 символов)
  • Инкрементальная индексация — догружать новые сайты без перезапуска

https://github.com/evgip/vector-search

Демонстрация: каталог сайтов nasua

2 Ответа

  1. Можно и другие модели подцепить?

    1. Да всё можно. Тут то выбрана очень легковестная, у меня VPS слабенький очень. Да и цель была изучить, как тут всё работает. А приделать можно любую, ИМХО.