הגדרת אינדקסים מלאים של MySQL עבור 1C-Bitrix

כאשר קטלוג ב-1C-Bitrix גדל, החיפוש הסטנדרטי מתחיל להאט, ומאלץ לקוחות להמתין עשר שניות או יותר לתגובה. אנו מגדירים אינדקסים מלאים של MySQL כך שהחיפוש יעבוד באופן מיידי גם בנפחי נתונים גדולים. הצוות שלנו מספק את הפרויקט עד הסוף — מביקורת והגדרת שרת ועד פיתוח רכיב מותאם אישית, תוך הבטחת פעולה יציבה ותמיכה שוטפת.
השירותים שאנו מציעים
מציג 1 מתוך 1כל 1626 השירותים
הגדרת אינדקסים מלאים של MySQL עבור 1C-Bitrix
פשוט
~1 יום

הכישורים שלנו:

שאלות נפוצות

כאשר קטלוג מוצרים ב-1C-Bitrix גדל ל-200 אלף פריטים, החיפוש הסטנדרטי מפסיק להתמודד — זמן התגובה עובר את 10 השניות. בפרויקט אחד עם קטלוג של 500 אלף מוצרים, חיפוש דרך LIKE ארך עד 18 שניות.

לאחר הטמעת FULLTEXT עם מנתח ngram, הזמן ירד ל-0.2 שניות. ביצענו ביקורת, הגדרנו את my.cnf, יצרנו אינדקסים ופיתחנו רכיב מותאם אישית. צרו קשר כדי להעריך את הפרויקט שלכם.

החיפוש הסטנדרטי של Bitrix פועל דרך הרכיב bitrix:search.page ומודול החיפוש. הוא בונה אינדקס משלו בטבלת b_search_content — כל רכיבי האינפובלוקים, הדפים והפורומים נכנסים לשם.

החיפוש פועל דרך LIKE '%query%', אשר עם נפח של למעלה מ-100 אלף רכיבים הופך לסריקת טבלה עם הידרדרות ל-5–15 שניות. הפתרון הוא אינדקסים מלאים של MySQL (FULLTEXT) ישירות על טבלאות האינפובלוקים או על b_search_content.

כיצד FULLTEXT עובד ב-MySQL

אינדקס FULLTEXT נבנה על גבי עמודות טקסט (CHAR, VARCHAR, TEXT). שאילתות מבוצעות באמצעות MATCH() AGAINST(). שני מצבים: IN NATURAL LANGUAGE MODE (דירוג לפי רלוונטיות) ו-IN BOOLEAN MODE (תמיכה באופרטורים: +required, -exclude, *prefix).

מגבלות FULLTEXT ב-MySQL:

  • אורך מילה מינימלי כברירת מחדל: innodb_ft_min_token_size = 3. מילים קצרות מכך אינן מאונדקסות.
  • מילות עצירה (innodb_ft_server_stopword_table) — יש להשבית אותן או להגדיר אותן מחדש.
  • עבור השפה הרוסית נדרש קידוד תקין (utf8mb4) ועדיף מנתח חיצוני (ngram עבור InnoDB או Sphinx/Manticore כחלופה).

בחירת מנוע חיפוש וארכיטקטורת חיפוש

מנתח Ngram עבור קירילית

מנתח ה-FULLTEXT הסטנדרטי של MySQL מכוון לאנגלית: אורך מילה מינימלי של 3 תווים, מילות עצירה. מילים בקירילית הן לעתים קרובות קצרות יותר (מילות יחס, מילות חיבור), ולכן הן אינן מאונדקסות.

מנתח ה-ngram מפצל טקסט לביגרמות (2 תווים כל אחת) ואינו תלוי בשפה. זה מבטיח שכל שאילתה של שני תווים או יותר תמצא התאמות. הגדרת ngram_token_size=2 ב-my.cnf מפעילה מצב ביגרמות.

שימוש באינדקסי FULLTEXT

אם החיפוש נדרש רק עבור הקטלוג, יעיל יותר לאנדקס ישירות את הטבלאות b_iblock_element (NAME, DETAIL_TEXT) ו-b_iblock_section (NAME). זה מפחית את העומס על b_search_content ומפשט את הארכיטקטורה.

