Briefly, this error occurs when Elasticsearch tries to sort on a field that doesn’t exist in the mapping. The mapping is a process that defines how a document and its fields are stored and indexed. To resolve this issue, you can either create a new index with the correct mapping that includes the field you want to sort on, or you can update the mapping of the existing index to include the new field. Remember, updating the mapping will not affect the existing documents, so you may need to reindex your data.
Before you dig into reading this guide, have you tried asking OpsGPT what this log means? You’ll receive a customized analysis of your log.
Try OpsGPT now for step-by-step guidance and tailored insights into your Elasticsearch/OpenSearch operation.
In addition we also recommend you try running the Elasticsearch Error Check-Up which can resolve issues that cause many errors.
This guide will help you understand the origin of the log “No mapping found for [field name] in order to sort on”, why it happens, with which concepts of Elasticsearch it is related and then give you some ideas on how to debug and avoid it.
Overview
Elasticsearch informs you with this error message that it could not fulfil your search request because one of the fields listed on the sort part of your request is not mapped in the index.
What it means
When you create a new index, you have two choices on how the fields of that index will be mapped:
- Dynamic mapping: allows you to experiment with and explore data when you’re just getting started. Elasticsearch adds new fields automatically, just by indexing a document.
- Explicit mapping: allows you to precisely choose how to define the mapping definition.
Any field that was not explicitly mapped and that was not yet included in any of the documents already indexed will not have been mapped, meaning Elasticsearch couldn’t know its data type. In that case, Elasticsearch throws an error when this unmapped field is included as one of the fields by which the results should be sorted.
We can easily replicate this by creating an index, indexing a document and then sending a search request sorting by some field not included in that document:
PUT test POST test/_doc { "id": "1", "i_value": -1, "d_value": -1.1 } POST test/_search { "sort": { "some_field": "desc" } } Result: { "error" : { "root_cause" : [ { "type" : "query_shard_exception", "reason" : "No mapping found for [some_field] in order to sort on", "index_uuid" : "Y-er-CNcRKiRMF5Ywd6PHA", "index" : "test" } ], "type" : "search_phase_execution_exception", "reason" : "all shards failed", "phase" : "query", "grouped" : true, "failed_shards" : [ { "shard" : 0, "index" : "test", "node" : "h4JFNQwSSvypf9vCF0ZLvQ", "reason" : { "type" : "query_shard_exception", "reason" : "No mapping found for [some_field] in order to sort on", "index_uuid" : "Y-er-CNcRKiRMF5Ywd6PHA", "index" : "test" } } ] }, "status" : 400 } On the other hand, notice that if the field was mapped, Elasticsearch would have no problem fulfilling our request: PUT test { "mappings": { "properties": { "some_field": { "type": "keyword" } } } } POST test/_doc { "id": "1", "i_value": -1, "d_value": -1.1 } POST test/_search { "sort": { "some_field": "desc" } } Result: { "took" : 0, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "test", "_type" : "_doc", "_id" : "BONmRXsBcaxskpj9pIrZ", "_score" : null, "_source" : { "id" : "1", "i_value" : -1, "d_value" : -1.1 }, "sort" : [ null ] } ] } }
Why it occurs
This error occurs because the sort part of your search request includes a field that is not yet mapped in the index (either dynamically, when the first document containing that field gets indexed, or explicitly, by defining the index’s schema beforehand).
One very common scenario in which this occurs is when you have several indices with possible different schemas hidden behind an alias. For example, this could be a time series observability solution that receives metrics from different subjects being monitored, each of them providing a different set of metrics. If your search use case expects all of them to comply with a common schema, but you actually never defined an index template that would map all the possible fields for every different sub-schema, then it may occur that some fields exist (and therefore are mapped) for some of those indices, but not for the others. If your user wants to sort for that field, the search request would fail.
In the example below, we created a couple of indices without mapping their fields first. We then hid them behind an alias and ran some queries on it trying to sort by fields that both exist and don’t exist in our source indices.
PUT house-sensors-doors-00001/_doc/1 { "sensor_id": 1, "subject_id": 1, "measured_at": "2021-08-28T10:42:00Z", "where": "hall", "description": "front door", "locked": true } PUT house-sensors-appliances-00001/_doc/2 { "sensor_id": 2, "subject_id": 2, "measured_at": "2021-08-28T10:43:00Z", "where": "kitchen", "description": "oven", "on": true, "temperature": 375, "temperature_scale": "Farenheit" } POST _aliases { "actions": [ { "add": { "index": "house-sensors*", "alias": "house-sensors" } } ] }
If you sort by a field that exists in both indices, the request will not fail:
GET house-sensors/_search { "sort": { "measured_at": "desc" } } Response: { "took" : 4, "timed_out" : false, "_shards" : { "total" : 2, "successful" : 2, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "house-sensors-appliances-00001", "_type" : "_doc", "_id" : "2", "_score" : null, "_source" : { "sensor_id" : 2, "subject_id" : 2, "measured_at" : "2021-08-28T10:43:00Z", "where" : "kitchen", "description" : "oven", "on" : true, "temperature" : 375, "temperature_scale" : "Farenheit" }, "sort" : [ 1630147380000 ] }, { "_index" : "house-sensors-doors-00001", "_type" : "_doc", "_id" : "1", "_score" : null, "_source" : { "sensor_id" : 1, "subject_id" : 1, "measured_at" : "2021-08-28T10:42:00Z", "where" : "hall", "description" : "front door", "locked" : true }, "sort" : [ 1630147320000 ] } ] } }
But if you try to sort by a field that does not exist in both indices, the request will partially fail:
GET house-sensors/_search { "sort": { "temperature": "desc" } } Response: { "took" : 1, "timed_out" : false, "_shards" : { "total" : 2, "successful" : 1, "skipped" : 0, "failed" : 1, "failures" : [ { "shard" : 0, "index" : "house-sensors-doors-00001", "node" : "h4JFNQwSSvypf9vCF0ZLvQ", "reason" : { "type" : "query_shard_exception", "reason" : "No mapping found for [temperature] in order to sort on", "index_uuid" : "Vmp6BImnTnqOP6ALF8IxNQ", "index" : "house-sensors-doors-00001" } } ] }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "house-sensors-appliances-00001", "_type" : "_doc", "_id" : "2", "_score" : null, "_source" : { "sensor_id" : 2, "subject_id" : 2, "measured_at" : "2021-08-28T10:43:00Z", "where" : "kitchen", "description" : "oven", "on" : true, "temperature" : 375, "temperature_scale" : "Farenheit" }, "sort" : [ 375 ] } ] } }
How to resolve it
If the sort part of your search request includes an unmapped field, chances are it’s because:
- You misspelled the field’s name.
- It’s a field that used to exist, but was removed.
- It’s a field that you expect to exist at some point, but since no document actually included it yet, and since the mapping of your index was probably not statically created, it remains unmapped.
- It’s a new field present in recent indexes of a time series, but wasn’t present in older indices of the same time series and the time series is queried over an alias.
If you misspelled or if the field does not exist anymore, the fix should be easy: just correct it in your application. For the third and fourth scenarios, if you expect the field to exist at some point and want to keep as a sortable field in your application, you can get around it by explicitly mapping:
PUT test/_mapping { "properties": { "some_field": { "type": "keyword" } } }
That will prevent Elasticsearch from throwing the “No mapping found for [field name] in order to sort on”.
By the way, it’s always a good practice to explicitly map your indices and not rely on the dynamic mapping feature, because you sure know more about your data than Elasticsearch, as stated in its official documentation.
Log Context
It might help knowing where in Elasticsearch code this error log is thrown. If we take a look at the FieldSortBuilder.java class for the codebase for 7.14 version of Elasticsearch we can easily see that it is thrown by the resolveUnmappedType() method as shown below:
private MappedFieldType resolveUnmappedType(SearchExecutionContext context) { if (unmappedType == null) { throw new QueryShardException(context, "No mapping found for [" + fieldName + "] in order to sort on"); } return context.buildAnonymousFieldType(unmappedType); }
In the FieldSortIT.java we can find the integration tests related to field sorting. If we take a look at the test described by the testIgnoreUnmapped() we can see that it expects that the “No mapping found for [field name] in order to sort on” is thrown when the sort part of your search request asks the cluster to sort by a field that was not mapped. In the case of this integration test they create an index, index a document with some fields and then execute a search request sorting by a field that was not mapped neither explicitly, nor by being included in the document indexed.
public void testIgnoreUnmapped() throws Exception { createIndex("test"); client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() .field("id", "1") .field("i_value", -1) .field("d_value", -1.1) .endObject()).get(); logger.info("--> sort with an unmapped field, verify it fails"); try { SearchResponse result = client().prepareSearch() .setQuery(matchAllQuery()) .addSort(SortBuilders.fieldSort("kkk")) .get(); assertThat("Expected exception but returned with", result, nullValue()); } catch (SearchPhaseExecutionException e) { //we check that it's a parse failure rather than a different shard failure for (ShardSearchFailure shardSearchFailure : e.shardFailures()) { assertThat(shardSearchFailure.toString(), containsString("[No mapping found for [kkk] in order to sort on]")); } } ...
Overview
Mapping is similar to database schemas that define the properties of each field in the index. These properties may contain the data type of each field and how fields are going to be tokenized and indexed. In addition, the mapping may also contain various advanced level properties for each field to define the options exposed by Lucene and Elasticsearch.
You can create a mapping of an index using the _mappings REST endpoint. The very first time Elasticsearch finds a new field whose mapping is not pre-defined inside the index, it automatically tries to guess the data type and analyzer of that field and set its default value. For example, if you index an integer field without pre-defining the mapping, Elasticsearch sets the mapping of that field as long.
Examples
Create an index with predefined mapping:
PUT /my_index?pretty { "settings": { "number_of_shards": 1 }, "mappings": { "properties": { "name": { "type": "text" }, "age": { "type": "integer" } } } }
Create mapping in an existing index:
PUT /my_index/_mapping?pretty { "properties": { "email": { "type": "keyword" } } }
View the mapping of an existing index:
GET my_index/_mapping?pretty
View the mapping of an existing field:
GET /my_index/_mapping/field/name?pretty
Notes
- It is not possible to update the mapping of an existing field. If the mapping is set to the wrong type, re-creating the index with updated mapping and re-indexing is the only option available.
- In version 7.0, Elasticsearch has deprecated the document type and the default document type is set to _doc. In future versions of Elasticsearch, the document type will be removed completely.
How to optimize your Elasticsearch mapping to reduce costs
Watch the video below to learn how to save money on your deployment by optimizing your mapping.
Common problems
- The most common problem in Elasticsearch is incorrectly defined mapping which limits the functionality of the field. For example, if the data type of a string field is set as text, you cannot use that field for aggregations, sorting or exact match filters. Similarly, if a string field is dynamically indexed without predefined mapping, Elasticsearch automatically creates two fields internally. One as a text type for full-text search and another as keyword type, which in most cases is a waste of space.
- Elasticsearch automatically creates an _all field inside the mapping and copies values of each field of a document inside the _all field. This field is used to search text without specifying a field name. Make sure to disable the _all field in production environments to avoid wasting space. Please note that support for the _all field has been removed in version 7.0.
- In versions lower than 5.0, it was possible to create multiple document types inside an index, similar to creating multiple tables inside a database. In those versions, there were higher chances of getting data types conflicts across different document types if they contained the same field name with different data types.
- The mapping of each index is part of the cluster state and is managed by master nodes. If the mapping is too big, meaning there are thousands of fields in the index, the cluster state grows too large to be handled and creates the issue of mapping explosion, resulting in the slowness of the cluster.
Introduction
Sorting is an essential aspect of Elasticsearch when it comes to presenting search results in a specific order. By default, Elasticsearch sorts the results based on the relevance score, which is calculated using the Lucene scoring formula. However, there are cases where you might want to sort the results based on other criteria, such as a specific field value or a custom sorting logic. In this article, we will explore advanced techniques and best practices for sorting in Elasticsearch.
Advanced techniques and best practices for sorting in Elasticsearch
1. Sorting by Field Values
To sort the search results based on a specific field value, you can use the “sort” parameter in your search query. For example, if you want to sort the results based on the “price” field in ascending order, you can use the following query:
GET /products/_search { "query": { "match_all": {} }, "sort": [ { "price": { "order": "asc" } } ] }
2. Sorting by Multiple Fields
You can also sort the search results based on multiple fields by specifying an array of sort objects. For example, if you want to sort the results first by “category” in ascending order and then by “price” in descending order, you can use the following query:
GET /products/_search { "query": { "match_all": {} }, "sort": [ { "category": { "order": "asc" } }, { "price": { "order": "desc" } } ] }
3. Sorting with Missing Values
In some cases, the documents in your index might not have a value for the field you want to sort by. By default, Elasticsearch treats these documents as having the lowest possible value for the field. However, you can control how Elasticsearch handles missing values by using the “missing” parameter. For example, if you want to treat documents with missing “price” values as having the highest possible price, you can use the following query:
GET /products/_search { "query": { "match_all": {} }, "sort": [ { "price": { "order": "asc", "missing": "_last" } } ] }
4. Sorting with Nested Fields
If you have nested fields in your documents, you can sort the search results based on the values of these fields using the “nested” parameter. For example, if you have a “reviews” nested field with a “rating” property, you can sort the products based on the average rating as follows:
GET /products/_search { "query": { "match_all": {} }, "sort": [ { "reviews.rating": { "order": "desc", "nested": { "path": "reviews" }, "mode": "avg" } } ] }
5. Custom Sorting with Script-Based Sorting
In some cases, you might want to apply custom sorting logic that cannot be achieved using the built-in sorting options. In such cases, you can use script-based sorting to define your custom sorting logic using Painless, Elasticsearch’s scripting language. For example, if you want to sort the products based on the difference between their regular price and discounted price, you can use the following query:
GET /products/_search { "query": { "match_all": {} }, "sort": [ { "_script": { "type": "number", "script": { "source": "doc['regular_price'].value - doc['discounted_price'].value" }, "order": "desc" } } ] }
Best Practices for Sorting in Elasticsearch
- Use Doc Values: When sorting by field values, make sure to use doc values, which are the on-disk data structure that Elasticsearch uses for sorting and aggregations. Doc values are enabled by default for most field types, but if not, you can explicitly enable them by setting the “doc_values” parameter to “true” in your field mapping.
- Avoid Sorting by Text Fields: Sorting by text fields can be slow and memory-intensive, as Elasticsearch needs to load the field data into memory. Instead, use keyword fields or other field types that support doc values for sorting.
- Use Index Sorting: If you have a fixed sorting order that you use frequently, you can improve the sorting performance by using index sorting. Index sorting sorts the documents during indexing, which can speed up the sorting process during search. However, keep in mind that index sorting can increase the indexing time and memory usage.
- Optimize Pagination: When using sorting with pagination, avoid using deep pagination, as it can be slow and memory-intensive. Instead, use the “search_after” parameter to paginate through the search results more efficiently.
Conclusion
By following these advanced techniques and best practices, you can optimize the sorting process in Elasticsearch and ensure that your search results are presented in the desired order.
Overview
Search refers to the searching of documents in an index or multiple indices. The simple search is just a GET API request to the _search endpoint. The search query can either be provided in query string or through a request body.
Examples
When looking for any documents in this index, if search parameters are not provided, every document is a hit and by default 10 hits will be returned.
GET my_documents/_search
A JSON object is returned in response to a search query. A 200 response code means the request was completed successfully.
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 1.0, "hits" : [ ... ] } }
Notes and good things to know
- Distributed search is challenging and every shard of the index needs to be searched for hits, and then those hits are combined into a single sorted list as a final result.
- There are two phases of search: the query phase and the fetch phase.
- In the query phase, the query is executed on each shard locally and top hits are returned to the coordinating node. The coordinating node merges the results and creates a global sorted list.
- In the fetch phase, the coordinating node brings the actual documents for those hit IDs and returns them to the requesting client.
- A coordinating node needs enough memory and CPU in order to handle the fetch phase.
Log Context
Log “No mapping found for [” + fieldName + “] in order to sort on” class name is FieldSortBuilder.java. We extracted the following from Elasticsearch source code for those seeking an in-depth context :
} } private MappedFieldType resolveUnmappedType(SearchExecutionContext context) { if (unmappedType == null) { throw new QueryShardException(context; "No mapping found for [" + fieldName + "] in order to sort on"); } return context.buildAnonymousFieldType(unmappedType); } private MultiValueMode localSortMode() {