#Что происходит и когда возникает
FTS5 сравнивает не исходную строку посимвольно, а последовательность токенов, которую определяет параметр tokenize при создании виртуальной таблицы. Например, если дефис включён в tokenchars, «usb-c» будет одним токеном, и поиск слова «usb» его не найдёт. Без такого параметра unicode61 обычно делит строку на «usb» и «c». Изменение токенизатора требует согласованного нового индекса; обычный REBUILD не меняет определение tokenize.
#Возможные причины: как различить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Дефис/подчёркивание стали частью токенаОпция tokenchars включает разделитель внутрь слова. | MATCH usb не находит запись usb-c; точная фраза с дефисом может находиться. | Согласовать tokenchars и построить новый индекс. |
| Поиск части слова вместо токенаunicode61 не делает автоматического поиска произвольных подстрок и не выполняет русское склонение. | «ошиб» не находит «ошибка», а «ошиб*» может найти. | Использовать поддерживаемый префиксный запрос либо другую модель поиска. |
| Индекс отстаёт от исходной таблицыДля external-content индекса триггеры могли не перенести изменения. | Прямой SELECT видит строку, а MATCH — нет после INSERT/UPDATE. | Проверить триггеры синхронизации и отдельно выполнить rebuild индекса. |
#Пошаговая диагностика и исправление
- Уточните точное поисковое слово и записьНайдите в исходной таблице проблемную строку, её идентификатор и текст. Сохраните исходный запрос MATCH без пользовательских секретов. Разделите случаи «слово не разбивается» и «запись вообще не попала в индекс»: это две разные ошибки.
- Посмотрите определение таблицы FTS5Откройте SQL-консоль на копии базы и выполните SELECT sql FROM sqlite_schema WHERE name='search_fts';, подставив имя вашей виртуальной таблицы. Найдите tokenize, tokenchars, separators, prefix, content. Если tokenize не указан, обычно используется unicode61. Не изменяйте схему, пока не проверили конкретные правила.
- Проверьте доступность расширения FTS5В консоли для своей базы выполните SELECT sqlite_version(); и PRAGMA compile_options;. При попытке CREATE VIRTUAL TABLE может быть ошибка «no such module: fts5»; в таком случае проверьте используемую сборку и не пытайтесь исправлять отсутствующий модуль настройками MATCH.
- Воспроизведите влияние дефиса в отдельной базеВ новой тестовой SQLite-базе создайте FTS5 с параметром tokenchars для дефиса, вставьте «usb-c» и выполните запросы из учебного примера. Если MATCH 'usb' ничего не возвращает, а точная фраза возвращает строку, причина — токенизация, а не отсутствие записи.
- Проверьте различие между словом, префиксом и подстрокойЕсли пользователь вводит «ошиб», испытайте MATCH 'ошиб*' на тестовой таблице: звёздочка означает поиск по началу токена. Для символов дефиса и операторов FTS5 используйте корректно экранированные фразы, иначе парсер MATCH может воспринимать ввод как синтаксис запроса.
- Проверьте обновление индекса при отдельной исходной таблицеЕсли используется content='имя_таблицы', изучите триггеры INSERT/UPDATE/DELETE, которые поддерживают внешний индекс. Без них данные могли появиться в исходной таблице, но не в FTS5. На копии после исправления синхронизации применяйте рекомендованный для FTS5 rebuild и проверяйте соответствие, не запускайте rebuild на занятой базе без окна и резервной копии.
- Пересоздайте индекс с нужными правилами только после тестовЕсли политика поиска требует другой токенизатор, создайте новую FTS5-таблицу с другим именем в копии, заполните из исходных записей, проверьте контрольные запросы и только затем согласуйте переключение приложения. Существующий индекс и старые записи не удаляйте до подтверждения результата и возможности отката.
#Команды и проверочные примеры
SELECT sql FROM sqlite_schema WHERE name='search_fts';SELECT sqlite_version();CREATE VIRTUAL TABLE demo_fts USING fts5(text, tokenize="unicode61 tokenchars '-_'");
INSERT INTO demo_fts VALUES ('usb-c');
SELECT count(*) FROM demo_fts WHERE demo_fts MATCH 'usb';
SELECT count(*) FROM demo_fts WHERE demo_fts MATCH '"usb-c"';#Как проверить результат
Тестовый поиск находит специально выбранные контрольные слова, знаки и префиксы; пересозданный индекс содержит ожидаемое число записей. Убедитесь, что изменения в исходных строках отображаются в поиске после INSERT/UPDATE/DELETE.
#Если не помогло
Если выдача пустая только для новых строк, изучите модель external-content и триггеры. Если не находится отдельное слово внутри «usb-c», повторно проверьте tokenchars и экранирование MATCH. Для сложных языковых форм понадобится отдельная нормализация или поисковый механизм.