1

I'm trying to sort the results based on a numeric field,

Here is my mapping:

{
  "elasticie": {
    "mappings": {
      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "number": {
          "type": "long"
        }
      }
    }
  }
}

I'm using Python, and this is my testing data:

data = [
    {'name': 'sElwUYiLXGHaQCKbdxtnvVzqIehfFWkJcPSTurgNoRD', 'number': 8583},
    {'name': 'XJEtNsIFfcwHTMhqAvRkiygjbUGzZQPdS', 'number': 8127},
    {'name': 'ZIeAGosUKJbjOdylM', 'number': 5862},
    {'name': 'HYvcafoXkC', 'number': 7458},
    {'name': 'tATJCjNuizOlGckXBpyVqSQL', 'number': 530},
    {'name': 'TFYixotjhXzNZPvHnkraRDpAMEImJfqdcVGLC', 'number': 7052},
    {'name': 'JCEGfoKDHRrcIkPQSqiVgNshZOBaMdXjAlxwUzmeWLy', 'number': 6168},
    {'name': 'IpCTwUAQynSizJtcsuDmbX', 'number': 6492},
    {'name': 'fTrcoXSBJNFhAkzWpDMxsEiLmZRvgnC', 'number': 382},
    {'name': 'ulVNmqKTpPXfEIdiykhDjMrUGOYazLBFvgnWwsRtJoQbxSe', 'number': 2061}
]

Using following code, I'm creating the index and inserting the data:

from elasticsearch import Elasticsearch
from data import data  # the data I've shown above

INDEX = 'elasticie'
es = Elasticsearch('http://127.0.0.1:9200')

for _ in data:
    es.index(index=INDEX, body=_)

I'm trying to sort data based on number, asc or desc Here is what I tried so far:

