Search code examples
elasticsearchnestedfieldelasticsearch-6

Sorting documents by a nested field


I'm trying to sort the result returned by ElasticSearch by the nested field sections.name as follows:

Mapping:

PUT /staff
{
    "mappings": {
        "list": {
            "properties": {
                "id": {"type": "text" },
                "name": {
                  "type":"text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                },
                "sections" : {
                  "type":"nested",
                  "properties": {
                    "id": {"type":"text", "fielddata" : true},
                    "name": {
                    "fielddata" : true,
                    "type": "text",
                    "fields": {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                      }
                    }
                  }
                }
              }
            }
        }
    }
}

documents:

POST /staff/list
{
    "id": 10,
    "name": "abc def",
    "sections":
    [
      {
        "id":"1",
        "name" : "zamphire"
      },{
        "id":"2",
        "name" : "warden"
      }
    ]
}

POST /staff/list
{
    "id": 9,
    "name": "abc def",
    "sections":
    [
      {
        "id":"1",
        "name" : "shaggi"
      },{
        "id":"2",
        "name" : "robert"
      }
    ]
}

POST /staff/list
{
    "id": 8,
    "name": "abc def",
    "sections":
    [
      {
        "id":"3",
        "name" : "zamphire"
      },{
        "id":"2",
        "name" : "abi"
      }
    ]
}

I'm performing the following query:

GET /staff/_search
{
  "from": 0,
  "query": {
    "nested": {
      "path": "sections",
      "query": {
        "match": {
          "sections.id": {
            "query": "1"
          }
        }
      }
    }
  },
  "size": 25,
  "sort": [
    {
      "sections.name": {
        "nested": {
          "filter": {
            "nested": {
              "path": "sections",
              "query": {
                 "term" : { "sections.id" : "1" }
              }
            }
          }
        },
        "order": "asc"
      }
    }
  ],
  "_source": {
    "includes": [
      "id",
      "name",
      "sections"
    ]
  }
}

I get these results:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "staff",
        "_type" : "list",
        "_id" : "rJtyyGwBNB-cdBRb5XGR",
        "_score" : null,
        "_source" : {
          "name" : "abc def",
          "id" : 10,
          "sections" : [
            {
              "name" : "zamphire",
              "id" : "1"
            },
            {
              "name" : "warden",
              "id" : "2"
            }
          ]
        },
        "sort" : [
          null
        ]
      },
      {
        "_index" : "staff",
        "_type" : "list",
        "_id" : "rZtyyGwBNB-cdBRb6nHU",
        "_score" : null,
        "_source" : {
          "name" : "abc def",
          "id" : 9,
          "sections" : [
            {
              "name" : "shaggi",
              "id" : "1"
            },
            {
              "name" : "robert",
              "id" : "2"
            }
          ]
        },
        "sort" : [
          null
        ]
      }
    ]
  }
}

I'm expecting the section shaggi to come before zamphire and thus the order of the two documents should be reversed.

I noticed this in the results:

"sort" : [
  null
]

Is that related? What am I missing here?


Solution

  • Changing sort part to this should do the job according to the docs

      "sort": [
        {
          "sections.name": {
            "order": "asc", 
            "nested": {
              "path": "sections",
              "filter": {
                "term" : { "sections.id" : "1" }
              }
            }
          }
        }
      ]
    

    Returns

    {
      "took" : 7,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 2,
          "relation" : "eq"
        },
        "max_score" : null,
        "hits" : [
          {
            "_index" : "staff",
            "_type" : "_doc",
            "_id" : "8hSJyWwBHfpsFyAs9f_8",
            "_score" : null,
            "_source" : {
              "name" : "abc def",
              "id" : 9,
              "sections" : [
                {
                  "name" : "shaggi",
                  "id" : "1"
                },
                {
                  "name" : "robert",
                  "id" : "2"
                }
              ]
            },
            "sort" : [
              "shaggi"
            ]
          },
          {
            "_index" : "staff",
            "_type" : "_doc",
            "_id" : "8RSJyWwBHfpsFyAs5v98",
            "_score" : null,
            "_source" : {
              "name" : "abc def",
              "id" : 10,
              "sections" : [
                {
                  "name" : "zamphire",
                  "id" : "1"
                },
                {
                  "name" : "warden",
                  "id" : "2"
                }
              ]
            },
            "sort" : [
              "zamphire"
            ]
          }
        ]
      }
    }
    

    Tested with elasticsearch 7.2.0.

    Hope that helps.