from the real query to an isolated root cause
When search in the store returns wrong or missing results, guessing rarely helps. Systematic search debugging starts by capturing the actual Elasticsearch query Magento generates, running that query directly against the cluster, and reliably separating whether the problem lies in Magento's logic or in the Elasticsearch index itself. This article walks through the methodology step by step.
Table of Contents
- 1. Why search debugging fails without a methodology
- 2. Enabling debug logging in Magento
- 3. Extracting the real query from the log
- 4. Replaying the query directly against Elasticsearch
- 5. Isolating the Magento layer vs. the Elasticsearch layer
- 6. Common root causes on the Magento side
- 7. Common root causes on the Elasticsearch side
- 8. Tools for relevance debugging: Validate and Explain
- 9. A reusable debug runbook
- 10. Summary
- 11. FAQ
1. Why search debugging fails without a methodology
"Search does not find the product" is one of the most common, and simultaneously hardest to pin down, support reports in a Magento project. Without systematic search debugging, troubleshooting usually starts in the storefront: developers type the same search term repeatedly, change filters, check product visibility in the admin, and eventually stumble on an explanation by chance. This approach is time-consuming and produces no reliable diagnosis, because it never actually shows what Magento sent to Elasticsearch.
The core of the problem is unclear layer separation. A Magento search passes through multiple layers: PHP-side query construction, transmission to Elasticsearch, analysis and scoring inside the cluster, and finally result rendering for the storefront. A bug can originate in any of these layers, but without a methodology that cleanly separates them, every root cause remains a guess. Systematic search debugging solves this by making the Magento layer and the Elasticsearch layer independently testable.
This article presents a repeatable methodology: enable debug logging, extract the real query, run it in isolation against Elasticsearch, and use the result to decide which layer the actual problem lives in. This methodology works regardless of whether the issue is missing hits, wrong relevance ordering, or unexpected zero-result pages.
2. Enabling debug logging in Magento
The first step of any thorough search debugging is getting Magento to reveal the query it actually sends. Under Stores > Configuration > Catalog > Catalog Search, the Elasticsearch configuration section has an option "Enable Elasticsearch Debug Logging". When enabled, Magento writes a complete log entry for every request sent to Elasticsearch, including the request body and response, into var/log/es_queries.log.
This setting should only be enabled temporarily in production environments, because it creates noticeable I/O load under heavy search traffic and potentially logs sensitive search terms. For targeted search debugging, it is enough to enable debug logging briefly, run the problematic search on the storefront, then disable it again immediately. In staging environments, the option can safely stay on permanently without operational risk.
# Enable Elasticsearch debug logging via CLI (store-scoped config path)
bin/magento config:set catalog/search/engine elasticsearch7
bin/magento config:set catalog/search/elasticsearch7_server_hostname localhost
bin/magento config:set dev/query_logging/enabled 1
# Reproduce the problematic search in the storefront now
# Tail the query log while the search runs
bin/log es_queries.log
# Disable again once the query has been captured
bin/magento config:set dev/query_logging/enabled 0
3. Extracting the real query from the log
The es_queries.log file contains, for every search request, a block with the complete JSON query exactly as it was sent to the _search endpoint of the relevant store index. This query is noticeably more complex than what a developer would intuitively expect: Magento combines a bool query with must and should clauses for the fulltext search, filters for visibility and store, and frequently a function_score component that weights the relevance of attributes such as name versus description.
For efficient search debugging, it is worth copying the extracted query into a separate JSON file and formatting it there, rather than reading it directly from the often unformatted log text. A common mistake here: developers copy only part of the query, for example omitting the _source filtering or the sort parameters, and then wonder why the isolated test produces a different result than the storefront. The complete query, including all header parameters, is the baseline requirement for a valid replay.
{
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{ "match": { "name": { "query": "running shoe", "boost": 3 } } },
{ "match": { "sku": { "query": "running shoe", "boost": 5 } } },
{ "match": { "description": { "query": "running shoe", "boost": 1 } } }
],
"minimum_should_match": 1
}
}
],
"filter": [
{ "term": { "visibility": 4 } },
{ "term": { "store_id": 1 } }
]
}
},
"sort": [ { "_score": "desc" } ],
"size": 24,
"from": 0
}
4. Replaying the query directly against Elasticsearch
Once the complete query is available, it can be run directly against the Elasticsearch cluster with curl or Kibana Dev Tools, completely independent of Magento. This step is the core of search debugging, because it shows Elasticsearch's response without any processing by the Magento application layer. If the direct replay returns the same, user-visible incorrect results as the storefront, the problem is very likely inside the index itself or in the query logic. If the replay instead returns different, correct results, the bug must lie between query construction and result rendering in the Magento application layer.
For a clean replay, it is important to use the same index alias that Magento uses for the relevant store. Store-specific indices carry names like magento2_default_catalogsearch_fulltext_1, where the trailing number is the store ID. Replaying against the wrong store index produces apparently contradictory results that have nothing to do with the actual problem, but merely reflect different analyzer configurations or synonym groups between stores.
# Replay the extracted query directly against the store's Elasticsearch index
curl -s -X POST "localhost:9200/magento2_default_catalogsearch_fulltext_1/_search" \
-H "Content-Type: application/json" \
-d @extracted_query.json | jq '.hits.total, .hits.hits[]._source.sku'
# Compare hit count with what the storefront actually shows
# If counts match: the problem is likely in the ES layer (mapping, analyzer, data)
# If counts differ: the problem is likely in the Magento layer (query building, result mapping)
5. Isolating the Magento layer vs. the Elasticsearch layer
The real strength of this methodology lies in the clean separation of responsibilities. If the isolated replay returns the same unexpected results as the storefront, the Magento application layer is largely ruled out as the source, and search debugging can focus entirely on Elasticsearch: check the mapping, test the analyzer, verify document contents in the index. This focus saves enormous amounts of time, because it prevents searching the PHP codebase for a bug that does not exist there.
If, on the other hand, the replay shows correct results while the storefront returns wrong ones, the focus shifts to the Magento side: Is the query correctly parsed from the response? Do additional filters apply in the ViewModel or block that are not part of the actual Elasticsearch query, for example a post-hoc price filter based on a stale price cache? Is the result manipulated afterward by a plugin or extension? This separation turns a vague "search is broken" into a clearly scoped technical problem.
| Symptom | Replay result | Likely cause | Next step |
|---|---|---|---|
| Product missing entirely | Also missing in replay | Elasticsearch layer | Check mapping and indexing of the product |
| Product missing on storefront | Present in replay | Magento layer | Check post-filtering, cache, plugin chain |
| Wrong sort order | Same order as storefront | Elasticsearch layer | Check boost values and function_score |
| Zero results | Hits present in replay | Magento layer | Check result parsing and ViewModel logic |
6. Common root causes on the Magento side
On the Magento side, search bugs often stem from additional filter logic applied after the Elasticsearch request. A classic example is a custom price filter based on a separate, stale price cache that hides products afterward even though Elasticsearch correctly returned them. Another common pattern is faulty pagination logic that gets the correct total hit count but incorrectly offsets when rendering the current page, causing products to appear to vanish.
Layout XML configurations can also become a source of errors: a block that displays additional attributes in the search results can throw an exception on missing attribute data, which in the worst case is silently swallowed and produces a fake empty result. Such cases cannot be found through pure search debugging on the Elasticsearch side, which is why the layer separation from section 5 is so critical for investigating search in the right codebase.
7. Common root causes on the Elasticsearch side
On the Elasticsearch side, the most common cause is a mismatch between the expected and the actual field mapping. If an attribute is changed from text to keyword afterward without rebuilding the index, search on that field behaves inconsistently, because old documents are still indexed with the old mapping. Another common problem is analyzer discrepancies: if a custom analyzer is configured only for product names but not for descriptions, the same search term produces different hit rates depending on which field is searched, which appears completely inexplicable to end users.
Stale index data is also a common cause: a product was changed in the admin, but the corresponding Elasticsearch document still reflects the old state, because the partial reindex failed or the changelog entry was never generated. A direct GET call on the document by its ID immediately shows whether the data stored in the index matches the current product data in the database.
# Fetch the raw indexed document for a specific product by its entity ID
curl -s "localhost:9200/magento2_default_catalogsearch_fulltext_1/_doc/10231?pretty"
# Compare relevant fields against the current database state
bin/mysql magento -e "
SELECT sku, value AS name
FROM catalog_product_entity_varchar v
JOIN eav_attribute a ON a.attribute_id = v.attribute_id AND a.attribute_code = 'name'
JOIN catalog_product_entity e ON e.entity_id = v.entity_id
WHERE e.entity_id = 10231;
"
# If name differs between the two outputs, the index entry is stale
8. Tools for relevance debugging: Validate and Explain
Beyond plain query replay, Elasticsearch offers two specialized APIs that significantly speed up search debugging. The _validate/query API with the explain=true parameter checks whether a query is syntactically and semantically valid and returns a precise error message on failure, without actually executing the query. This is especially useful when a query generated by Magento becomes invalid due to a broken custom extension and the storefront only shows a generic error without details.
The _explain API, on the other hand, shows for a single document exactly how its relevance score for a given query was computed, including every individual boost factor and sub-score. When a customer complains that an irrelevant product is shown above an obviously better-matching one, the Explain API delivers the exact reason: for example, an overly high boost on an attribute that works against the desired outcome in this specific case. Without this API, the cause of a wrong relevance order would remain pure speculation.
9. A reusable debug runbook
So that search debugging does not have to be improvised for every new case, a documented runbook with fixed steps is worthwhile: enable debug logging, reproduce the search, extract the query from the log, replay the query against the correct store index, compare the result with the storefront, determine the layer based on the comparison, and continue with mapping review or codebase analysis depending on the layer. Such a runbook substantially cuts onboarding time for new team members and ensures every search bug is investigated using the same, traceable pattern.
For recurring cases, a small script that automates the most common steps also pays off: enable debug logging via CLI, extract the last query from the log after a defined wait, automatically replay it against the appropriate store index, and print the hit count along with top results directly in the terminal. This shortens the time from the first support ticket to the first reliable diagnosis from hours to a few minutes.
#!/usr/bin/env bash
# debug-search.sh - minimal automated search debugging runbook
set -euo pipefail
STORE_INDEX="magento2_default_catalogsearch_fulltext_1"
# Step 1: extract the most recent query block from the debug log
last_query=$(tac var/log/es_queries.log | grep -m1 -A 30 '"query"' | tac)
# Step 2: replay it against the correct store index
echo "$last_query" > /tmp/last_query.json
curl -s -X POST "localhost:9200/${STORE_INDEX}/_search" \
-H "Content-Type: application/json" \
-d @/tmp/last_query.json > /tmp/replay_result.json
# Step 3: print total hits and top 5 SKUs for quick comparison
jq '.hits.total.value, [.hits.hits[:5][]._source.sku]' /tmp/replay_result.json
Mironsoft
Systematic search debugging for Magento and Elasticsearch setups
Search bugs nobody can explain?
We set up debug logging and a reusable runbook, isolate root causes between Magento and Elasticsearch, and deliver reliable diagnoses instead of guesses.
Debug setup
Set up query logging, extraction, and replay tooling for your team
Layer isolation
Narrow down concrete search bugs between the Magento and Elasticsearch layer
Runbook
Build a documented debug process for your support team
10. Summary
Successful search debugging in Magento never starts on the storefront, it starts with capturing the actual Elasticsearch query via es_queries.log. Replaying that query directly against the correct store index, independent of the Magento application layer, is the decisive step for determining whether a search bug originates in the PHP codebase or inside the Elasticsearch index itself. This layer separation turns a vague error report into a clearly scoped technical problem.
Additional tools like the _validate/query and _explain APIs give precise answers to questions that would otherwise remain pure speculation: is a query valid, and why did a specific document receive exactly this relevance score. Anyone who captures this methodology in a documented runbook drastically reduces the time from the first search bug ticket to a reliable diagnosis, and turns search debugging into a repeatable process rather than an art form.
Search debugging in Magento, the essentials at a glance
Capture the query
Enable Elasticsearch debug logging, extract the actual query from es_queries.log.
Replay the query
Run it directly against the correct store index, independent of the Magento application layer.
Isolate the layer
If the replay result matches the storefront, the bug is in Elasticsearch, otherwise it is in Magento.
Specialized APIs
_validate/query for syntax errors, _explain for traceable relevance scores.