Elasticsearch for Bitrix: 10x faster search

When Bitrix built-in search stops working With 100 thousand products, the built-in MySQL-based search slows down: queries to b_search_content take 300–500 ms, and on a million-record database — timeout. Clients complain about long search times, price sorting doesn't work, facets overload the data

Our competencies:

Frequently Asked Questions

When Bitrix built-in search stops working

With 100 thousand products, the built-in MySQL-based search slows down: queries to b_search_content take 300–500 ms, and on a million-record database — timeout. Clients complain about long search times, price sorting doesn't work, facets overload the database. For example, a recent project with a catalog of 250,000 products: standard search returned results in 2–3 seconds, complex property filters (price, brand, size) caused 30-second pauses. Elasticsearch solves this radically: response time 5–30 ms, aggregations on the fly, typos and morphology out of the box. Our experience — 30+ ES integrations with Bitrix, we guarantee a turnkey result. We use licensed components and are 1C-Bitrix certified. To understand if Elasticsearch is right for your project, order a free audit — we will analyze the load and data structure.

Problems that Elasticsearch solves

Elasticsearch replaces the standard Bitrix search engine and solves three key problems:

  1. Full-text search speed. MySQL FULLTEXT starts slowing down at 50–100 thousand documents. ES handles millions.
  2. Faceted search (aggregations). Bitrix built-in filters are separate queries for each property. ES returns aggregations in one request, giving a 10–20x gain on complex filters.
  3. Search with typos and synonyms. Without third-party modules, MySQL does not support fuzzy search. ES has built-in fuzziness and synonyms.

If you face similar issues, contact us for an audit — it will help identify bottlenecks.

Why Elasticsearch is faster than MySQL FULLTEXT?

Characteristic MySQL FULLTEXT Elasticsearch
Index type B-tree + inverted file Inverted index + FST
Morphology External dictionaries needed (morphy) Stemmer and analyzers (russian)
Typo search Not supported Fuzziness (AUTO)
Aggregations (facets) Not supported Supported, in one query
Speed on 1 million documents (single query) 200–500 ms 5–30 ms

Elasticsearch is 10–50 times faster than MySQL FULLTEXT on large data.

Integration architecture

The integration consists of three parts:

  1. Indexer — a component that reads data from Bitrix (infoblocks, users, pages) and writes documents to Elasticsearch index.
  2. Search gateway — replaces standard requests to b_search_content with requests to Elasticsearch API. The gateway is implemented as a PHP proxy: it receives a request from the standard bitrix:search.page component, transforms it into Elasticsearch query DSL, and returns results in the format expected by Bitrix.
  3. Event handlers — update the index when entities are modified or deleted.

Index structure for product catalog

The index is created via Elasticsearch Mapping API. Example mapping for products:

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_" } } } } } 

The russian analyzer with stemmer is a key difference from MySQL FULLTEXT, which without additional dictionaries does not understand morphology.

Example analyzer configuration with synonyms
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"] } } } } 

How to set up automatic index update?

Subscribe to infoblock events:

// local/php_interface/init.php AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'esUpdateProduct'); AddEventHandler('iblock', 'OnAfterIBlockElementDelete', 'esDeleteProduct'); function esUpdateProduct(array &$arFields): void { $client = getEsClient(); $productId = (int)$arFields['ID']; // Re-index a single document $client->index([ 'index' => 'bitrix_catalog', 'id' => $productId, 'body' => buildProductDocument($productId), ]); } function esDeleteProduct(int $productId): void { getEsClient()->delete(['index' => 'bitrix_catalog', 'id' => $productId]); } 

The OnAfterIBlockElementUpdate event also triggers on API changes (1C import), which is important for index freshness.

Data indexing

Initial indexing is run via a cron script. Data is read in batches using CIBlockElement::GetList() with nTopCount = 100 and offset to avoid memory overload:

\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 allows sending up to 1000 documents per request. Do not use individual index requests for initial indexing — it is 10–50 times slower.

Search query

Replace the standard bitrix:search.page component with a custom one that queries 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, ], ]); 

The fuzziness: AUTO parameter provides typo search: for words up to 5 characters, 1 substitution is allowed; for longer words, 2 substitutions.

What is included in our work?

  • Audit of current search and load.
  • Setting up Elasticsearch cluster (version, configuration, monitoring).
  • Creating mapping according to your data structure.
  • Developing indexer and search gateway.
  • Configuring events for automatic update.
  • Performance and accuracy testing.
  • Documentation and training for your team.
  • Support during the warranty period.
  • Monitoring and alerts for indexing failures.

Implementation timeline

Scope Components Duration
Basic ES installation, mapping, indexer, search gateway 5–7 days
Full Faceted search via aggregations, suggestions (suggest), synonyms, autocomplete 10–14 days

Contact us for a consultation. Get an accurate project estimate and architectural recommendations — with no obligation.