By default, full-text queries sort results by the relevance score. You can choose to sort the results by any field value in either ascending or descending order by setting the parameter to asc or desc.

For example, to sort results by descending order of a line_id value, use the following query:

The results are sorted by line_id in descending order:

  1. {
  2. "took" : 24,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 3205,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [
  17. {
  18. "_index" : "shakespeare",
  19. "_id" : "3204",
  20. "_score" : null,
  21. "_source" : {
  22. "type" : "line",
  23. "line_id" : 3205,
  24. "play_name" : "Henry IV",
  25. "speech_number" : 8,
  26. "line_number" : "",
  27. "speaker" : "KING HENRY IV",
  28. "text_entry" : "Exeunt"
  29. },
  30. "sort" : [
  31. 3205
  32. ]
  33. },
  34. {
  35. "_index" : "shakespeare",
  36. "_id" : "3203",
  37. "_score" : null,
  38. "_source" : {
  39. "type" : "line",
  40. "line_id" : 3204,
  41. "play_name" : "Henry IV",
  42. "speech_number" : 8,
  43. "line_number" : "5.5.45",
  44. "speaker" : "KING HENRY IV",
  45. "text_entry" : "Let us not leave till all our own be won."
  46. },
  47. "sort" : [
  48. 3204
  49. ]
  50. },
  51. {
  52. "_index" : "shakespeare",
  53. "_id" : "3202",
  54. "_score" : null,
  55. "_source" : {
  56. "type" : "line",
  57. "line_id" : 3203,
  58. "play_name" : "Henry IV",
  59. "speech_number" : 8,
  60. "line_number" : "5.5.44",
  61. "speaker" : "KING HENRY IV",
  62. "text_entry" : "And since this business so fair is done,"
  63. },
  64. "sort" : [
  65. 3203
  66. ]
  67. },
  68. {
  69. "_index" : "shakespeare",
  70. "_id" : "3201",
  71. "_score" : null,
  72. "_source" : {
  73. "type" : "line",
  74. "line_id" : 3202,
  75. "play_name" : "Henry IV",
  76. "speech_number" : 8,
  77. "line_number" : "5.5.43",
  78. "speaker" : "KING HENRY IV",
  79. "text_entry" : "Meeting the cheque of such another day:"
  80. },
  81. "sort" : [
  82. 3202
  83. ]
  84. },
  85. {
  86. "_index" : "shakespeare",
  87. "_id" : "3200",
  88. "_score" : null,
  89. "_source" : {
  90. "type" : "line",
  91. "line_id" : 3201,
  92. "play_name" : "Henry IV",
  93. "speech_number" : 8,
  94. "line_number" : "5.5.42",
  95. "speaker" : "KING HENRY IV",
  96. "text_entry" : "Rebellion in this land shall lose his sway,"
  97. },
  98. "sort" : [
  99. 3201
  100. ]
  101. },
  102. {
  103. "_index" : "shakespeare",
  104. "_id" : "3199",
  105. "_score" : null,
  106. "_source" : {
  107. "type" : "line",
  108. "line_id" : 3200,
  109. "play_name" : "Henry IV",
  110. "speech_number" : 8,
  111. "line_number" : "5.5.41",
  112. "speaker" : "KING HENRY IV",
  113. "text_entry" : "To fight with Glendower and the Earl of March."
  114. },
  115. "sort" : [
  116. 3200
  117. ]
  118. },
  119. {
  120. "_index" : "shakespeare",
  121. "_id" : "3198",
  122. "_score" : null,
  123. "_source" : {
  124. "type" : "line",
  125. "line_id" : 3199,
  126. "play_name" : "Henry IV",
  127. "speech_number" : 8,
  128. "line_number" : "5.5.40",
  129. "speaker" : "KING HENRY IV",
  130. "text_entry" : "Myself and you, son Harry, will towards Wales,"
  131. },
  132. "sort" : [
  133. 3199
  134. ]
  135. },
  136. {
  137. "_index" : "shakespeare",
  138. "_id" : "3197",
  139. "_score" : null,
  140. "_source" : {
  141. "type" : "line",
  142. "line_id" : 3198,
  143. "play_name" : "Henry IV",
  144. "speech_number" : 8,
  145. "line_number" : "5.5.39",
  146. "speaker" : "KING HENRY IV",
  147. "text_entry" : "Who, as we hear, are busily in arms:"
  148. },
  149. "sort" : [
  150. 3198
  151. ]
  152. },
  153. {
  154. "_index" : "shakespeare",
  155. "_id" : "3196",
  156. "_score" : null,
  157. "_source" : {
  158. "type" : "line",
  159. "line_id" : 3197,
  160. "play_name" : "Henry IV",
  161. "speech_number" : 8,
  162. "line_number" : "5.5.38",
  163. "speaker" : "KING HENRY IV",
  164. "text_entry" : "To meet Northumberland and the prelate Scroop,"
  165. },
  166. "sort" : [
  167. 3197
  168. ]
  169. },
  170. {
  171. "_index" : "shakespeare",
  172. "_id" : "3195",
  173. "_score" : null,
  174. "_source" : {
  175. "type" : "line",
  176. "line_id" : 3196,
  177. "play_name" : "Henry IV",
  178. "speech_number" : 8,
  179. "line_number" : "5.5.37",
  180. "speaker" : "KING HENRY IV",
  181. "text_entry" : "Towards York shall bend you with your dearest speed,"
  182. },
  183. "sort" : [
  184. ]
  185. }
  186. ]
  187. }
  188. }

