Как добавить поиск в приложение — от простого фильтра до поиска по смыслу

Поиск выглядит как большая фича. Кажется, нужно что-то умное, «как у Google». Хорошая новость: в девяти случаях из десяти поиск — это один запрос к базе, который ты допишешь за вечер.
А переусложняют его те, кто с первого дня лезет искать «по смыслу», хотя хватило бы совпадения по буквам. Пойдём снизу вверх — и остановишься там, где тебе достаточно.
Сначала ответь на один вопрос
Прежде чем писать код, реши: ищешь по точным словам или по смыслу?
- «Найти заметку со словом отчёт» — по словам. Это просто.
- «Найти заметки про работу, даже если слова «работа» в них нет» — по смыслу. Это дороже и нужно реже, чем кажется.
Начни с поиска по словам. К смыслу перейдёшь, только если реально упрёшься. Большинству проектов первого-второго уровня хватает навсегда.
Уровень 1 — фильтр по списку (5 минут)
Если данных мало и они уже загружены на страницу — не ходи в базу вообще. Отфильтруй прямо в памяти.
const found = notes.filter(n =>
n.title.toLowerCase().includes(query.toLowerCase())
);
toLowerCase с обеих сторон — чтобы «Отчёт» находился по «отчёт». Всё. Для списка в пару сотен строк это мгновенно и не требует ничего нового.
Предел уровня — сотни записей. Дальше грузить всё на клиент станет тяжело, и пора в базу.
Уровень 2 — поиск в базе через LIKE
Когда записей тысячи, фильтровать надо там, где они лежат — в базе данных. На SQL это одна строчка:
select * from notes where title ilike '%отчёт%';
ilike — поиск без учёта регистра, % по краям значит «где угодно в строке». В Supabase то же самое делается методом .ilike('title', '%отчёт%').
Что получится: база сама переберёт хоть миллион строк и вернёт совпадения. Тащить их на клиент не нужно.
Ловушка: ilike '%слово%' с процентом в начале база не может ускорить индексом — на очень больших таблицах он начнёт подтормаживать. Это сигнал перейти на уровень 3.
Уровень 3 — полнотекстовый поиск
Когда ilike стал медленным или хочешь искать по нескольким словам и по-умному (учитывать формы слова), включается полнотекстовый поиск. Он есть прямо в базе — отдельный сервис не нужен.
В Postgres (на нём работает Supabase) это to_tsvector и to_tsquery. Идея: база заранее строит индекс из слов, а потом ищет по нему мгновенно.
select * from notes
where to_tsvector('russian', title || ' ' || body)
@@ to_tsquery('russian', 'отчёт');
Что получится: быстрый поиск по большому тексту, который понимает «отчёт», «отчёты», «отчётом» как одно слово. Для большинства приложений это финальная остановка.
Уровень 4 — поиск по смыслу
Нужен, только если пользователь ищет словами, которых в тексте нет. «Как сэкономить» должно находить заметку про «урезать расходы». Совпадения по буквам тут ноль — а по смыслу это одно.
Здесь в дело идёт векторная база: текст превращается в набор чисел, близких по смыслу. Как это работает под капотом — в разборе про семантический поиск.
Это мощно, но и дороже: нужен вызов модели на каждый текст и на каждый запрос. Не начинай отсюда. Дойди сюда, только когда точный поиск реально не справляется.
Что получится в итоге
Поле ввода, а под ним — список, который сужается по мере набора. Разница только в том, где происходит фильтрация: в памяти (уровень 1), в базе через ilike (уровень 2), через полнотекстовый индекс (уровень 3) или по смыслу (уровень 4). Начни с нижнего и поднимайся, только когда упёрся.
Совет: добавь небольшую задержку перед запросом — 300 мс после последней буквы, — чтобы не бить в базу на каждый символ. Это называется debounce и экономит кучу запросов.
С какого уровня начать новичку?
С первого, если данные уже на странице, иначе со второго — ilike в базе. Это покрывает подавляющее большинство задач и пишется в одну строку. Полнотекст и смысловой поиск подключай по факту боли, а не заранее.
Нужна ли отдельная поисковая система вроде Elasticsearch?
Почти наверняка нет. Отдельный поисковый движок — это лишний сервис, который надо поднимать и синхронизировать с базой. Полнотекстовый поиск внутри твоей базы (уровень 3) закрывает нужды почти любого пет-проекта. Заводи отдельный движок, только когда данных десятки миллионов и штатный поиск явно не тянет.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





