# Поиск — Администрирование

Администрирование поиска в 1Форме охватывает настройку режимов поиска пользователей в контролах выбора, текстовых режимов поиска задач (FTS, триграммный, точный, префикс/суффикс), а также глобальные параметры через CustomSettings.

## Поиск пользователей

### Режимы поиска в контроле «Кому»

**Где настраивается:** Общие настройки приложения (`system-settings`) → параметр «Быстрый поиск и поиск в контроле Кому».

**Что контролируется:** какие поля пользователя участвуют в поиске при выборе получателя в контроле «Кому» (карточка задачи, назначение исполнителей, подписчиков, расширенный поиск пользователей и др.).

| Режим | Описание |
|-------|----------|
| По имени | Поиск по имени пользователя |
| По фамилии | Поиск по фамилии |
| По имени или фамилии | Совпадение по имени или фамилии |
| По имени и фамилии | Совпадение одновременно по имени и фамилии |
| По фамилии и имени | Совпадение одновременно по фамилии и имени |

**⚠️ Жёсткое ограничение:** независимо от настройки, поиск запускается при вводе не менее трёх символов. Поиск по одному или двум символам невозможен — это обеспечивает стабильность при больших объёмах данных.

**Поиск по основной должности** работает автоматически (дополнительная настройка не требуется).

**Умный поиск** (fuzzy): при донаборе символов опечатка не очищает выборку — удобно искать контакты даже с опечатками.