The sort parameter is an array, so you can specify multiple field values in the order of their priority.

If you have two fields with the same value for line_id, OpenSearch uses speech_number, which is the second option for sorting:

  1. GET shakespeare/_search
  2. {
  3. "query": {
  4. "term": {
  5. "play_name": {
  6. "value": "Henry IV"
  7. }
  8. }
  9. },
  10. "sort": [
  11. {
  12. "line_id": {
  13. "order": "desc"
  14. }
  15. {
  16. "speech_number": {
  17. "order": "desc"
  18. }
  19. }
  20. ]
  21. }

You can continue to sort by any number of field values to get the results in just the right order. It doesn’t have to be a numerical value—you can also sort by date or timestamp fields:

  1. "sort": [
  2. {
  3. "date": {
  4. "order": "desc"
  5. }
  6. }
  7. ]

A text field that is analyzed cannot be used to sort documents, because the inverted index only contains the individual tokenized terms and not the entire string. So you cannot sort by the play_name, for example.

To bypass this limitation, you can use a raw version of the text field mapped as a keyword type. In the following example, play_name.keyword is not analyzed and you have a copy of the full original version for sorting purposes:

  1. GET shakespeare/_search
  2. {
  3. "query": {
  4. "term": {
  5. "play_name": {
  6. "value": "Henry IV"
  7. }
  8. }
  9. },
  10. "sort": [
  11. {
  12. "play_name.keyword": {
  13. "order": "desc"
  14. }
  15. }
  16. ]
  17. }

The results are sorted by the play_name field in alphabetical order.

Use sort with the for more efficient scrolling. The results start with the document that comes after the sort values you specify in the search_after array.

Make sure you have the same number of values in the search_after array as in the sort array, also ordered in the same way. In this case, you are requesting results starting with the document that comes after line_id = 3202 and speech_number = 8:

  1. GET shakespeare/_search
  2. {
  3. "query": {
  4. "term": {
  5. "play_name": {
  6. "value": "Henry IV"
  7. }
  8. }
  9. },
  10. "sort": [
  11. {
  12. "line_id": {
  13. "order": "desc"
  14. }
  15. },
  16. {
  17. "speech_number": {
  18. "order": "desc"
  19. }
  20. }
  21. ],
  22. "search_after": [
  23. "3202",
  24. "8"
  25. ]
  26. }

Sort mode

The sort mode is applicable to sorting by array or multivalued fields. It specifies what array value should be chosen for sorting the document. For numeric fields that contain an array of numbers, you can sort by the avg, sum, or median modes. To sort by the minimum or maximum values, use the min or max modes that work for both numeric and string data types.

The default mode is min for ascending sort order and max for descending sort order.

Consider an index that holds student grades. Index two documents into the index:

  1. PUT students/_doc/1
  2. {
  3. "name": "John Doe",
  4. "grades": [70, 90]
  5. }
  6. PUT students/_doc/2
  7. {
  8. "name": "Mary Major",
  9. "grades": [80, 100]
  10. }

Sort all students by highest grade average using the avg mode:

  1. GET students/_search
  2. {
  3. "query" : {
  4. "match_all": {}
  5. },
  6. "sort" : [
  7. {"grades" : {"order" : "desc", "mode" : "avg"}}
  8. ]
  9. }

The response contains students sorted by grades in descending order:

When sorting nested objects, provide the path parameter specifying the path to the field on which to sort.

For example, in the index students, map the variable first_sem as nested:

  1. PUT students
  2. {
  3. "mappings" : {
  4. "properties": {
  5. "first_sem": {
  6. "type" : "nested"
  7. }
  8. }
  9. }
  10. }

Index two documents with nested fields:

  1. PUT students/_doc/1
  2. {
  3. "name": "John Doe",
  4. "first_sem" : {
  5. "grades": [70, 90]
  6. }
  7. }
  8. PUT students/_doc/2
  9. {
  10. "name": "Mary Major",
  11. "first_sem": {
  12. "grades": [80, 100]
  13. }
  14. }

When sorting by grade average, provide the path to the nested field:

  1. GET students/_search
  2. {
  3. "query" : {
  4. "match_all": {}
  5. },
  6. "sort" : [
  7. {"first_sem.grades": {
  8. "order" : "desc",
  9. "mode" : "avg",
  10. "nested": {
  11. "path": "first_sem"
  12. }
  13. }
  14. }
  15. ]
  16. }

Handling missing values

The missing parameter specifies the handling of missing values. The built-in valid values are _last (list the documents with the missing value last) and _first (list the documents with the missing value first). The default value is _last. You can also specify a custom value to be used for missing documents as the sort value.

For example, you can index a document with an average field and another document without an average field:

  1. PUT students/_doc/1
  2. {
  3. "name": "John Doe",
  4. "average": 80
  5. }
  6. PUT students/_doc/2
  7. {
  8. "name": "Mary Major"
  9. }

Sort the documents, ordering the document with a missing field first:

  1. GET students/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "sort": [
  7. {
  8. "average": {
  9. "order": "desc",
  10. "missing": "_first"
  11. }
  12. }
  13. ]
  14. }