עם זאת, עבור חיפוש כלל-אתרי נוח יותר להשתמש ב-b_search_content — הוא כולל את כל סוגי התוכן.

הגדרה ויצירת אינדקסים

הגדרת my.cnf עבור FULLTEXT ברוסית

[mysqld] innodb_ft_min_token_size = 2 innodb_ft_enable_stopword = OFF ngram_token_size = 2

לאחר השינוי, יש ליצור מחדש את כל אינדקסי ה-FULLTEXT — הפעלה מחדש של MySQL בלבד אינה מספיקה.

יצירת אינדקס FULLTEXT על טבלאות b_search_content ואינפובלוקים

טבלת b_search_content היא הנקודה המרכזית של החיפוש ב-Bitrix. עמודות מפתח: TITLE, BODY. עבור הקטלוג אנו indexing את b_iblock_element עם העמודה SEARCHABLE_CONTENT, שאותה Bitrix ממלאת אוטומטית.

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

WITH PARSER ngram הוא מנתח המובנה ב-MySQL 5.7+ המפצל טקסט לביגרמות/טריגרמות. הוא עובד היטב עבור קירילית ואינו דורש כלים חיצוניים.

ניטור ותחזוקה של אינדקסים

בדיקת מצב האינדקס
-- Statistics of InnoDB FULLTEXT indexes
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
-- Forced rebuild
SET GLOBAL innodb_optimize_fulltext_only = ON;
OPTIMIZE TABLE b_search_content;
SET GLOBAL innodb_optimize_fulltext_only = OFF;

שאילתות אלה עוזרות לעקוב אחר אכלוס האינדקס ולבנות אותו מחדש בעת הצורך.

פיתוח קומפוננטה מותאמת אישית עבור FULLTEXT

עקיפת החיפוש ב-Bitrix

bitrix:search.page הסטנדרטי אינו משתמש ב-FULLTEXT — הוא עובד דרך Bitrix 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 with prefix search
        $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
    {
        $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([]); // we do not cache search
$this->IncludeComponentTemplate();

ביצועים והשוואת מנתחים

מדדים השוואתיים

שיטה זמן עבור 100 אלף רשומות שימוש ב-CPU אינדוקס
LIKE %query% 5–15 שניות 100% מליבה אחת לא נדרש
FULLTEXT (BOOLEAN) 0.1–0.5 שניות 10–20% נדרש ראשוני
מנתח אורך מילה מינימלי תמיכה בקירילית דורש הגדרה
Standard 3 תווים חלקית לא
ngram (ביגרמות) 2 תווים מלאה ngram_token_size

כיצד ליישם FULLTEXT ב-5 שלבים

  1. ביקורת: מדידת זמן החיפוש הנוכחי, ניתוח נפח הנתונים.
  2. הגדרת MySQL: קביעת ngram_token_size=2, השבתת מילות עצירה.
  3. יצירת אינדקסים: הרצת ALTER TABLE עם FULLTEXT ומנתח ngram.
  4. פיתוח קומפוננטה: יצירת FulltextSearcher מותאם אישית ותבנית.
  5. בדיקות: בדיקות עומס, השוואת "לפני/אחרי".

מה כלול בעבודה

  • ביקורת של אינדקס החיפוש הנוכחי, מדידת זמן השאילתה.
  • הגדרת MySQL: ngram_token_size, השבתת מילות עצירה.
  • יצירת אינדקסי FULLTEXT על b_search_content ו/או טבלאות אינפובלוקים.
  • פיתוח קומפוננטת חיפוש מותאמת אישית עם שאילתות FULLTEXT.
  • בנייה מחדש של אינדקס החיפוש של Bitrix (BXSearch::reindex()).
  • בדיקות עומס עם דוח "לפני/אחרי".
  • אספקת תיעוד וסקריפטים למיגרציה.
  • תמיכה חינם למשך חודש אחד.

הניסיון שלנו בפיתוח Bitrix הוא למעלה מ-10 שנים, הצלחנו להאיץ חיפוש ביותר מ-50 פרויקטים. קבלו ייעוץ — כתבו לנו, נעריך את הפרויקט שלכם בתוך יום אחד.

על פי התיעוד של MySQL 8.0, מנתח ה-ngram מבטיח אינדוקס נכון של קירילית ללא תלויות חיצוניות (MySQL Ngram Full-Text Parser).