> **См. также:** спецправа на видимость пользователей в результатах поиска — [Пользователи и группы — администрирование](https://help.1forma.ru/domains/users-and-groups/admin.md).

### Минимальная длина строки для подсказок

**Где настраивается:** Общие настройки приложения → параметр «Количество обязательных символов для поиска» (`Settings.NumberCharsForSearchContacts`).

Задаёт минимальное число символов, начиная с которого система предлагает подсказки в выпадающем списке подходящих пользователей. **Жёсткий лимит:** не менее 3 символов.

### CustomSettings: ограничение полей поиска

Глобальные ключи CustomSettings, ограничивающие поля поиска пользователей:

| Ключ | Тип / По умолчанию | Назначение |
|------|---------------|------------|
| `OnlyNameUsersSearch` | bool / `false` | Если `true` — поиск сотрудников учитывает **только** `DisplayName` и `FullName`. Если `false` — также учитываются телефон, email и другие параметры профиля (медленнее, но шире). Используется для ускорения поиска на больших инсталляциях |

## Текстовый поиск задач, комментариев и ДП

### Тип поиска по тексту задачи (TaskTextSearchType)

**Где настраивается:**

- Глобально: Общие настройки приложения → блок «Настройки поиска»
- На уровне категории: настройки категории → «Прочие» → «Тип поиска»

**Порядок применения:** настройка категории переопределяет глобальную (приоритет возрастает: общие → категория).

| Режим | TaskTextSearchType | Описание | Пример |
|-------|-------------------|----------|--------|
| Поиск по вхождению подстроки | 16 (LIKE) | Находит задачи, где в тексте встречается указанная фраза, даже если вокруг неё есть другие слова | «договор» → «Подписать договор», «Договор №123» |
| Полнотекстовый | 2 (FTS) | Ищет с учётом различных форм слов (окончаний, склонений). Медленнее из-за лингвистического анализа | «оплатить счет» → «оплаченные счета» |
| Полное совпадение | 3 | Только полное совпадение текста задачи | «Акт» → только «Акт», не «Акт сверки» |
| Обрамлять справа | 4 | Поиск по концу текста | «2024» → «Договор №123/2024», не «2024 год» |
| Обрамлять слева | 5 | Поиск по началу текста | «Отчет» → «Отчет за май», не «Сдать отчет» |

Подписи двух последних режимов читаются наоборот: «Обрамлять справа» отбирает задачи, текст которых заканчивается введённой строкой, «Обрамлять слева» — те, что с неё начинаются. В коде режимы так и называются: `EndWith` = 4, `StartWith` = 5.

> **См. также:** ранжирование и сортировка результатов поиска — [Поиск — бизнес-логика](https://help.1forma.ru/domains/search/business.md).

### Минимальная длина строки текстового поиска

Пригодность поисковой строки проверяет функция `dbo.IsStringSearchable`. Её вызывают `ShowTasksFeed` (страница общего поиска), `SimpleSearchByTasks` (быстрый поиск и саджесты) и процедуры поиска по файлам (`SearchFileAbstract`, `FindFilesAbstracts`). Строка проходит проверку, если она непустая и выполнено хотя бы одно условие:

- тип поиска — «Полное совпадение» (`TaskTextSearchType` = 3): длина не проверяется вовсе;
- длина строки не меньше значения параметра «Количество обязательных символов для поиска» (`Settings.NumberCharsForSearchContacts`) из Общих настроек приложения;
- поиск идёт ровно по одной категории, и в её настройках выключено «Использовать триграмм» (`Subcategories.UseTrigramSearchF` = 0).

Настройка категории не переопределяет общий порог, а даёт из него исключение: в категории без триграмм короткая строка проходит в поиск, во всех остальных случаях порог из Общих настроек приложения действует как есть. Категория учитывается, только когда выводится ровно одна категория, но собирают набор категорий вызывающие по-разному. В MS SQL-версии `ShowTasksFeed` он складывается из переданных категорий, категорий переданных разделов вместе с вложенными и категорий, входящих в переданные сводные категории, — сводная категория, разворачивающаяся ровно в одну категорию, единственную категорию тоже даёт. В PostgreSQL-версии сборка набора целиком закрыта условием «переданы категории или разделы», сводные категории в это условие не входят: сам разворот сводных категорий внутри блока написан, но при передаче одних только сводных категорий блок не выполняется, набор остаётся пустым и единственной категории не даёт. Права пользователя набор не сужают — доступ проверяется отдельно и лишь взводит признак «среди категорий есть недоступные». В `SimpleSearchByTasks` берутся только переданные категории: разделы и сводные категории в категории там не разворачиваются. Кроме того, в MS SQL-версии `SimpleSearchByTasks` единственная категория может вывестись не из параметров поиска вообще: если категории не переданы, а поисковая строка после удаления `+`, `-`, скобок и пробелов состоит только из цифр и не длиннее 10 (поиск по телефону), набор заполняется из CustomSetting `SimpleSearchByTasks.PhonesSubcatIDs` и единственная категория пересчитывается уже по нему — исключение по `UseTrigramSearchF` = 0 срабатывает тогда без единой категории в параметрах. При поиске по нескольким категориям и при поиске по файлам категория не передаётся и работает общий порог.

Сама проверка `dbo.IsStringSearchable` одинаково реализована в MS SQL и PostgreSQL.

### Триграммный поиск

**Где настраивается:**

- Глобально: CustomSettings `UseTrigramInSimpleSearch`
- На уровне категории: настройки категории → «Прочие» → «Использовать триграмм» (`Subcategories.UseTrigramSearchF`, по умолчанию = 1)

**Что делает:** метод поиска на основе разбиения строк на последовательности из трёх символов (триграммы). Позволяет находить совпадения при опечатках, морфологических вариациях или частичном совпадении строк. Если настройка активна, система автоматически генерирует триграммы для текста задачи категории при её создании или изменении. Если отключена — триграммы не рассчитываются, и поиск по неточным совпадениям невозможен.

**⚠️ Ограничения:**

- Триграммный поиск осуществляется при вводе не менее трёх символов. Поиск по одному или двум символам невозможен.
- Триграммный поиск учитывает специальные символы.

**При включении/выключении** в категории вызывается хранимая процедура `OnChangeSubcatUseTrigramSearchF` (только MS SQL).

**Когда триграммы перестраиваются.** Триграммы строятся из текста задачи и служат только подстрочному поиску. Они перестраиваются при изменении текста задачи или её категории; отдельно их можно пересобрать целиком процедурой `dbo.TaskTrigramFullUpdate`. Планового полного пересчёта по расписанию нет. Если «Использовать триграмм» у категории выключено, процедура `OnChangeSubcatUseTrigramSearchF` перестраивает триграммы её задач при выключении — иначе таблица триграмм этой категории остаётся пустой, подстрочный поиск по ней не идёт, а полнотекстовый работает как раньше.

**Особенности перестроения на MS SQL.** Перестроение читает зафиксированный текст задачи и, если сохранённые триграммы ему уже соответствуют, ничего не пишет — это штатный режим, а не сбой. Расчёт рассчитан на площадки с включённым режимом RCSI (дефолт); на базе с выключенным RCSI поведение не гарантируется. Если на площадке отключена конвертация Unicode, перестроение остаётся на прежней версии процедуры — подробности в Поиск — база данных.

**Категории пространств.** Триграммный путь ускоряет поиск по названиям страниц пространств: заголовки ищутся триграммами, только если у всех выбранных категорий пространств включён «Использовать триграмм»; если хотя бы у одной он выключен, заголовки по-прежнему ищутся полнотекстом по всей таблице задач — медленным путём. Поэтому на крупных стендах стоит проверить, что у категорий пространств триграммный поиск включён.

### CustomSettings для триграммного поиска

Ключи CustomSettings, управляющие триграммным поиском:

| Ключ | Тип | Описание | Значение по умолчанию |
|------|-----|----------|----------------------|
| `UseTrigramInSimpleSearch` | int | Включение нечёткого поиска по тексту (триграммы, поиск по вхождению подстроки) **только в быстром поиске / саджестах** (`POST /api/search/simple` → `SimpleSearchByTasks`). Если 0 или не задан — в быстром поиске работает полнотекстовый поиск. На страницу общего поиска `/spa/search` **не влияет** (см. врезку ниже) | 0 (полнотекст) |
| `FilterChain.MaxTrigramCountForTrigramSearch` | int | Максимальное количество триграмм (для категорий, в которых поиск не использует индексированные тексты задач), при превышении которого поиск выполняется непосредственно по денормализованным данным, без применения триграмм | 100000 |
| `FilterChain.MinSubcatSizeForTrigramSearch` | int | Минимальный размер категории, при превышении которого поиск выполняется по денормализованным данным, без использования триграмм и индексированных задач, на которые ссылаются ДП Lookup и Multilookup | 100000 |

> **Важно — какая настройка на какую поверхность поиска влияет.** `UseTrigramInSimpleSearch` управляет **только быстрым поиском (саджестами в шапке/тулбаре)** — вызов `POST /api/search/simple`, SP `SimpleSearchByTasks`. Страница общего поиска `/spa/search` (вкладка «Задачи») ходит в другой контур — `POST /api/tasks/feeds/search`, SP `ShowTasksFeed` — и ищет полнотекстом по **целым словам** (`TaskTextSearchType`), на который `UseTrigramInSimpleSearch` не действует. Поэтому обрезанное слово («контрак») находит «контракт» в быстром поиске при `UseTrigramInSimpleSearch=1`, но не находит на `/spa/search`. Частичный (подстрочный) поиск на странице общего поиска даёт только «Тип поиска = по вхождению подстроки» (LIKE, 16) на уровне категории или глобально.

### Поиск по локализованным значениям

**Где настраивается:** CustomSettings `EnabledLocalizedSearch` = 1

**Что делает:** поиск в задачах, комментариях и ДП учитывает локализованные значения. Если у пользователя установлен английский интерфейс, система автоматически находит записи, у которых есть перевод на английский язык.

**⚠️ Ограничение:** при поиске по тексту задачи или ДП учитывается только тот язык, который выбран в интерфейсе пользователя. Значения в других локалях в поиске не участвуют. Исключение — ДП «Ссылка» из настройки `AllLocalesSearchEpIds` (см. [справочник настроек](https://help.1forma.ru/domains/system/settings-custom.md#alllocalessearchepids)): для них поиск в выпадающем списке ДП, текстовый фильтр и фильтр колонки в табличном представлении сверяют текст со всеми локализованными значениями задачи-источника, и достаточно совпадения хотя бы в одной локали.

> **См. также:** ранжирование и сортировка результатов поиска — [Поиск — бизнес-логика](https://help.1forma.ru/domains/search/business.md).

## Включение дополнительных режимов поиска (CustomSettings приложения)

Ряд функций поиска по умолчанию выключен и активируется администратором через пользовательскые настройки приложения.

| Ключ | Что включает |
|------|--------------|
| `showAI` | Вкладка AI beta в полной форме поиска — поисковая выдача Анфисы: задачи и документы со сниппетом и ссылкой. Руководство пользователя — [Умный AI-поиск](https://help.1forma.ru/domains/search/ai-search-user-guide.md) |
| `useNewExtendedSearch` | Расширенный поиск задач по параметрам — полная форма с табличным представлением, конструктором отбора, фильтрами и группировкой. Прямой адрес формы: `/spa/search?mode=advanced` |
| `SearchEncryptedTasks` | Поиск по тексту зашифрованных задач. По умолчанию недоступен; включается только при явной необходимости |

> Функциональное описание этих режимов с точки зрения пользователя — [Поиск — бизнес-логика](https://help.1forma.ru/domains/search/business.md).

## AI Search документации — исключение секций из PageRank

Хранимая процедура `dbo.sp_BuildPageRank` пересчитывает ранжирование документации на основе графа ссылок (`dbo.DocsLinks` → `dbo.DocsPageRank`). По умолчанию из расчёта исключаются служебные секции, страницы которых не должны влиять на ранжирование основной документации.

Список исключаемых секций задаётся в `dbo.SettingsCustom`:

| Ключ | Формат значения | Значение по умолчанию | Описание |
|------|------------------|-----------------------|----------|
| `anfisa_search_section_exclude` | JSON-массив имён секций (имя секции — первый сегмент пути после `docs/`) | `["scenarios","clients"]` | Страницы, путь которых начинается с `docs/<section>/`, исключаются из графа PageRank |

Пример значения:
```json
["scenarios","clients","experiments"]
```

При таком значении страницы, путь которых начинается с `docs/scenarios/`, `docs/clients/` или `docs/experiments/`, не попадают в граф PageRank: они отсутствуют в наборе вершин, не получают строки в `dbo.DocsPageRank` и не влияют на PageRank / HITS соседних документов.

Если ключ отсутствует, его значение пусто или равно `[]`, процедура автоматически подставляет `["scenarios","clients"]`. Чтобы отключить исключение полностью, задайте значение, не покрывающее ни одной реальной секции (например, `["__none__"]`).

Настройка применяется при следующем запуске `dbo.sp_BuildPageRank` — при очередном обновлении документации или плановом перестроении.

### Слои-хабы — исключение распространения PageRank от хабов

С версии **2.268** процедура `dbo.sp_BuildPageRank` дополнительно исключает исходящие рёбра от документов-хабов. Hub-документы определяются по полю `Layer` в `dbo.DocsChunks` (chunk 0): если слой документа входит в указанный список, его исходящие ссылки не участвуют в расчёте PageRank/HITS.

Список слоёв-хабов задаётся в `dbo.SettingsCustom`:

| Ключ | Формат значения | Значение по умолчанию | Описание |
|------|------------------|-----------------------|----------|
| `anfisa_pagerank_skip_layers` | JSON-массив имён слоёв | `["overview","navigator","changelog","digest"]` | Страницы с `Layer` из списка исключаются из распространения PageRank (исходящие рёбра не учитываются). Если ключ отсутствует или пуст — подставляется значение по умолчанию |

**Фильтр несуществующих путей.** Дополнительно процедура отфильтровывает ссылки на документы, отсутствующие в `dbo.DocsChunks` (возникают из битых относительных ссылок в markdown). В граф PageRank теперь попадают только документы, существующие в `DocsChunks` на момент запуска. Настройка не требуется — работает автоматически.

## Поиск по дополнительным параметрам

### Участие ДП в поиске

**Где настраивается:** настройки ДП в категории → параметр «Участвует в поиске».

**Особенность для ДП «Таблица»:** параметр «Участвует в поиске» влияет не только на поиск «в полях», но и на фильтр **«Содержит»** в табличном представлении категории. Если этот параметр отключён у всех столбцов таблицы, фильтр «Содержит» на колонке ДП Таблица в гриде не найдёт ни одной задачи. Фильтры «Нет значения» и «Есть значение» этого ограничения не имеют.

> **См. также:** настройка колонок ДП «Таблица» — [ДП «Таблица» — справочник настроек](https://help.1forma.ru/domains/ext-params/table/settings-reference.md).

### Поиск в Lookup-полях

Подсказки при выборе значения в самом контроле ДП «Lookup-поле» (`vh-control-lookup`) уходят на сервер только с трёх символов — порог зашит в контроле и настройками не управляется. Пока весь список значений уместился в первую страницу выдачи, тип поиска не полнотекстовый и ДП не перечислен в CustomSetting `AllLocalesSearchEpIds`, контрол фильтрует уже загруженные элементы локально — без обращения к серверу и без порога. Параметр «Количество обязательных символов для поиска» из Общих настроек приложения (`Settings.NumberCharsForSearchContacts`, в конфигурации клиента — `NumberCharactersForSearch`) на этот контрол не влияет: ДП «Lookup-поле» передаёт его только в диалог иерархического выбора значения.

Фильтрация задач по значению ДП «Lookup-поле» в `dbo.filters_chain_row_expr` идёт одним из двух путей. Подзапрос по категориям, на которые смотрит лукап, строится, только если длина значения не меньше 3 символов либо поиск ограничен ровно одной категорией с выключенной настройкой «Прочие» → «Использовать триграмм» (`Subcategories.UseTrigramSearchF`); это условие одинаково в MS SQL и PostgreSQL.

В MS SQL подзапрос дальше отбрасывается по двум причинам: если в условиях фильтра есть `OR` и если задач в единственной категории меньше, чем `FilterChain.MinSubcatSizeForTrigramSearch`. Обе проверки стоят до блока, который собирает подзапрос, и не дают ему выполниться. Количество триграмм в том же блоке тоже считается и сравнивается с `FilterChain.MaxTrigramCountForTrigramSearch`, но результат сравнения попадает в переменную, которая дальше нигде не читается (единственное чтение осталось в закомментированном блоке); подзапрос подставляется в итоговое выражение по факту своей непустоты, поэтому порог по триграммам на выбор пути не влияет. Внутри самого подзапроса по каждой категории лукапа выбор делает `dbo.CanSubcatBeFilteredByText`: триграммный поиск (`dbo.TaskTrigramSearch`) применяется только там, где нет подходящего индекса по тексту денормализации и триграммы в категории не выключены, иначе подставляется текстовый поиск по денормализации.

В PostgreSQL-версии функции подзапрос не отбрасывается ни по одной из этих причин: признак наличия `OR` объявлен параметром и в теле функции не используется, блок с `FilterChain.MinSubcatSizeForTrigramSearch` целиком закомментирован, а `FilterChain.MaxTrigramCountForTrigramSearch` в функции не упоминается вовсе — признак пригодности зашит константой. Ветки с `dbo.TaskTrigramSearch` внутри подзапроса там тоже нет: `dbo.CanSubcatBeFilteredByText` ни на что не переключает и по каждой категории лукапа безусловно подставляет текстовый поиск, но не по денормализации, как в MS SQL, а прямо по основной таблице задач — `dbo.Tasks` по колонке `Description` в нижнем регистре, с отбором по `SubcatID` категории лукапа.

Когда подзапрос не построен, фильтр не выключается: срабатывает обычный предикат по значению ДП (`like '%…%'` для «Содержит», сравнение для «=» и остальных операторов). Колонка зависит от того, сужен ли поиск до единственной категории: при единственной категории берётся денормализованная колонка (`ExtParam<ИД ДП>Value` или `ExtParam<ИД ДП>NativeValue`), без неё — колонка `dbo.ExtParamValues` под алиасом `epv<ИД ДП>` (`SelectedTaskID`, когда значение передано числом-номером задачи, иначе `ExtParamValue`). Без единственной категории подзапрос не строится на любом значении короче трёх символов, и фильтр в этой ветке работает предикатом по `dbo.ExtParamValues`, а не по денормализации. По одному-двум символам фильтр работает — просто без триграммного подзапроса.

## Диагностика типовых инцидентов

Частые обращения по поиску и их вероятные причины:

| Симптом | Возможная причина |
|---|---|
| Пустой результат при ожидаемых совпадениях | неподходящий режим поиска, фильтры или права доступа |
| Обрезанное (частичное) слово не находит задачу на `/spa/search`, хотя `UseTrigramInSimpleSearch=1` | страница общего поиска использует `ShowTasksFeed` (полнотекст по целым словам); `UseTrigramInSimpleSearch` влияет только на быстрый поиск/саджесты (`SimpleSearchByTasks`). Для подстрочного поиска на странице — «Тип поиска = по вхождению подстроки» на уровне категории/глобально |
| Медленный поиск | тяжёлый запрос в `ShowTasksFeed`, неподходящий путь поиска |
| Разные результаты на разных экранах | разные параметры серверных запросов |
| Файлы выводятся не по свежести | `SearchFileAbstract` сортирует только по FTS-рангу, без учёта даты |
| Старые задачи выше в саггестах | исправлено: `SimpleSearchByTasks` использует сортировку по дате изменения (новые выше) |
| Обновление путей индекса документации вернуло `0` сразу после старта ядра | ожидаемо в окне фонового прогрева: признак завершения ещё не выставлен — дождаться окончания прогрева |
