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

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Налаштування повнотекстових індексів MySQL для 1С-Бітрікс
Проста
~1 робочий день
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • 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
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Налаштування повнотекстових індексів 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 тижні.