Настройка полнотекстовых индексов MySQL для 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Настройка полнотекстовых индексов MySQL для 1С-Битрикс
Простая
~1 рабочий день
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    747
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Настройка полнотекстовых индексов MySQL для 1С-Битрикс

Стандартный поиск Битрикс работает через компонент bitrix:search.page и модуль search. Он строит собственный индекс в таблице b_search_content — туда попадают все элементы инфоблоков, страницы, форумы. Поиск идёт через LIKE '%запрос%', что при объёме свыше 100 тысяч элементов превращается в table scan с деградацией до 5–15 секунд. Решение — полнотекстовые индексы MySQL (FULLTEXT) напрямую на таблицах инфоблоков или на b_search_content.

Как работает FULLTEXT в MySQL

FULLTEXT-индекс строится поверх текстовых колонок (CHAR, VARCHAR, TEXT). Запросы — через MATCH() AGAINST(). Два режима: IN NATURAL LANGUAGE MODE (ранжирование по релевантности) и IN BOOLEAN MODE (поддержка операторов: +обязательно, -исключить, *префикс).

Ограничения MySQL FULLTEXT:

  • Минимальная длина слова по умолчанию: ft_min_word_len = 4 (для MyISAM), innodb_ft_min_token_size = 3 (для InnoDB). Слова короче — не индексируются.
  • Стоп-слова (innodb_ft_server_stopword_table) — их нужно отключить или перенастроить.
  • Для русского языка требуется правильная кодировка (utf8mb4) и, желательно, внешний парсер (ngram для InnoDB или Sphinx/Manticore как альтернатива).

Настройка my.cnf для русского FULLTEXT

[mysqld]
# Минимальная длина токена
innodb_ft_min_token_size = 2

# Отключаем стоп-слова по умолчанию (они для английского)
innodb_ft_enable_stopword = OFF

# Включаем ngram-парсер для поддержки CJK и коротких слов
# (альтернатива — использовать ngram в DDL)

После изменения innodb_ft_min_token_size нужно пересоздать все FULLTEXT-индексы — просто перезапуска MySQL недостаточно.

Создание FULLTEXT-индекса на b_search_content

Таблица b_search_content — центральная точка поиска Битрикс. Ключевые колонки: TITLE, BODY.

-- Проверяем текущие индексы
SHOW INDEX FROM b_search_content;

-- Создаём FULLTEXT-индекс
ALTER TABLE b_search_content
    ADD FULLTEXT INDEX ft_search_content (TITLE, BODY)
    WITH PARSER ngram;

WITH PARSER ngram — встроенный в MySQL 5.7+ парсер, разбивающий текст на биграммы/триграммы. Хорошо работает для кириллицы, не требует внешних инструментов.

Размер токена ngram настраивается:

[mysqld]
ngram_token_size = 2  # оптимально для русского

Переопределение поиска в Битрикс

Стандартный bitrix:search.page не использует FULLTEXT — он работает через ORM Битрикс с LIKE. Чтобы подключить FULLTEXT, переопределяем запрос в кастомном компоненте-обёртке или через событие OnBeforeIBlockElementGetList.

Минимальный кастомный поиск через FULLTEXT:

namespace Local\Search;

class FulltextSearcher
{
    private \Bitrix\Main\DB\Connection $db;

    public function __construct()
    {
        $this->db = \Bitrix\Main\Application::getConnection();
    }

    public function search(string $query, int $page = 1, int $limit = 20): array
    {
        $query   = $this->sanitizeQuery($query);
        $offset  = ($page - 1) * $limit;

        // BOOLEAN MODE с префиксным поиском
        $boolQuery = '+' . implode('* +', explode(' ', $query)) . '*';

        $sql = "
            SELECT
                sc.ID,
                sc.TITLE,
                sc.URL,
                sc.MODULE_ID,
                sc.ITEM_ID,
                MATCH(sc.TITLE, sc.BODY) AGAINST (? IN BOOLEAN MODE) AS relevance
            FROM b_search_content sc
            WHERE
                MATCH(sc.TITLE, sc.BODY) AGAINST (? IN BOOLEAN MODE)
                AND sc.SITE_ID = ?
                AND sc.PUBLIC = 'Y'
            ORDER BY relevance DESC
            LIMIT ? OFFSET ?
        ";

        $result = $this->db->query($sql, [$boolQuery, $boolQuery, SITE_ID, $limit, $offset]);

        $rows = [];
        while ($row = $result->fetch()) {
            $rows[] = $row;
        }

        return $rows;
    }

    public function count(string $query): int
    {
        $boolQuery = '+' . implode('* +', explode(' ', $query)) . '*';

        $result = $this->db->query(
            "SELECT COUNT(*) AS cnt FROM b_search_content
             WHERE MATCH(TITLE, BODY) AGAINST (? IN BOOLEAN MODE)
             AND SITE_ID = ? AND PUBLIC = 'Y'",
            [$boolQuery, SITE_ID]
        );

        return (int)$result->fetch()['cnt'];
    }

    private function sanitizeQuery(string $query): string
    {
        // Убираем операторы FULLTEXT, оставляем только слова
        $query = preg_replace('/[+\-><()\~*"@]+/', ' ', $query);
        $query = preg_replace('/\s+/', ' ', trim($query));

        return mb_substr($query, 0, 255);
    }
}

Кастомный компонент поиска

Шаблон компонента использует FulltextSearcher вместо стандартного модуля:

// /local/components/local/search.fulltext/component.php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();

$query = trim($_GET['q'] ?? '');

if (mb_strlen($query) < 2) {
    $this->arResult['ITEMS'] = [];
    $this->arResult['TOTAL'] = 0;
    $this->IncludeComponentTemplate();
    return;
}

$searcher = new \Local\Search\FulltextSearcher();
$page     = max(1, (int)($_GET['PAGEN_1'] ?? 1));

$this->arResult['ITEMS'] = $searcher->search($query, $page);
$this->arResult['TOTAL'] = $searcher->count($query);
$this->arResult['QUERY'] = htmlspecialchars($query);
$this->arResult['PAGE']  = $page;

$this->SetResultCacheKeys([]); // поиск не кешируем

$this->IncludeComponentTemplate();

FULLTEXT на таблицах инфоблоков

Для поиска только по каталогу эффективнее индексировать напрямую таблицы инфоблоков: b_iblock_element (NAME, DETAIL_TEXT) и b_iblock_section (NAME).

ALTER TABLE b_iblock_element
    ADD FULLTEXT INDEX ft_iblock_element_search (NAME, SEARCHABLE_CONTENT)
    WITH PARSER ngram;

Колонка SEARCHABLE_CONTENT — заполняется Битрикс при сохранении элемента, содержит объединённый текст для поиска.

Мониторинг индекса

-- Статистика FULLTEXT-индексов InnoDB
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;

-- Принудительная пересборка
SET GLOBAL innodb_optimize_fulltext_only = ON;
OPTIMIZE TABLE b_search_content;
SET GLOBAL innodb_optimize_fulltext_only = OFF;

Состав работ

  • Аудит текущего поиска, замер производительности
  • Настройка my.cnf: ngram_token_size, отключение стоп-слов
  • Создание FULLTEXT-индексов на b_search_content и/или таблицах инфоблоков
  • Разработка кастомного компонента поиска с FULLTEXT-запросами
  • Пересборка индекса Битрикс-поиска (BXSearch::reindex())
  • Нагрузочное тестирование до/после

Сроки: настройка индексов и кастомного компонента — 1–2 недели.