The response lists document 2 first:

  1. {
  2. "took" : 1,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [
  17. {
  18. "_index" : "students",
  19. "_id" : "2",
  20. "_score" : null,
  21. "_source" : {
  22. "name" : "Mary Major"
  23. },
  24. "sort" : [
  25. 9223372036854775807
  26. ]
  27. },
  28. {
  29. "_id" : "1",
  30. "_score" : null,
  31. "_source" : {
  32. "name" : "John Doe",
  33. "average" : 80
  34. },
  35. "sort" : [
  36. 80
  37. ]
  38. }
  39. ]
  40. }

If a field is not mapped, a search request that sorts by this field fails by default. To avoid this, you can use the unmapped_type parameter, which signals to OpenSearch to ignore the field. For example, if you set unmapped_type to long, the field is treated as if it were mapped as type long. Additionally, all documents in the index that have an unmapped_type field are treated as if they had no value in this field, so they are not sorted by it.

For example, consider two indexes. Index a document that contains an average field in the first index:

  1. PUT students/_doc/1
  2. {
  3. "name": "John Doe",
  4. "average": 80
  5. }

Search for all documents in both indexes and sort them by the average field:

  1. GET students*/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "sort": [
  7. {
  8. "average": {
  9. "order": "desc"
  10. }
  11. }
  12. ]
  13. }

