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

Как выглядит
Пользователь печатает «куда сходить в Москве в выходные». Сервер:
-
Берёт текст запроса, добавляет префикс
query: - Прогоняет через BERT-модель — получает вектор из 384 чисел
- Сравнивает косинусной близостью с векторами всех 1117 сайтов
- Сортирует по убыванию, отдаёт 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
Можно и другие модели подцепить?
Да всё можно. Тут то выбрана очень легковестная, у меня VPS слабенький очень. Да и цель была изучить, как тут всё работает. А приделать можно любую, ИМХО.