Заметочник без RAG: как хранить данные в базе и искать без нейросетей

Если вы когда-нибудь теряли заметки, разбросанные по Notepad++, Trello, OneNote и Obsidian, вы не одиноки. Многие разработчики сталкиваются с проблемой фрагментации личных записей, когда важные идеи, ссылки или инструкции оказываются в разных системах, а поиск превращается в квест. В этой статье мы

Заметочник без RAG: как хранить данные в базе и искать без нейросетей

Если вы когда-нибудь теряли заметки, разбросанные по Notepad++, Trello, OneNote и Obsidian, вы не одиноки. Многие разработчики сталкиваются с проблемой фрагментации личных записей, когда важные идеи, ссылки или инструкции оказываются в разных системах, а поиск превращается в квест. В этой статье мы разберем, как построить заметочник на основе реляционной базы данных и полнотекстового поиска, отказавшись от модного RAG. Вы узнаете, почему хранение в PostgreSQL удобнее файлов, как работает поиск без нейросетей и какую архитектуру выбрать для pet-проекта.

Почему база данных, а не файлы

Многие привыкли хранить заметки в виде Markdown-файлов на диске — это просто и привычно. Однако со временем файловая система перестает справляться: ссылки между заметками теряются, теги и метаданные приходится держать в голове или в отдельных файлах, а поиск по содержимому становится медленным. Реляционная база данных, например PostgreSQL, решает эти проблемы. Она обеспечивает целостность данных через транзакции, позволяет строить индексы для быстрого поиска и связывать записи через внешние ключи. Например, можно хранить теги в отдельной таблице и связывать их с заметками, а ссылки между заметками — в таблице связей. Это делает данные структурированными и легко управляемыми.

Почему PostgreSQL — хороший выбор для заметочника?

PostgreSQL — зрелая и мощная СУБД с отличной поддержкой полнотекстового поиска. Она бесплатна, имеет большое сообщество и работает на любом сервере. Для заметочника важны такие возможности, как индексы GIN для текстового поиска, транзакции для атомарного обновления данных и поддержка JSON для гибких метаданных. Кроме того, PostgreSQL легко масштабируется и доступен в российских облаках, что актуально при ограничениях на зарубежные сервисы.

Поиск без RAG: почему классика лучше

RAG (Retrieval-Augmented Generation) — популярный подход, при котором языковая модель ищет релевантные фрагменты в базе и генерирует ответ. Однако для заметочника RAG избыточен и даже вреден. Во-первых, он требует постоянного доступа к LLM, что дорого и медленно. Во-вторых, генерация может галлюцинировать — придумывать факты, которых нет в заметках. В-третьих, пользователю заметочника нужен точный результат, а не пересказ. Поэтому классический полнотекстовый поиск на основе tsvector в PostgreSQL — лучший выбор. Он быстр, точен и не зависит от внешних сервисов.

Как работает полнотекстовый поиск в PostgreSQL?

PostgreSQL поддерживает индексы GIN для полнотекстового поиска. При сохранении заметки текст разбивается на лексемы (слова в нормальной форме) с помощью totsvector. Строится взвешенный вектор терминов, где заголовки и ключевые слова получают больший вес. Поисковый запрос превращается в tsquery через totsquery или plaintotsquery, и система находит документы, где вектор соответствует запросу. Можно ранжировать результаты по релевантности с помощью tsrank, использовать веса для заголовков и основного текста, а также фрагментировать вывод с tsheadline. Это быстрее и надёжнее, чем любой RAG, если не нужно отвечать на вопросы по смыслу, а нужно просто найти заметки по ключевым словам.

Какие есть альтернативы полнотекстовому поиску в PostgreSQL?

Кроме встроенного поиска, можно использовать внешние инструменты вроде Elasticsearch или Sphinx. Однако для небольшого заметочника они избыточны: требуют отдельного сервера, настройки и потребляют больше ресурсов. PostgreSQL справляется с тысячами заметок без проблем, а при росте данных можно добавить репликацию или шардирование. Если же вам нужен семантический поиск (похожие по смыслу заметки), придётся использовать векторные базы данных или RAG, но для большинства сценариев классический поиск достаточен.

Архитектура хранения: теги, ссылки, метаданные

Помимо текста, заметки содержат теги, ссылки на другие заметки и метаданные (дата создания, дата изменения, источник). Всё это хранится в связанных таблицах: notes, tags, notetags, links. Теги нормализованы: есть таблица тегов и таблица связи тегов с заметками, что позволяет быстро находить все заметки по тегу. Ссылки между заметками хранятся как пары (fromnoteid, tonoteid) с обратными индексами. Метаданные можно хранить в колонках или в JSON-поле для гибкости. Для каждого тега и каждой ссылки есть индексы, что обеспечивает быстрый поиск. Такая архитектура легко расширяется: можно добавить таблицу для вложений, категорий или версий заметок.

Кого затронет и как

Статья будет полезна разработчикам, которые пишут свои pet-проекты и ищут простую, но мощную архитектуру для хранения текстовых данных. Особенно тем, кто разочаровался в сложности RAG и хочет получить быстрый, предсказуемый поиск без нейросетей. В российском контексте это актуально, так как доступ к облачным LLM может быть ограничен, а свой сервер с PostgreSQL есть у многих. Если вы устали от разрозненных заметок и хотите собрать всё в одном месте с возможностью быстрого поиска, этот подход для вас.

Что будет дальше

В следующих частях автор планирует рассказать о пользовательском интерфейсе, импорте из Obsidian и других систем, а также о синхронизации между устройствами. Возможно, он добавит поддержку вложений и шифрования. Код проекта открыт, следить за ним можно на GitHub. Если вы хотите внести свой вклад или предложить идеи, добро пожаловать в репозиторий.

Итог

Классический полнотекстовый поиск на PostgreSQL — надёжная альтернатива RAG для заметочников. Он не требует нейросетей, работает быстро и даёт точные результаты. Если вы тоже пишете свой инструмент для заметок, возможно, стоит присмотреться к такому подходу. Хранение в базе данных, нормализованные теги и индексы GIN обеспечат производительность и удобство. Главное — не гнаться за модными технологиями, а выбирать то, что действительно решает задачу.