By default, the second index produces an error because the average field is not mapped:

  1. {
  2. "took" : 3,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 2,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 1,
  9. "failures" : [
  10. {
  11. "shard" : 0,
  12. "index" : "students_no_map",
  13. "node" : "cam9NWqVSV-jUIkQ3tRubw",
  14. "reason" : {
  15. "type" : "query_shard_exception",
  16. "reason" : "No mapping found for [average] in order to sort on",
  17. "index" : "students_no_map",
  18. "index_uuid" : "JgfRkypKSUSpyU-ZXr9kKA"
  19. }
  20. }
  21. ]
  22. },
  23. "hits" : {
  24. "total" : {
  25. "value" : 1,
  26. "relation" : "eq"
  27. },
  28. "max_score" : null,
  29. "hits" : [
  30. {
  31. "_index" : "students",
  32. "_id" : "1",
  33. "_score" : null,
  34. "_source" : {
  35. "name" : "John Doe",
  36. "average" : 80
  37. },
  38. "sort" : [
  39. 80
  40. ]
  41. }
  42. ]
  43. }
  44. }

You can specify the unmapped_type parameter so that the unmapped field is ignored:

  1. GET students*/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "sort": [
  7. {
  8. "average": {
  9. "order": "desc",
  10. "unmapped_type": "long"
  11. }
  12. }
  13. ]
  14. }

The response contains both documents:

  1. {
  2. "took" : 4,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 2,
  6. "successful" : 2,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [
  17. {
  18. "_index" : "students",
  19. "_id" : "1",
  20. "_score" : null,
  21. "_source" : {
  22. "name" : "John Doe",
  23. "average" : 80
  24. },
  25. "sort" : [
  26. 80
  27. ]
  28. },
  29. {
  30. "_index" : "students_no_map",
  31. "_id" : "2",
  32. "_score" : null,
  33. "_source" : {
  34. "name" : "Mary Major"
  35. },
  36. "sort" : [
  37. -9223372036854775808
  38. ]
  39. }
  40. ]
  41. }
  42. }

Tracking scores

By default, scores are not computed when sorting on a field. You can set track_scores to true to compute and track scores:

  1. GET students/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "sort": [
  7. {
  8. "average": {
  9. "order": "desc"
  10. }
  11. }
  12. ],
  13. "track_scores": true
  14. }

You can sort documents by _geo_distance. The following parameters are supported.

The _geo_distance parameter does not support missing_values. The distance is always considered to be infinity when a document does not contain the field used for computing distance.

For example, index two documents with geopoints:

  1. PUT testindex1/_doc/1
  2. {
  3. "point": [74.00, 40.71]
  4. }
  5. PUT testindex1/_doc/2
  6. {
  7. "point": [73.77, -69.63]
  8. }

Search for all documents and sort them by the distance from the provided point:

  1. GET testindex1/_search
  2. {
  3. "sort": [
  4. {
  5. "_geo_distance": {
  6. "point": [59, -54],
  7. "order": "asc",
  8. "unit": "km",
  9. "distance_type": "arc",
  10. "mode": "min",
  11. "ignore_unmapped": true
  12. }
  13. }
  14. ],
  15. "query": {
  16. "match_all": {}
  17. }
  18. }

The response contains the sorted documents:

You can provide coordinates in any format supported by the geopoint field type. For a description of all formats, see the .

To pass multiple geopoints to _geo_distance, use an array:

  1. GET testindex1/_search
  2. {
  3. "sort": [
  4. {
  5. "_geo_distance": {
  6. "point": [[59, -54], [60, -53]],
  7. "order": "asc",
  8. "unit": "km",
  9. "distance_type": "arc",
  10. "mode": "min",
  11. "ignore_unmapped": true
  12. }
  13. }
  14. ],
  15. "query": {
  16. "match_all": {}
  17. }
  18. }

For each document, the sorting distance is calculated as the minimum, maximum, or average (as specified by the mode) of the distances from all points provided in the search to all points in the document.

Performance considerations