Ви вводите запит у рядок пошуку документації. З’являються результати. Але що відбулося між натисканням клавіші та результатами? Для більшості платформ документації відповідь або «небагато» (просте зіставлення ключових слів, що пропускає очевидні результати), або «багато інфраструктури» (кластер Elasticsearch, який ваша команда ops повинна підтримувати).
Є золота середина, про яку більшість команд не знає: вбудований повнотекстовий пошук. DocPlatform використовує Bleve, пошукову бібліотеку на Go, скомпільовану безпосередньо в бінарний файл. Жодних зовнішніх сервісів, жодних мережевих викликів, жодних кластерів для управління — але з функціями, які вам дійсно потрібні: стемінг, нечітке зіставлення, підсилення полів і ранжування за релевантністю.
Ось як це працює від основ.
Чому зіставлення ключових слів не працює
Найпростіша реалізація пошуку — це LIKE '%query%' у SQL. Це те, що ви отримуєте, коли розробник додає пошук як доповнення. Воно працює для точних збігів, але провалюється у всіх інших випадках:
- Пошук «install» не знаходить сторінки, що містять «installation» або «installing»
- Пошук «authn» не знаходить сторінки про «authentication»
- Помилка на кшталт «deploymnet» не повертає нічого
- Кожен результат має однакове ранжування — сторінка з назвою «Installation Guide» ранжується так само, як сторінка, що згадує «install» один раз у підвалі
Деякі платформи покращують це за допомогою розширення SQLite FTS5, що додає токенізацію та базове ранжування. Це крок вперед, але все ще бракує стемінгу, нечіткого зіставлення та можливості підсилювати певні поля (наприклад, заголовки) над іншими.
Що насправді робить повнотекстовий пошук
Повноцінний пошуковий рушій обробляє текст у двох фазах: індексація (коли контент записується) і запит (коли хтось шукає). Обидві фази роблять більше роботи, ніж ви очікуєте.
Індексація: що відбувається при збереженні сторінки
Коли ви створюєте або оновлюєте сторінку в DocPlatform, контент проходить через конвеєр аналізу перед індексацією:
1. Токенізація — Текст розбивається на окремі терміни. «Getting started with DocPlatform» стає ["getting", "started", "with", "docplatform"].
2. Приведення до нижнього регістру — Усі токени нормалізуються до нижнього регістру. «DocPlatform» і «docplatform» зіставляються.
3. Видалення стоп-слів — Поширені слова на кшталт «the», «is», «with», «a» видаляються. Вони з’являються майже в кожному документі і не допомагають розрізнити релевантні результати.
4. Стемінг — Слова зводяться до кореневої форми. «installing», «installation» та «installed» — усі стають «instal». Це означає, що пошук за будь-яким із цих слів знаходить усі інші.
5. Розділення полів — Різні частини документа індексуються окремо. Заголовок, тіло, теги та шлях отримують кожен своє поле в індексі. Це дозволяє підсилювати поля під час запиту.
Результуючий індекс — це структура даних, що називається інвертованим індексом — відображення від кожного терміна до списку документів, що його містять, разом із позиційною інформацією (де в документі з’являється термін і як часто).
"instal" → [doc_3 (title, pos:0), doc_7 (body, pos:45), doc_12 (body, pos:102)]
"deploy" → [doc_3 (body, pos:23), doc_5 (title, pos:0)]
"kubernetes" → [doc_5 (body, pos:15), doc_5 (body, pos:89)]
Запит: що відбувається при пошуку
Коли користувач вводить запит, пошуковий рушій запускає той самий конвеєр аналізу на тексті запиту (токенізація, приведення до нижнього регістру, стемінг), потім шукає кожен термін в інвертованому індексі.
Але справжня цінність — у ранжуванні. Не всі збіги рівні. Bleve використовує варіант TF-IDF (частота терміна, обернена частота документа) у поєднанні з підсиленням полів для отримання оцінки релевантності:
- Частота терміна: Сторінка, що згадує «deployment» 10 разів, ймовірно, більш релевантна, ніж та, що згадує його один раз.
- Обернена частота документа: Термін, що з’являється лише в 3 із 500 документів, більш характерний (і корисніший для ранжування), ніж термін, що з’являється в 400 документах.
- Підсилення полів: Збіг у заголовку вартує більше, ніж збіг у тілі. У DocPlatform збіги в заголовку отримують підсилення 3x, збіги в тегах — 2x, а збіги в тілі — 1x.
Формула створює числову оцінку для кожного документа зі збігами, і результати повертаються відсортованими за оцінкою.
Нечітке зіставлення: обробка помилок
Реальні користувачі роблять помилки. «Kuberntes» замість «Kubernetes». «Authentcation» замість «Authentication». Базовий пошук не повертає нічого для цих запитів.
Bleve підтримує нечітке зіставлення за допомогою відстані редагування (відстань Левенштейна). Термін запиту зіставляється з терміном документа, якщо вони відрізняються на N або менше символьних операцій (вставки, видалення, заміни). DocPlatform використовує відстань редагування 1 за замовчуванням — достатньо для виявлення односимвольних помилок без створення занадто великої кількості хибних збігів.
Запит: "authentcation"
Відстань редагування 1: зіставляється з "authentication" (одна відсутня 'i')
Результати: всі документи, що містять "authentication"
Це відбувається прозоро. Користувачам не потрібно знати про нечітке зіставлення чи щось налаштовувати. Вони просто шукають і отримують результати, навіть коли роблять помилки при введенні.
Як DocPlatform підтримує індекс синхронізованим
Складна частина вбудованого пошуку — не сам пошук, а підтримка узгодженості індексу з контентом. DocPlatform має два джерела контенту: веб-редактор і git. Обидва можуть створювати, оновлювати та видаляти сторінки.
Ось потік індексації:
Збереження у веб-редакторі: Користувач натискає «Зберегти» → контент записується в базу даних → пошуковий індексатор оновлює індекс Bleve → рушій git sync комітить зміну.
Отримання git push: Спрацьовує git webhook → рушій синхронізації витягує зміни → нові/змінені сторінки записуються в базу даних → пошуковий індексатор оновлює індекс Bleve.
Масові операції: Коли ви імпортуєте репозиторій із сотнями markdown-файлів, індексатор обробляє їх пакетами. Імпорт 500 сторінок займає приблизно 3 секунди для повної індексації на помірному обладнанні.
Видалення: Коли сторінку видалено (з веб-інтерфейсу або git), відповідний документ видаляється з індексу Bleve. Жодних осиротілих результатів пошуку.
Важлива деталь: індексація синхронна з операцією запису. Коли збереження/синхронізація завершується, пошуковий індекс вже оновлений. Немає затримки «очікуйте переіндексації». Це можливо, тому що Bleve працює в тому ж процесі — немає мережевого стрибка до окремого кластера Elasticsearch.
Більше про роботу рушія синхронізації читайте у нашому пості про чому git-синхронізація ламається та патерн Content Ledger, що вирішує цю проблему.
Порівняння: вбудований проти зовнішнього пошуку
| Можливість | SQL LIKE | SQLite FTS5 | Bleve (вбудований) | Elasticsearch |
|---|---|---|---|---|
| Токенізація | Ні | Так | Так | Так |
| Стемінг | Ні | Обмежений | Так | Так |
| Нечітке зіставлення | Ні | Ні | Так | Так |
| Підсилення полів | Ні | Ні | Так | Так |
| Ранжування за релевантністю | Ні | Базове | TF-IDF | BM25 |
| Додатковий сервіс | Ні | Ні | Ні | Так |
| Накладні витрати пам’яті | Немає | ~1 МБ | ~10 МБ | 1-4 ГБ (JVM) |
| Операційна складність | Немає | Немає | Немає | Висока |
Elasticsearch виграє за просунутими функціями: агрегації, запити вкладених документів, користувацькі аналізатори, розподілений пошук між кластерами. Якщо ви будуєте пошуковий продукт, він вам, ймовірно, потрібен.
Але для пошуку документації — де корпус складає тисячі сторінок, а не мільйони записів — вбудований Bleve покриває вимоги з нульовими операційними накладними витратами. Вам не потрібен окремий кластер для пошуку по документації.
Як ми розглянули в пості про архітектуру одного бінарного файлу, утримання всього в одному процесі усуває цілий клас операційних проблем.
Що насправді шукають користувачі
Ми побудували нашу конфігурацію пошуку на основі того, як люди реально шукають у документації:
Точні назви функцій: «RBAC», «WebAuthn», «git sync» — вони повинні точно зіставлятися в заголовках і тегах.
Концептуальні запити: «how to set up permissions» — вони покладаються на стемінг і зіставлення тексту тіла.
Часткове згадування: «that page about deploy…» — нечітке зіставлення та підсилення заголовків допомагають знайти правильний результат навіть із неповними запитами.
Повідомлення про помилки: Користувачі вставляють повідомлення про помилки в пошук. Вони виграють від точного зіставлення з довгими послідовностями токенів.
Конфігурація за замовчуванням обробляє все це добре. Налаштування не потрібне.
Спробуйте
Якщо хочете побачити це в дії, встановіть DocPlatform і створіть кілька сторінок. Рядок пошуку на опублікованому сайті документації використовує саме ту систему, що описана тут. Введіть запит, навмисно зробіть помилку і побачте, як він все одно знаходить потрібне.
Community Edition включає повні можливості пошуку — без функціональних обмежень, без «оновіться для кращого пошуку». Посібник з налаштування пошуку охоплює деталі кастомізації поведінки пошуку, якщо це потрібно.