כאשר החיפוש המובנה של Bitrix מפסיק לעבוד
עם 100 אלף מוצרים, החיפוש המובנה המבוסס על MySQL מאט: שאילתות ל-b_search_content לוקחות 300–500 אלפיות השנייה, ובמסד נתונים עם מיליון רשומות — מתרחש timeout. לקוחות מתלוננים על זמני חיפוש ארוכים, מיון לפי מחיר לא עובד, ופילטרים (facets) מעמיסים על מסד הנתונים. לדוגמה, פרויקט אחרון עם קטלוג של 250,000 מוצרים: החיפוש הסטנדרטי החזיר תוצאות תוך 2–3 שניות, ופילטרים מורכבים לפי מאפיינים (מחיר, מותג, מידה) גרמו להשהיות של 30 שניות. Elasticsearch פותר זאת באופן קיצוני: זמן תגובה של 5–30 אלפיות השנייה, אגרגציות בזמן אמת, טעויות הקלדה ומורפולוגיה מובנים כברירת מחדל. הניסיון שלנו — 30+ אינטגרציות ES עם Bitrix, ואנחנו מבטיחים תוצאה סופית. אנו משתמשים ברכיבים מורשים ומוסמכים על ידי 1C-Bitrix. כדי להבין אם Elasticsearch מתאים לפרויקט שלך, הזמינו אודיט — ננתח את העומס ומבנה הנתונים.
בעיות ש-Elasticsearch פותר
Elasticsearch מחליף את מנוע החיפוש הסטנדרטי של Bitrix ופותר שלוש בעיות מרכזיות:
- מהירות חיפוש טקסט מלא. MySQL FULLTEXT מתחיל להאט ב-50–100 אלף מסמכים. ES מתמודד עם מיליונים.
- חיפוש פאקטלי (אגרגציות). הפילטרים המובנים של Bitrix הם שאילתות נפרדות לכל מאפיין. ES מחזיר אגרגציות בבקשה אחת, ומעניק רווח של פי 10–20 בפילטרים מורכבים.
- חיפוש עם טעויות הקלדה ומילים נרדפות. ללא מודולים חיצוניים, MySQL לא תומך בחיפוש משוער (fuzzy). ל-ES יש fuzziness ומילים נרדפות מובנים.
אם אתם נתקלים בבעיות דומות, צרו קשר לאודיט — זה יעזור לזהות צווארי בקבוק.
למה Elasticsearch מהיר יותר מ-MySQL FULLTEXT?
| מאפיין | MySQL FULLTEXT | Elasticsearch |
|---|---|---|
| סוג אינדקס | B-tree + קובץ הפוך | אינדקס הפוך + FST |
| מורפולוגיה | נדרשים מילונים חיצוניים (morphy) | Stemmer ומנתחים (רוסית) |
| חיפוש טעויות הקלדה | לא נתמך | Fuzziness (AUTO) |
| אגרגציות (פאקטים) | לא נתמך | נתמך, בשאילתה אחת |
| מהירות על מיליון מסמכים (שאילתה בודדת) | 200–500 אלפיות השנייה | 5–30 אלפיות השנייה |
Elasticsearch מהיר פי 10–50 מ-MySQL FULLTEXT על נתונים גדולים.
ארכיטקטורת אינטגרציה
האינטגרציה מורכבת משלושה חלקים:
- אינדקסר (Indexer) — רכיב שקורא נתונים מ-Bitrix (בלוקי מידע, משתמשים, עמודים) וכותב מסמכים לאינדקס Elasticsearch.
- שער חיפוש (Search gateway) — מחליף בקשות סטנדרטיות ל-
b_search_contentבבקשות ל-Elasticsearch API. השער מיושם כ-proxy ב-PHP: הוא מקבל בקשה מהרכיב הסטנדרטיbitrix:search.page, הופך אותה ל-Elasticsearch query DSL, ומחזיר תוצאות בפורמט ש-Bitrix מצפה לו. - מטפלי אירועים (Event handlers) — מעדכנים את האינדקס כאשר ישויות משתנות או נמחקות.
מבנה אינדקס לקטלוג מוצרים
האינדקס נוצר באמצעות Elasticsearch Mapping API. דוגמה ל-mapping למוצרים:
PUT /bitrix_catalog
{
"mappings": {
"properties": {
"id": {
"type": "integer"
},
"iblock_id": {
"type": "integer"
},
"name": {
"type": "text",
"analyzer": "russian"
},
"description": {
"type": "text",
"analyzer": "russian"
},
"sku": {
"type": "keyword"
},
"price": {
"type": "float"
},
"active": {
"type": "boolean"
},
"section_id": {
"type": "integer"
},
"properties": {
"type": "object"
},
"updated_at": {
"type": "date"
}
}
},
"settings": {
"analysis": {
"analyzer": {
"russian": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"russian_stop",
"russian_stemmer"
]
}
},
"filter": {
"russian_stemmer": {
"type": "stemmer",
"language": "russian"
},
"russian_stop": {
"type": "stop",
"stopwords": "_russian_"
}
}
}
}
}המנתח PUT /bitrix_catalog { "mappings": { "properties": { "id": { "type": "integer" }, "iblock_id": { "type": "integer" }, "name": { "type": "text", "analyzer": "russian" }, "description": { "type": "text", "analyzer": "russian" }, "sku": { "type": "keyword" }, "price": { "type": "float" }, "active": { "type": "boolean" }, "section_id": { "type": "integer" }, "properties": { "type": "object" }, "updated_at": { "type": "date" } } }, "settings": { "analysis": { "analyzer": { "russian": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "russian_stop", "russian_stemmer"] } }, "filter": { "russian_stemmer": { "type": "stemmer", "language": "russian" }, "russian_stop": { "type": "stop", "stopwords": "_russian_" } } } } } עם stemmer הוא ההבדל המרכזי מ-MySQL FULLTEXT, שבלי מילונים נוספים לא מבין מורפולוגיה.
דוגמה לתצורת מנתח עם מילים נרדפות
PUT /bitrix_catalog/_settings
{
"analysis": {
"filter": {
"russian_synonyms": {
"type": "synonym",
"synonyms": [
"брюки, штаны, джинсы => trousers",
"смартфон, телефон, мобила => mobile"
]
}
},
"analyzer": {
"russian_with_synonyms": {
"tokenizer": "standard",
"filter": ["lowercase", "russian_stop", "russian_stemmer", "russian_synonyms"]
}
}
}
} איך להגדיר עדכון אינדקס אוטומטי?
הירשמו לאירועי בלוקי מידע:
// local/php_interface/init.php
AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'esUpdateProduct');
AddEventHandler('iblock', 'OnAfterIBlockElementDelete', 'esDeleteProduct');
function esUpdateProduct(array &$arFields): void
{
$client = getEsClient();
$productId = (int)$arFields['ID'];
// Переиндексировать один документ
$client->index([
'index' => 'bitrix_catalog',
'id' => $productId,
'body' => buildProductDocument($productId),
]);
}
function esDeleteProduct(int $productId): void
{
getEsClient()->delete(['index' => 'bitrix_catalog', 'id' => $productId]);
}האירוע russian מופעל גם על שינויים דרך API (ייבוא 1C), שחשוב לרעננות האינדקס.
אינדוקס נתונים
אינדוקס ראשוני רץ דרך סקריפט cron. הנתונים נקראים בקבוצות באמצעות PUT /bitrix_catalog/_settings { "analysis": { "filter": { "russian_synonyms": { "type": "synonym", "synonyms": [ "брюки, штаны, джинсы => trousers", "смартфон, телефон, мобила => mobile" ] } }, "analyzer": { "russian_with_synonyms": { "tokenizer": "standard", "filter": ["lowercase", "russian_stop", "russian_stemmer", "russian_synonyms"] } } } } עם // local/php_interface/init.php AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'esUpdateProduct'); AddEventHandler('iblock', 'OnAfterIBlockElementDelete', 'esDeleteProduct'); function esUpdateProduct(array &$arFields): void { $client = getEsClient(); $productId = (int)$arFields['ID']; // Переиндексировать один документ $client->index([ 'index' => 'bitrix_catalog', 'id' => $productId, 'body' => buildProductDocument($productId), ]); } function esDeleteProduct(int $productId): void { getEsClient()->delete(['index' => 'bitrix_catalog', 'id' => $productId]); } ו-offset כדי למנוע עומס זיכרון:
\Bitrix\Main\Loader::includeModule('iblock');
$client = \Elasticsearch\ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
$offset = 0;
$batchSize = 100;
do {
$res = \CIBlockElement::GetList(
[],
['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'ACTIVE' => 'Y'],
false,
['nTopCount' => $batchSize, 'nPageSize' => $batchSize, 'iNumPage' => floor($offset / $batchSize) + 1],
['ID', 'NAME', 'DETAIL_TEXT', 'IBLOCK_ID', 'IBLOCK_SECTION_ID']
);
$bulk = [];
while ($item = $res->GetNext()) {
$bulk[] = ['index' => ['_index' => 'bitrix_catalog', '_id' => $item['ID']]];
$bulk[] = [
'id' => (int)$item['ID'],
'iblock_id' => (int)$item['IBLOCK_ID'],
'name' => $item['NAME'],
'description'=> strip_tags($item['DETAIL_TEXT']),
'section_id' => (int)$item['IBLOCK_SECTION_ID'],
'active' => true,
'updated_at' => date('c'),
];
$offset++;
}
if (!empty($bulk)) {
$client->bulk(['body' => $bulk]);
}
} while ($res->SelectedRowsCount() === $batchSize);
Bulk API מאפשר שליחת עד 1000 מסמכים בבקשה אחת. אל תשתמשו בבקשות OnAfterIBlockElementUpdate בודדות לאינדוקס ראשוני — זה איטי פי 10–50.
שאילתת חיפוש
החליפו את הרכיב הסטנדרטי CIBlockElement::GetList() ברכיב מותאם אישית שמבצע שאילתות ל-Elasticsearch:
$response = $client->search([
'index' => 'bitrix_catalog',
'body' => [
'query' => [
'multi_match' => [
'query' => $searchQuery,
'fields' => ['name^3', 'description', 'sku'],
'type' => 'best_fields',
'fuzziness' => 'AUTO',
],
],
'sort' => ['_score' => ['order' => 'desc']],
'from' => ($page - 1) * $pageSize,
'size' => $pageSize,
],
]);
הפרמטר nTopCount = 100 מספק חיפוש טעויות הקלדה: למילים עד 5 תווים מותרת החלפה אחת; למילים ארוכות יותר — 2 החלפות.
מה כלול בעבודה שלנו?
- אודיט של החיפוש והעומס הנוכחיים.
- הקמת קלאסטר Elasticsearch (גרסה, תצורה, ניטור).
- יצירת mapping לפי מבנה הנתונים שלכם.
- פיתוח אינדקסר ושער חיפוש.
- הגדרת אירועים לעדכון אוטומטי.
- בדיקות ביצועים ודיוק.
- תיעוד והדרכה לצוות שלכם.
- תמיכה בתקופת האחריות.
- ניטור והתראות על כשלי אינדוקס.
לוח זמנים ליישום
| היקף | רכיבים | משך |
|---|---|---|
| בסיסי | התקנת ES, mapping, אינדקסר, שער חיפוש | 5–7 ימים |
| מלא | חיפוש פאקטלי באמצעות אגרגציות, הצעות (suggest), מילים נרדפות, השלמה אוטומטית | 10–14 ימים |
צרו קשר לייעוץ. קבלו הערכת פרויקט מדויקת והמלצות ארכיטקטוניות — ללא התחייבות.