es.search(index=INDEX, params={'sort': {'number': {'order': 'asc'}})
es.search(index=INDEX, params={'sort': {'number': 'asc'})
es.search(index=INDEX, params={'sort': [('number', 'asc')]})
es.search(index=INDEX, params={'sort': {'number': {'order': 'asc', 'ignore_unmapped': True}})
es.search(index=INDEX, params={'sort': {'number': {'order': 'asc', 'unmapped_type': 'integer'}})
es.search(index=INDEX, params={'sort': {'number': {'order': 'asc', 'unmapped_type': 'long'}})
es.search(index=INDEX, params={'sort': {'number.raw': 'asc'})

Not of the above methods worked for me, The result is the same as the inserted data, If I assign the above lines to a variable named search_result and print the result using the following code:

for index, result in enumerate(search_result['hits']['hits']):
    print(f'{index}. {result["_source"]["number"]}')

I'll get the following result:

0. 8583
1. 8127
2. 5862
3. 7458
4. 530
5. 7052
6. 6168
7. 6492
8. 382
9. 2061

Which is obviously not sorted using number field!!

I don't know what I'm doing wrong, I'm using ElasticSearch 7.6 and Python 3.8

How can I make the sorting results work?

Update

Based on debugging logs, Python is sending a GET request to the following URL using the first method: http://127.0.0.1:9200/elasticie/_search?sort={%27number%27%3A+{%27order%27%3A+%27asc%27}}

Amit
  • 30,756
  • 6
  • 57
  • 88
DarkSuniuM
  • 2,523
  • 2
  • 26
  • 43
  • Could you provide your search JSON, I tried with your dataset and it worked very well with my search query, I don't have `pyhton` setup but can share my postman collection, if you want to try out these API yourself – Amit Mar 09 '20 at 10:21
  • You should try with this request : `es.search(index=INDEX, params={'sort': [{'number': {'order': 'asc'}}]})` – fmdaboville Mar 09 '20 at 10:23
  • @OpsterElasticsearchNinja Added the request information to the question – DarkSuniuM Mar 09 '20 at 10:26
  • 1
    @fmdaboville Already tried that, getting the same result as before – DarkSuniuM Mar 09 '20 at 10:27
  • 1
    @DarkSuniuM, why you are sending `sort` param as a query param and making `GET` request, can you change it to `POST` and send `sort` param as part of your body – Amit Mar 09 '20 at 10:29
  • @DarkSuniuM, also I just decoded your url param and its translating to `{'number':+{'order':+'asc'}}` which is giving me `illegal_argument_exception` when I hit it using postman, as `sort` option is missing – Amit Mar 09 '20 at 10:30
  • @DarkSuniuM, strane, Even with `GET`, you can pass the `search body` and it gives me proper results – Amit Mar 09 '20 at 10:32
  • @fmdaboville, wanted to point out the same, but then realised he already tried that – Amit Mar 09 '20 at 10:33
  • @OpsterElasticsearchNinja You're comment led me to the answer, It works well on the POST request, I was doing the search using what the python library's doc string was telling me to do, I read the docs again, seems like it takes a `sort` argument which makes the library send the request using `POST` method – DarkSuniuM Mar 09 '20 at 10:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/209298/discussion-between-opster-elasticsearch-ninja-and-darksunium). – Amit Mar 09 '20 at 10:36
  • @OpsterElasticsearchNinja I just add the '[' which seems to be missing on each tries. @DarkSuniuM The elastic doc make it work with a `GET` with a search https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-sort.html#search-request-sort – fmdaboville Mar 09 '20 at 10:37
  • @fmdabovillem I know it works well, with the `GET` and thats what I mentioned in previous comment but it's not recommended to send the search payload as part of your query string(has a lot of known issues), best to use the post method, which also solved the OP problem :-) – Amit Mar 09 '20 at 10:39

2 Answers2

2

I am not familiar with python, but here is the Elasticsearch JSON query which would sort your documents according to the numbers in desc order. I've tried with your data set and it gives proper results.

Sort Search query

{
    "sort": [
        {
            "number": {
                "order": "desc"
            }
        }
    ]
}

Results

"hits": [
         {
            "_index": "so-60598395-sort",
            "_type": "_doc",
            "_id": "1",
            "_score": null,
            "_source": {
               "name": "sElwUYiLXGHaQCKbdxtnvVzqIehfFWkJcPSTurgNoRD",
               "number": 8583
            },
            "sort": [
               8583
            ]
         },
         {
            "_index": "so-60598395-sort",
            "_type": "_doc",
            "_id": "2",
            "_score": null,
            "_source": {
               "name": "XJEtNsIFfcwHTMhqAvRkiygjbUGzZQPdS",
               "number": 8127
            },
            "sort": [
               8127
            ]
         },
         {
            "_index": "so-60598395-sort",
            "_type": "_doc",
            "_id": "4",
            "_score": null,
            "_source": {
               "name": "HYvcafoXkC",
               "number": 7862
            },
            "sort": [
               7862
            ]
         },
         {
            "_index": "so-60598395-sort",
            "_type": "_doc",
            "_id": "3",
            "_score": null,
            "_source": {
               "name": "ZIeAGosUKJbjOdylM",
               "number": 5862
            },
            "sort": [
               5862
            ]
         }

EDIT:- Based on the OP comments, python library which he is using supports the POST method of search endpoint, using which he solved the issue. Refer to the comments on the question for more details.

Amit
  • 30,756
  • 6
  • 57
  • 88
1

My mistake, I read the documentation and the code functionality using help and dir functions

There is no parameter named sort defined on the Elasticsearch.search method, That's why I thought I should use it as a key within the params dict that it takes,

Thanks to @OpsterElasticSearchNinja and his comment, I realized there is something wrong with either the library or how I'm using it

Sending POST request with sort key as post body worked well, So I decided to read the whole source code and find out what's going wrong?

@query_params(
    #...
    "size",
    "sort",
    #...
)
def search(self, body=None, index=None, doc_type=None, params=None):
    # ...

This is how the sort parameter is defined, using a decorator on runtime!!

That's when I tried this code, and somehow it worked!

es.search(index=INDEX, sort=['number:asc'])
DarkSuniuM
  • 2,523
  • 2
  • 26
  • 43