Since Magento 2.4 Elasticsearch is the only supported search engine – MySQL Search was removed. For many shops it “just works”, but when a client reports that “the search doesn’t find the right products”, the real work begins. I show how Magento indexes data in ES, how to debug queries, and how to extend the index with custom fields.
How Magento indexes products in Elasticsearch
Magento creates a separate index in Elasticsearch for each store view, in the format magento2_product_1 (where 1 is the store view ID). The index contains JSON documents with product data – searchable, filterable and sortable attributes go into the appropriate fields according to the mapping.
# Full reindex of the product catalogue bin/magento indexer:reindex catalog_product_fulltext # Check indexer status bin/magento indexer:status # View index directly in Elasticsearch curl http://localhost:9200/_cat/indices?v # Check the Magento index mapping curl http://localhost:9200/magento2_product_1/_mapping | python3 -m json.tool
Debugging queries – what does Magento send to ES?
<?php
// Plugin to log ES queries - useful for debugging
namespace Vendor\Module\Plugin;
use Magento\Elasticsearch\Model\Adapter\ElasticsearchAdapter;
class ElasticsearchQueryLogger
{
public function __construct(private \Psr\Log\LoggerInterface $logger) {}
public function beforeQuery(ElasticsearchAdapter $subject, array $query): array
{
if (isset($_GET['debug_es'])) {
$this->logger->debug('ES Query', ['query' => json_encode($query, JSON_PRETTY_PRINT)]);
}
return [$query];
}
}
# Run the query directly against ES to see scoring details
curl -X GET "localhost:9200/magento2_product_1/_search?explain=true" \
-H 'Content-Type: application/json' \
-d '{
"query": {
"bool": {
"must": [{"match": {"name": {"query": "shoes", "boost": 2}}}],
"filter": [
{"term": {"status": 1}},
{"terms": {"visibility": [2, 3, 4]}}
]
}
}
}'
The explain=true parameter returns a detailed explanation of how ES calculated the score for each document – invaluable when debugging “why is this product ranked higher than that one”.
Extending the index with custom attributes
<?php
namespace Vendor\Module\Plugin;
use Magento\Elasticsearch\Model\Adapter\BatchDataMapper\ProductDataMapper;
class AddCustomDataToIndex
{
public function afterMap(
ProductDataMapper $subject,
array $documents,
array $documentData,
int $storeId,
array $context
): array {
foreach ($documents as $productId => &$document) {
// Add a custom field to the ES document
$document['sales_count_30d'] = $this->getSalesCount((int) $productId, 30);
$document['custom_tags'] = $this->getProductTags((int) $productId);
}
return $documents;
}
private function getSalesCount(int $productId, int $days): int { return 0; }
private function getProductTags(int $productId): string { return ''; }
}
<type name="Magento\Elasticsearch\Model\Adapter\BatchDataMapper\ProductDataMapper">
<plugin name="vendor_module_add_custom_data"
type="Vendor\Module\Plugin\AddCustomDataToIndex"/>
</type>
Custom analyzer for Polish language
<?php
namespace Vendor\Module\Plugin;
use Magento\Elasticsearch\Model\Adapter\Index\Builder;
class AddPolishAnalyzer
{
public function afterBuild(Builder $subject, array $settings): array
{
$settings['analysis']['analyzer']['polish_analyzer'] = [
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => ['lowercase', 'polish_stop', 'polish_stem'],
];
$settings['analysis']['filter']['polish_stop'] = [
'type' => 'stop',
'stopwords' => '_polish_',
];
$settings['analysis']['filter']['polish_stem'] = [
'type' => 'stemmer',
'language' => 'polish',
];
return $settings;
}
}
After changing the analyzer configuration a full reindex is required – Elasticsearch cannot modify the mapping of an existing index, Magento must recreate it from scratch.
Elasticsearch in DDEV – verifying the connection
# Check if ES is responding inside DDEV ddev exec curl -s http://elasticsearch:9200 # Configure Magento to connect to ES in the container ddev exec bin/magento config:set catalog/search/engine elasticsearch7 ddev exec bin/magento config:set catalog/search/elasticsearch7_server_hostname elasticsearch ddev exec bin/magento config:set catalog/search/elasticsearch7_server_port 9200
Summary
Elasticsearch in Magento 2 is not a black box – the index mapping, query structure and scoring mechanism are all accessible and modifiable. It is worth investing time to understand how Magento builds ES queries before writing your own extensions. The explain=true parameter and direct ES queries via curl are the fastest way to understand “why the search is returning wrong results”.
