Поиск¶
Один поисковый индекс хранит заявки и статьи базы знаний. Справочный центр, форма запроса, рабочая область и API обращаются к нему, и каждый показывает спрашивающему только то, что он может читать. Он работает на библиотеке YetiSearch (SQLite FTS5 с ранжированием BM25), встроенной в Helpdesk Pro, поэтому устанавливать нечего и не нужно запускать сервис.
Где находится индекс¶
Индекс — один файл SQLite, user/data/helpdesk-pro/search/helpdesk.db, с маркером helpdesk.meta.json рядом. Он следует за database.sqlite.path: это папка search/ рядом с папкой базы данных, и она получает запрещающий всё .htaccess. Это производные данные: удалите их в любое время, и следующий поиск построит их снова.
Файл содержит два индекса:
| Индекс | Что в нём | Кто ищет |
|---|---|---|
hd_public |
Один документ на заявку (тема, первое сообщение, публичные ответы, названия меток) и один на статью базы знаний (заголовок, текст, категории и теги) | Клиенты, гости (только статьи) и сотрудники |
hd_internal |
Один документ на заявку с внутренними заметками: текст заметки и ничего больше | Только сотрудники |
Текст заметок записывается только в hd_internal, и клиентский код поиска не может назвать этот индекс, поэтому никакой клиентский поиск не доходит до заметки.
Кто что находит¶
Каждый поиск сначала сужается по правам, затем каждая находка снова проверяется по базе данных.
- Гости находят публичные статьи.
- Вошедшие клиенты находят статьи, которые могут читать, заявки, которые они отправили или в копии которых были, и общие заявки проектов, в которых состоят. Они видят сводку и статус заявки словами клиента, но никогда её заметки, внутреннюю активность или людей.
- Сотрудники находят заявки в проектах, где работают (администраторы — все), включая внутренние заметки, и каждую статью. Заявка, найденная по заметке, помечается в списке рабочей области Matched in an internal note.
Как индекс остаётся актуальным¶
- Заявки переиндексируются после каждого изменения: новая заявка, ответ или заметка, правка, метка, статус, участник, объединение или удаление. Записи делаются один раз в конце запроса, после отправки ответа. Запрос, изменивший больше 100 заявок (массовое редактирование), передаёт их заданиям
search.index. - Статьи переиндексируются при сохранении, переводе или перемещении страницы в админке и удаляются при удалении, снятии с публикации или смене типа страницы. Правки вне Grav (git sync, FTP, развёртывание) подхватывает ежечасное задание
kb.syncи первый поиск в справочном центре после очистки кэша. - Самовосстановление. Первый поиск в запросе проверяет, что файл и маркер существуют и что ни одна заявка не была записана в обход индекса (импорт или восстановленная база). Если что-то не так, он перестраивает индекс на месте до двух секунд. Больший индекс завершает задание
search.rebuild, а пока поиск переходит на обычное совпадение по сводкам заявок и заголовкам статей. Нечитаемый файл удаляется и перестраивается так же.
Перестройка индекса¶
Используйте любой способ:
- Operations → Search → Rebuild index в рабочей области (Rebuild articles only перестраивает только часть базы знаний).
bin/plugin helpdesk-pro reindexна сервере.--scope=ticketsили--scope=kbперестраивает одну часть;--statusпечатает состояние индекса, не перестраивая его.POST /helpdesk-pro/search/rebuildчерез API.
Operations → Search также показывает, построен ли индекс, сколько документов он хранит, когда его последний раз перестраивали, его размер и путь, сколько синонимов загружено и состояние семантического поиска. Для экрана нужно helpdesk-pro.settings.
Синонимы¶
Люди и статьи не всегда используют одни и те же слова. Поиск любого слова или фразы из группы также находит остальные:
log in, login, sign in, signin, log on
log out, logout, sign out
password, passcode, pass word, pwd
reset, forgot, recover, change password
account, profile, user
email, e-mail, mail, inbox
invoice, bill, receipt
refund, money back, chargeback
cancel, unsubscribe, stop, close account
subscription, plan, membership, renewal
error, bug, broken, not working, doesn't work, crash, issue
slow, lag, loading, performance
upload, attach, attachment, file
download, install, setup, set up
delete, remove, erase
two-factor, 2fa, mfa, authenticator, verification code
payment, card, charge, billing
shipping, delivery, tracking
license, licence, key, activation
Чтобы изменить список:
- Скопируйте
user/plugins/helpdesk-pro/data/synonyms.jsonвuser/data/helpdesk-pro/search/synonyms.json. - Отредактируйте его
groups. Каждая группа — список слов и фраз (["log in", "login", "sign in"]), и фраза совпадает как фраза.
Helpdesk Pro читает вашу копию вместо копии плагина. Установите search.synonyms в false, чтобы отключить синонимы.
Когда поиск не находит ничего, он пробует ещё раз с исправлением опечаток, если search.fuzzy не равен false.
Похожие заявки¶
Панель Similar tickets на экране заявки перечисляет заявки в проектах, где вы работаете, тема и текст которых похожи на эту. Сама заявка и заявки, объединённые с ней, исключаются, а слабые совпадения (меньше 35% от оценки лучшего) отбрасываются, поэтому панель появляется, только когда что-то действительно близко. Клиенты никогда не видят похожие заявки; форма запроса вместо этого предлагает статьи и их собственные обращения.
Семантический поиск¶
Поиск по ключевым словам находит слова. Семантический поиск находит ещё и смысл: «my card was charged twice» может найти статью «Duplicate payments». Ему нужен API встраивания, говорящий на формате OpenAI (OpenAI, OpenRouter, Ollama, Voyage, Mistral и другие), и по умолчанию он выключен.
Включите его в настройках плагина (вкладка Search) или в user/config/plugins/helpdesk-pro.yaml:
Пишите ключ как env:NAME, чтобы прочитать его из переменной окружения NAME. Ключ, введённый в настройках, хранится как есть в user/config. Ключ никогда не возвращается API и не показывается в рабочей области.
Как это работает:
- Документы встраиваются заданием
search.embedпакетами поsearch.semantic.batch_limitпосле индексации. Это задание выполняется только в фоновом процессе, никогда в конце запроса посетителя, поэтому семантическому поиску нужен планировщик в cron (Задания и cron). - Поиск встраивает запрос и ранжирует по словам и смыслу вместе, а
search.semantic.weightрешает долю. Запросы корочеsearch.semantic.min_query_charsостаются только по ключевым словам. - Встраивается только
hd_public. Внутренние заметки отправляются в API, только когда включёнsearch.semantic.notes; иначе текст заметок никогда не покидает ваш сервер. - Когда API недоступен, поиск продолжает по ключевым словам. Operations → Search показывает, сколько документов встроено и сколько ждёт.
Заявки по умолчанию имеют 256 измерений. При 512 измерениях поиск стоит около 110 мс на 10 000 фрагментов; 256 уменьшает это вдвое. Каждая заявка считается в результатах один раз, на сколько бы фрагментов ни делился её текст.
Общие настройки с YetiSearch Pro¶
Семантические ключи повторяют настройки semantic: YetiSearch Pro имя в имя. Любой пустой ключ берёт значение YetiSearch Pro, когда этот плагин включён со своим семантическим поиском, и встроенное значение по умолчанию в остальных случаях, поэтому сайт, где работают оба, настраивает одну модель в одном месте.
Ключи соединения (base_url, api_key, model, dimensions и два префикса) идут вместе: если задать любой из них здесь, ни один не берётся из YetiSearch Pro. enabled, notes, embed_after_indexing и batch_limit никогда не берутся из YetiSearch Pro.
Настройки¶
| Ключ | По умолчанию | Что делает |
|---|---|---|
search.fuzzy |
true |
Повторять поиск, не нашедший ничего, с исправлением опечаток. |
search.synonyms |
true |
Расширять поиск списком синонимов. |
search.semantic.enabled |
false |
Ранжировать по смыслу, а также по словам. |
search.semantic.provider |
openai_compatible |
Единственный провайдер: любой OpenAI-совместимый API встраивания. |
search.semantic.base_url |
пусто (https://api.openai.com/v1) |
Базовый URL API, например http://localhost:11434/v1 для Ollama. |
search.semantic.api_key |
пусто | Ключ или env:NAME. Не нужен для локального сервера. |
search.semantic.model |
пусто (text-embedding-3-small) |
Модель встраивания. |
search.semantic.dimensions |
пусто (256) |
Длина вектора для моделей, которые её принимают; 0 — собственная длина модели. |
search.semantic.query_prefix |
пусто | Текст перед запросами (search_query: для nomic-embed-text). |
search.semantic.document_prefix |
пусто | Текст перед документами (search_document:). |
search.semantic.weight |
пусто (0.5) |
Доля ранжирования из смысла: 0 — только слова, 1 — только смысл. |
search.semantic.min_similarity |
пусто (0.25) |
Документы менее похожие на это никогда не появляются только по смыслу. |
search.semantic.min_query_chars |
пусто (3) |
Более короткие запросы только по ключевым словам. |
search.semantic.query_timeout |
пусто (5) |
Секунды ожидания встраивания запроса перед переходом на ключевые слова. |
search.semantic.timeout |
пусто (20) |
Секунды ожидания фонового процесса для пакета встраиваний документов. |
search.semantic.embed_after_indexing |
true |
Ставить search.embed в очередь при каждом изменении документов. |
search.semantic.batch_limit |
200 |
Документов на задание search.embed. |
search.semantic.notes |
false |
Также встраивать внутренние заметки (отправляет текст заметок в API). |
portal.suggestions |
true |
Предлагать статьи, пока люди печатают в поиске и форме запроса. |
portal.kb_session_days |
30 |
Сколько cookie hd_kb объединяет поиски посетителя. |
privacy.kb_events_days |
90 |
Поиски, просмотры и ответы справочного центра удаляются через столько дней. |
Пустой семантический ключ разрешается, как описано в разделе Общие настройки с YetiSearch Pro; значение в скобках — встроенное значение по умолчанию.
API и MCP¶
| Маршрут | Право | Что делает |
|---|---|---|
GET /helpdesk-pro/search |
desk | q, scope (all, tickets или kb), include_notes (по умолчанию включено), project, limit (до 100). Отвечает {tickets, articles, semantic, fallback}; строки заявок несут score и matched_in_note. fallback: true означает, что ответило обычное совпадение, пока индекс перестраивался. |
GET /helpdesk-pro/tickets/{id}/similar |
desk | Похожие заявки (limit до 20) с относительным score. |
POST /helpdesk-pro/search/rebuild |
settings | scope: all, tickets или kb. Ставит search.rebuild в очередь и отвечает 202 с {job_id, scope, queued}; queued: false, когда перестройка уже ждёт. |
Инструменты MCP: search, find_similar_tickets и rebuild_search.
Задания¶
| Задание | Что делает |
|---|---|
search.index |
Перезаписывает документы некоторых заявок: путь переполнения для массовых изменений. |
search.rebuild |
Перестраивает индекс. По одному за раз. |
search.embed |
Один проход встраивания по индексу, назначается снова, пока документы ждут. Только фоновый процесс. |
kb.sync |
Ежечасно: переиндексирует базу знаний, когда статья изменилась вне Grav. |